ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

跨域迁移学习+YOLOv11的卫星建筑物提取与变化检测实战

跨域迁移学习+YOLOv11的卫星建筑物提取与变化检测实战 简介跨域迁移学习与YOLOv11的结合在卫星遥感建筑物提取与变化检测中颇具实践价值。这份PDF文档共38页完整包含目录结构与章节跳转系统梳理了迁移学习基础、YOLO系列演进、YOLOv11网络结构、遥感图像预处理、建筑物提取与变化检测实现、实验对比及未来挑战等内容便于按章节快速定位学习。文档具体涉及基于特征的迁移学习、锚框与损失函数设计、非极大值抑制、图像配准与辐射校正等关键环节并重点分析了跨域迁移学习在解决遥感图像背景复杂、数据分布差异等问题上的作用说明单阶段检测机制在精度与速度上的优势。资源为单个PDF文件大小1.95MB已有78人浏览/学习。读者可借此掌握迁移学习理论框架、YOLOv11实现要点与遥感实验设计方法适合目标检测、遥感图像分析及迁移学习方向的初学者和研究者系统参考。1. 跨域迁移学习 YOLOv11 的卫星建筑物提取与变化检测先认清这个坑在哪在航空影像上 mAP50 能到 0.85 的 YOLOv11 模型直接丢到 GaoFen-2 卫星瓦片上跑mAP50 掉到 0.4 出头是遥感圈最常见的翻车现场。这不是模型坏了而是跨域迁移学习里典型的域偏移源域和目标域的数据分布差得太远。标题这条路线要解决的正是这个问题——用跨域迁移学习把 YOLOv11 从开源遥感数据集适配到你手里的卫星影像先做建筑物提取再做两期影像之间的变化检测。适合 GIS 工程师、违建监测和灾害评估从业者以及想在遥感项目里用上 YOLOv11 又怕被数据分布坑到的算法同学。下面按任务定义、数据管线、迁移训练、变化检测、避坑、验证部署的顺序讲。2. 把遥感任务翻译成 YOLOv11 的检测任务任务定义与跨域数据管线2.1 建筑物提取为什么用 YOLOv11 而不是分割模型任务重定义与网络结构传统建筑物提取是语义分割逐像素分类。但放到变化检测场景里业务方真正关心的是哪里有建筑、面积多大、这一期和上一期比是多了还是少了。这个诉求用目标检测就够而且 YOLOv11 一次推理同时给出类别、水平框和置信度OBB 定向框版本还能输出带朝向的框对密集城区里朝向不同的屋顶非常有用。yolov11 目标检测在这个场景里的隐性优势是变化检测要做两期对比检测模型天然给出实例级结果可以直接进入后面的 IoU 匹配环节。YOLOv11 的网络结构和前代最大的区别在骨干里用了 C3k2 模块深层加了 C2PSA 注意力整体是 anchor-free 的解耦检测头分类和回归分开出结果。这套结构对密集小目标不算最激进但胜在训练稳定、部署成熟遥感社区里能找的预训练权重也多。所以我一般把任务定义为单类水平框检测先框住 building精细的屋顶轮廓留给分割模型做下游精修不在一开始把任务做重。2.2 源域和目标域差在哪遥感跨域迁移的四个差异维度跨域迁移学习里源域和目标域必须先定义清楚。常见做法是源域用开源遥感数据集比如 INRIA、WHU、xView目标域是你业务上真正要处理的卫星影像比如 GaoFen-2、Sentinel-2 或商业高分辨率影像。两边差异集中在四个维度差异维度源域航空/开源遥感目标域卫星影像地面分辨率 GSD0.05–0.3 米0.5–2 米波段构成RGB 为主常含近红外真彩色需融合拍摄角度近似垂直下视存在侧摆和视差阴影与纹理阴影短屋顶纹理清晰楼高阴影长屋顶纹理被抹平这四条直接决定了为什么源域权重不能直接套到目标域。GSD 变了同一栋房子在影像里的像素数从 100×100 缩到 10×10低层特征完全不是一个量级波段变了目标域三通道的数值分布和源域对不上。域偏移不是玄学是这些可量化差异的叠加迁移学习要做的就是把这层差异尽量抹平。2.3 把 GeoTIFF 和 Shapefile 转成 YOLO 格式转换脚本与最小过滤规则数据管线第一步是把标注从 GIS 格式转成 YOLO 能吃的格式。卫星影像通常是 GeoTIFF建筑标注是 Shapefile 或 GeoJSON 里的面要素转换脚本我一般这么写import rasterio import geopandas as gpd def geojson_to_yolo(shp_path, tif_path, out_dir, class_id0): gdf gpd.read_file(shp_path) with rasterio.open(tif_path) as src: gdf gdf.to_crs(src.crs) # 统一坐标系防止偏移 W, H src.width, src.height trs src.transform for idx, row in gdf.iterrows(): geom row.geometry if geom is None or geom.is_empty: continue minx, miny, maxx, maxy geom.bounds # 地理坐标 - 像素行列号注意影像行号向下增长 col_left, row_top ~trs * (minx, maxy) col_right, row_bottom ~trs * (maxx, miny) w col_right - col_left h row_bottom - row_top if w 2 or h 2: continue # 小于 2 像素的框直接丢掉 x_center (col_left col_right) / 2.0 / W y_center (row_top row_bottom) / 2.0 / H image_id row.get(image_id, fimg_{idx}) with open(f{out_dir}/{image_id}.txt, a) as f: f.write(f{class_id} {x_center:.6f} {y_center:.6f} {w / W:.6f} {h / H:.6f}\n)逻辑说明~trs是对仿射变换求逆把地理坐标换算成影像的列和行。地理坐标的 Y 向上增长图像行号向下增长所以要把maxy映射成row_topminy映射成row_bottom写反了标注会整体上下翻转。x_center、y_center、w、h全部除以影像宽高做归一化这是 YOLO 格式的死规定。参数说明class_id0表示单类 buildingimage_id建议和切片文件名保持一致Ultralytics 在训练时按图片名自动找同名 txt名字对不上就白标了。过滤掉小于 2 像素的框是为了不把标注误差和零碎面要素喂给模型。卫星影像往往很大常见做法是把大瓦片切成 1024×1024 的重叠切片overlap 取 100 像素左右避免建筑正好卡在切片边界。切片之后再跑上面的转换每个切片独立出一份 txt。最后写一个数据集描述文件path: /data/sat_building train: images/train val: images/val nc: 1 names: [building]参数说明nc是类别数建筑物提取写 1names里的字符串会出现在后续可视化标签上不要留空。train 和 val 指向图片目录YOLO 会自动寻找同名标签文件。这一步做完数据管线才算真正闭环。提示切片尺寸和 overlap 会直接影响训练效果建议切完先挑几个样片可视化确认建筑没有被切成两半再做后面的训练。3. 跨域迁移训练的三板斧让 YOLOv11 从源域走向卫星目标域3.1 迁移起点为什么源域预训练权重比 COCO 权重更值钱YOLOv11 官方权重是在 COCO 上预训练的COCO 的优势在自然图像的通用特征。遥感影像的视觉模式和自然图像差很远屋顶是俯视图、阴影方向一致、地物边缘和材质分布完全不同。从 COCO 权重起步不是不行但要在目标域上多烧很多 epoch 才能补回来。跨域迁移学习的常见做法是先找遥感场景的预训练权重要么直接用社区开源的在 INRIA、WHU、xView 上训过的 YOLOv11 权重要么自己先用源域数据快速训一个 base 模型。这个 base 模型的网络结构就是标准 YOLOv11只是权重已经见过建筑俯视特征后面迁移到卫星影像时低层的边缘纹理特征能直接复用。这一步决定了你是在微调还是在从零学效果差距很大。环境配置不展开pip install ultralytics就能跑通下面的脚本别碰源码编译的魔改版版本漂移最容易出幺蛾子。3.2 两阶段微调先冻结骨干再解冻全模型的训练参数与命令迁移训练我一般按两个阶段做。第一阶段冻结骨干只更新检测头让模型先适应目标域的数据分布和标注风格代价小不容易出现灾难性遗忘。第二阶段解冻全部用小学习率精修。训练脚本如下from ultralytics import YOLO # 阶段一冻结骨干只训 head model YOLO(yolov11s_source.pt) # 源域预训练权重不是 COCO 官方的 model.train( datasat_building.yaml, epochs30, imgsz1024, batch8, freeze10, # 冻结前 10 个模块backbone 不动 lr00.01, # 只动 head学习率可以给大 lrf0.01, workers4, projectruns/sat, namestage1_freeze, exist_okTrue, ) # 阶段二解冻全部小学习率精修 model YOLO(runs/sat/stage1_freeze/weights/best.pt) model.train( datasat_building.yaml, epochs60, imgsz1024, batch8, freeze0, # 全部可训练 lr00.001, # 比阶段一降一个数量级 lrf0.01, workers4, projectruns/sat, namestage2_unfreeze, exist_okTrue, )逻辑说明freeze10是 Ultralytics 的模块序号冻结参数遥感模型里通常能覆盖整个 backbone。如果目标域数据集很小比如只有几百张切片冻结阶段可以拉到 50 epoch数据集够大时 15 epoch 就够。第二阶段必须把学习率降一个数量级否则解冻的 backbone 会把源域学到的边缘纹理特征冲掉mAP 反而倒退。这个先冻后解的顺序是跨域迁移里最值得先试的方案比一上来就全量微调稳得多。参数说明imgsz1024是针对卫星影像小目标的基本设置别用默认的 640batch受显存限制显存不够就降到 4 或 2lrf0.01控制学习率衰减到初始值的 1%一般不用动。3.3 域对齐技巧直方图匹配、NDVI 通道注入与少样本微调微调能解决一部分域偏移但数据本身差太远时训练很难收敛。域对齐是在数据层面先把两个域拉近我用的三板斧里前两招在这里。第一招直方图匹配。把目标域瓦片的 RGB 直方图匹配到源域均值或者反过来让模型看到的光谱分布不再跳变。第二招是 NDVI 通道注入。卫星影像多数带近红外波段植被在 NDVI 上非常亮而植被是建筑物提取里最大的误检来源。不用改模型结构把红色波段和 NDVI 伪彩色合成一个三通道图喂给模型import rasterio import numpy as np def composite_ndvi(rgb_path, ms_path, out_path): # 波段顺序按传感器定这里假设多光谱为 B,G,R,NIR with rasterio.open(ms_path) as src: red src.read(3).astype(float32) # 第 3 波段是红 nir src.read(4).astype(float32) # 第 4 波段是近红外 ndvi (nir - red) / (nir red 1e-6) ndvi_img ((ndvi 1) / 2 * 255).astype(uint8) with rasterio.open(rgb_path) as src: profile src.profile r src.read(1) g src.read(2) with rasterio.open(out_path, w, **profile) as dst: dst.write(r, 1) dst.write(g, 2) dst.write(ndvi_img, 3) # 蓝色通道替换成 NDVI逻辑说明(nir - red) / (nir red 1e-6)是 NDVI 的标准公式1e-6防止除零(ndvi 1) / 2 * 255把范围从 [-1, 1] 拉到 [0, 255] 存成 uint8。蓝色通道被替换成 NDVI 后植被区域在图上明显发亮模型能更干净地学出房子不像树这条判别边界而且完全不用动 YOLOv11 的网络结构。第三招是少样本微调也叫 few-shot transfer。从目标域人工标注 200 到 500 个建筑框加进训练集通常能把 mAP50 拉回 10 个点以上。纯无监督的域自适应在遥感上效果不稳定别指望完全不打标签就能跨域。4. 变化检测落地从两期检测框到一份可发布的变化报告4.1 两期检测结果做 IoU 匹配变化检测的最稳基线变化检测在遥感里分像素级和对象级两条路线。像素级拿双时相影像直接做差或训一个双时相变化检测网络输出变化掩膜代表就是 HCANet 这类网络效果好但需要成对标注的训练数据。对象级路线更适合 YOLOv11先把 T1 和 T2 两期影像分别做建筑物检测再把两组框做 IoU 匹配。下面是匹配脚本import numpy as np def calc_iou(box1, box2): xx1 max(box1[0], box2[0]); yy1 max(box1[1], box2[1]) xx2 min(box1[2], box2[2]); yy2 min(box1[3], box2[3]) inter max(0.0, xx2 - xx1) * max(0.0, yy2 - yy1) area1 (box1[2] - box1[0]) * (box1[3] - box1[1]) area2 (box2[2] - box2[0]) * (box2[3] - box2[1]) return inter / (area1 area2 - inter 1e-6) def compare_phases(t1_boxes, t2_boxes, iou_thr0.5): # t1_boxes / t2_boxes 传 numpy 数组形状 (N, 4)像素坐标 matched [False] * len(t2_boxes) new_mask np.ones(len(t2_boxes), dtypebool) for a in t1_boxes: best_j, best_iou -1, iou_thr for j, b in enumerate(t2_boxes): if matched[j]: continue iou calc_iou(a, b) if iou best_iou: best_iou, best_j iou, j if best_j 0: matched[best_j] True new_mask[best_j] False return t2_boxes[new_mask] # 新增建筑框逻辑说明匹配采用贪心策略先到先得。iou_thr0.5是默认值卫星影像上同一栋房子两次检测的框 IoU 一般在 0.6 到 0.8取 0.5 能容忍定位误差。T2 里有框但 T1 匹配不上就是新增建筑反过来 T1 有框 T2 没有就是拆除建筑。注意这里要求两期影像已经做过几何配准像素坐标直接可比。预测时的 conf 阈值要固定比如两期都用 0.35不然信噪比不同变化结果会失真。注意两期影像必须先配准再进 IoU 匹配配准残差大于 0.5 像素时上面的逻辑会大面积误报。4.2 从检测框到变化矢量后处理、面积过滤与融合导出检测框是像素坐标业务上要的是矢量。用 shapely 把框转成面要素再做面积过滤和融合from shapely.geometry import box import geopandas as gpd def boxes_to_geojson(new_boxes, out_path, min_area9.0): geoms [box(b[0], b[1], b[2], b[3]) for b in new_boxes] gdf gpd.GeoDataFrame(geometrygeoms, crsEPSG:3857) # 过滤掉小于最小建筑面的噪声框9 平方米约等于一个小棚屋 gdf gdf[gdf.geometry.area min_area] # 融合相邻框避免一个建筑被切成两段 merged gdf.geometry.unary_union merged_gdf gpd.GeoDataFrame(geometry[merged], crsEPSG:3857) merged_gdf.to_file(out_path, driverGeoJSON)逻辑说明min_area按业务来定0.8 米分辨率影像上 9 平方米对应约 14×14 像素能把误检的阴影碎片滤掉。unary_union把相互重叠或共边的框融合成多边形输出给 ArcGIS 或 QGIS 直接用。参数不是死的如果任务是排查大面积违建min_area 可以提到 20 到 50 平方米如果要找翻建门槛降到 5 平方米同时多容忍一些误检。4.3 开放词汇变化检测新方向与 YOLOv11 路线的取舍边界最近热起来的开放词汇变化检测是另一个思路用文本提示词描述新建房屋、道路拓宽这类变化模型从双时相影像里检索对应变化。好处是不用固定类别表探索性强但落地时问题也很明显——结果对提示词措辞敏感变化边界的确定性差出了问题不好归因像黑匣子。YOLOv11 两阶段方案每一步都可解释检测框是看得见的IoU 匹配逻辑是确定的哪个建筑被判新增、为什么判新增都能回溯到模型输出和阈值。做生产级变化报告我倾向把 YOLOv11 当主线保证建筑完整召回开放词汇模型只做辅助排查如果数据充足再考虑 HCANet 这类语义变化检测网络做像素级校验但成对训练数据不是每个项目都攒得出来。5. 避坑记录卫星建筑物检测里最常见的五个翻车现场跨域迁移这条链路里坑比算法本身多。下面五条是遥感项目里反复踩过的每条按现象、原因、解决三个步骤写照着对号入座能省不少时间。5.1 小目标漏检换到 0.8 米分辨率后房子消失现象源域航空影像上检得很好切到 0.8 米分辨率的卫星瓦片后10×10 像素的小房子大量漏检mAP50-95 比 mAP50 难看很多。 原因默认训练用 640×640 输入YOLOv11 经过 5 次下采样最小特征图 stride 是 3210 像素的小目标在深层基本没有特征了。卫星影像视野大、目标小和自然图像的尺度分布完全是两回事。 解决三招并用。第一输入尺寸提到 1024 或 1280目标像素数直接翻倍。第二滑窗切片推理大瓦片切成 1024 切块带 100 像素重叠避免目标正好被切碎。第三针对 yolov11 小目标优化加 P2 检测头或借用 SAHI 这类切片推理库P2 头让模型在 stride 4 的特征图上出框对小目标最直接。5.2 跨域后 mAP 断崖式下跌换域如换刀现象源域验证集 mAP50 能到 0.85目标域一测只有 0.4 出头而且不是过拟合是换个数据分布就崩。 原因GSD 和光谱分布差异太大模型在源域学到的边缘纹理和色彩统计在目标域不成立。这不是训练不够是域偏移在硬切没有后悔药只能从头做对齐。 解决先做数据层对齐直方图匹配把两域光谱拉近再做训练层迁移按第 3 章的两阶段微调走最后从目标域抽 200 到 500 个框做少样本微调。按这个顺序目标域 mAP50 通常能拉回 0.7 以上。不要跳过直方图匹配直接全量微调那会把模型在源域的能力也一起毁掉。5.3 阴影和树冠混进来建筑物和植被傻傻分不清现象检测结果里出现大量细长阴影框和圆形树冠框夏季影像更严重绿色屋顶的漏检率也明显偏高。 原因RGB 三通道里阴影是低亮度区域树冠是绿色纹理某些屋顶材质的光谱特征和它们重叠。纯靠颜色判别模型会把亮度和纹理当成决定性特征。 解决加 NDVI 通道见第 3.3 节植被在 NDVI 上很亮阴影仍然暗光谱可分性立刻拉开。再把阴影样本和树冠样本专门切成负样本加入训练让模型见过这些看起来像房子但不是的东西。上了生产之后我还会对检测框做形状过滤细长比大于 4 的框先打上阴影嫌疑标签。5.4 伪变化两期影像的季节和角度在捣乱现象T1 是春季、T2 是秋季同一片区域跑完变化检测输出几百个新增建筑人工一看全是树影和农田的差异。 原因两期影像的太阳高度角、卫星侧摆角、植被状态都不同像素级差异和辐射差异全部被算成变化。变化检测的前提是除了目标变化其他都是静态的这个前提在真实卫星数据里经常不成立。 解决先做几何配准配准残差 RMSE 控制在 0.5 像素以内否则框级 IoU 匹配会大面积失真。再做辐射归一化至少做直方图匹配。最后把 IoU 匹配的置信度门槛提到 0.4加最小变化面积过滤把季节引起的碎变化压下去。这一步没做好变化报告发出去就是事故血泪经验。5.5 推理结果保存混乱save 参数和置信度没调对现象用 predict 跑完只看到可视化图找不到标签文件或者 labels 目录里 txt 一堆但没存置信度或者连续跑几次输出被丢进 predict2、predict3 目录里找不到。 原因Ultralytics 的 predict 默认save_txtFalse、save_confFalse可视化图和标签分开落盘不指定project和name时自动递增目录名脚本跑多了输出就散。 解决推理命令把参数写全固定输出目录yolo predict modelruns/sat/stage2_unfreeze/weights/best.pt sourcebig_tile_1024 imgsz1024 conf0.4 iou0.45 saveTrue save_txtTrue save_confTrue projectruns/infer nametile_0712 exist_okTrue line_width2参数说明conf 定在 0.35 到 0.45 之间太低会灌进大量误检框太高会把小建筑滤掉。可视化图和 txt 标签都在runs/infer/tile_0712/下txt 在labels/子目录每个框一行类 ID、中心点、宽高、置信度。推理前先用两三块验证切片试跑确认目录、阈值都对再铺开全图。yolov11 保存推理结果这件事看着简单真正按批次跑的时候目录和阈值不统一会浪费大量整理时间。6. 验证与部署用指标把关用 TensorRT 落地到 Jetson6.1 验证指标mAP50 和 mAP50-95 在建筑物任务里怎么读建筑物检测业务上主要看 mAP50它只算 IoU 大于 0.5 的框能反映有没有找到房子。mAP50-95 对框的定位精度更苛刻卫星影像标注边缘本身有歧义mAP50-95 低零点几个点很正常别为它过度调参。验证脚本from ultralytics import YOLO model YOLO(runs/sat/stage2_unfreeze/weights/best.pt) m model.val(datasat_building.yaml, imgsz1024, conf0.35, iou0.45) print(fmAP50{m.box.map50:.3f} mAP50-95{m.box.map50_95:.3f})除了 mAP还要看混淆矩阵里 building 类的召回率。变化检测对漏检更敏感漏掉一栋新建建筑比多报一栋严重得多。6.2 Jetson Nano 部署FP16 导出与输入尺寸的取舍模型验证通过后上 Jetson Nano先把权重导出成 TensorRT engineyolo export modelruns/sat/stage2_unfreeze/weights/best.pt formatengine halfTrue imgsz1024FP16 能砍掉一半显存占用但 4GB 的 Nano 跑 1024 输入仍然吃力我一般降到 640或者把推理 batch 固定成 1。导出之后连续跑 30 分钟测温度和掉帧率TensorRT 版比 PyTorch 快 2 到 3 倍。推理结果保存记得用save_txtTrue把坐标落盘方便工控机做联动和归档。我现在的习惯是任何遥感检测项目先花半天在目标域标 20 张切片跑一次冻结微调再决定要不要铺开做这比后续返工省太多时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表