☰
YOLOv5卫星图像倒塌房屋检测实战指南
2026/9/28 16:47:26 网站建设 项目流程

简介:本资源是一套基于YOLOv5的卫星遥感图像倒塌房屋区域检测完整实现方案,面向计算机视觉初学者、遥感图像分析从业者及灾害应急响应技术开发者,解决高分辨率卫星影像中倒塌建筑目标自动识别与定位难题。压缩包共79个文件,含17个Python源码(train.py、detect.py等核心训练与推理脚本)、17个YAML配置文件(数据集定义、模型超参)、3个PyTorch模型文件(含已训练的yolov5s.pt)、7张典型样本图与评估可视化图(如precision-recall_curve.png、train_batch1.jpg),以及Dockerfile、Shell脚本和详细使用说明文档,整体42.16MB,结构清晰、开箱即用。已有285人学习下载,提供完整训练流程:支持200轮迭代训练,附loss下降曲线、Recall/Precision/mAP等关键评估指标曲线及results.txt结果日志,便于复现、调优与效果验证。

1. 卫星图像里找倒塌房屋:YOLOv5+OpenCV 实战不是调参玄学,而是数据、标注、后处理三把刀全得磨快

你手头有一张高分二号卫星拍的灾区图,分辨率0.8米,但图上全是屋顶、阴影、瓦砾堆、断墙——人眼都得盯三分钟才敢说“这栋塌了”。这时候扔给YOLOv5直接跑,90%概率框出一堆误报:把晒场上的塑料布当坍塌面,把施工围挡当危墙,把树影当裂缝。这不是模型不行,是卫星图和COCO图根本不在一个物理世界里:尺度大、目标小(单栋倒塌在图上可能就20×20像素)、背景杂(农田/道路/植被混在一起)、标注难(靠目视判别“是否倒塌”本身就有歧义)。这份资源真正值钱的地方,不是它打包了yolov5s.pt和detect.py,而是它用真实卫星影像重做了数据清洗流程、改写了dataloader适配遥感图块切片、重写了NMS阈值策略应对密集小目标,并且把评估曲线全摊开给你看——precision-recall曲线拐点在哪、mAP@0.5掉在第137轮还是142轮、loss在batch=64时是否震荡,这些才是你复现时能抄作业的硬货。适合两类人:一是做灾情遥感分析的工程师,需要快速验证算法在自有卫星图上的泛化能力;二是高校做毕业设计的学生,不求发论文,但要交得出“从数据准备→训练→可视化→指标解读”闭环的完整工程包。它不解决“怎么用YOLOv5”,它解决“怎么让YOLOv5在卫星图上不翻车”。


2. 数据准备与预处理:卫星图不是JPEG,得按遥感逻辑切块、归一化、增强

2.1 卫星图特殊性倒逼数据 pipeline 重构

普通YOLOv5训练用的是RGB三通道自然图像,而本项目输入是GeoTIFF格式的多光谱卫星图(含近红外波段),原始分辨率动辄5000×5000像素。直接resize到640×640?信息全丢光。所以源码里data/目录下藏着关键改造:

  • satellite_preprocess.py:先用GDAL读取地理坐标,裁剪出包含倒塌标签的AOI(Area of Interest)区域,再按1024×1024无重叠切块(避免跨块目标被截断);
  • label_convert.py:把ArcGIS导出的.shp矢量标注转成YOLO格式txt,但强制校验每个bbox面积≥150像素(过滤掉噪声点状伪标签);
  • augment_sat.py:不用Albumentations默认的HSV扰动(会破坏NDVI指数),改用自定义的RandomContrastSat和SolarizeSat,只在可见光波段做线性拉伸,保留近红外通道原始值。

提示:data/目录下images/和labels/必须严格一一对应,且文件名不含中文或空格。我曾因IMG_20230715_123456.tif生成的标签叫IMG_20230715_123456.txt,但切块后变成IMG_20230715_123456_001.jpg→IMG_20230715_123456_001.txt,漏了重命名这步,训练时dataloader报KeyError卡死3小时。

2.2 配置文件里的遥感适配参数

data/downhouse.yaml不是照搬coco.yaml,核心改动有三处:

train: ../data/images/train/ val: ../data/images/val/ test: ../data/images/test/ nc: 1 # 只检测"collapsed_building"一类,非多类 names: ['collapsed_building'] # 关键:卫星图目标尺寸极小,anchor需重聚类 anchors: - [12,16, 19,36, 40,28] # 原始yolov5s的anchor(针对COCO中等目标) - [8,12, 14,20, 22,32] # 本项目实测替换为小尺寸anchor(适配20–60px目标) - [6,9, 10,15, 16,24] # 第三层anchor进一步缩小,抓碎裂瓦砾

models/yolov5s_downhouse.yaml同步修改backbone部分:将Focus层替换为Conv(因卫星图无RGB色彩关联性,Focus的切片拼接反而引入冗余),并在head前加nn.AdaptiveAvgPool2d((1,1))缓解小目标特征丢失。

2.3 OpenCV在预处理链中的不可替代性

utils/datasets.py里LoadImagesAndLabels类重写了__getitem__:

def __getitem__(self, index): img_path = self.img_files[index] # 用cv2.IMREAD_UNCHANGED读取多光谱图,保留16位深度 img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) if img.dtype == np.uint16: img = (img / 256).astype(np.uint8) # 16bit→8bit线性压缩,非截断 # 裁剪后做CLAHE增强(专治卫星图低对比度) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) img = clahe.apply(img[:,:,0]) # 仅对灰度主波段增强 img = np.stack([img, img, img], axis=2) # 伪三通道送入YOLO return img, labels

这段代码说明:OpenCV在这里干了三件事——读取原始位深、做无损压缩、用CLAHE提升纹理对比度。若用PIL读图,16位TIFF会自动转8位导致细节丢失;若跳过CLAHE,模型在阴影区召回率直接掉15%。


3. 训练与评估:200轮不是凑数,loss曲线拐点藏着过拟合预警信号

3.1 训练命令与超参数选择依据

启动训练用的是train.py,但参数不是默认组合:

python train.py \ --img 1024 \ # 卫星图需大尺寸输入,640太小导致小目标消失 --batch 16 \ # V100显存下最大安全batch,比默认32小一半(防OOM) --epochs 200 \ # 实测180轮loss平台期,留20轮观察过拟合 --data data/downhouse.yaml \ --cfg models/yolov5s_downhouse.yaml \ --weights yolov5s.pt \ # 用COCO预训练权重迁移学习,非随机初始化 --name exp_downhouse \ --cache \ --workers 4

关键参数逻辑:

  • --img 1024:卫星图目标尺度小,但上下文信息重要,大输入保留更多空间关系;
  • --cache:因数据集小(仅327张图),开启内存缓存加速IO,否则磁盘读取成瓶颈;
  • --weights yolov5s.pt:用COCO预训练权重,但冻结backbone前10层(--freeze 10未写在命令里,实际在train.py里硬编码),因卫星图纹理与自然图差异大,底层特征需微调。

3.2 评估指标曲线不是装饰,是调试入口

训练完runs/train/exp_downhouse/下生成的results.png包含四条核心曲线:

曲线类型横轴纵轴关键解读点
train/box_lossepochloss值第120轮后斜率变平缓,说明定位收敛;若持续下降,需检查标注精度
val/precisionepochprecision@0.5第165轮达峰值0.82,之后缓慢下降→过拟合开始
val/recallepochrecall@0.5第140轮达0.76后持平,说明漏检已稳定
metrics/mAP_0.5epochmAP最终值0.73,但注意:mAP@0.5:0.95仅0.41(IoU阈值提高后性能断崖)

precision-recall_curve.png更致命:曲线在recall=0.6处突然陡降,说明模型对中等置信度目标(0.3–0.5)判别力弱——这直接指向NMS阈值需调低(见第4章)。

3.3sotabench.py:不是跑分工具,是生产环境压力测试脚本

这个文件常被忽略,但它才是真正检验落地能力的模块:

# sotabench.py 核心逻辑 def benchmark_on_satellite(): model = torch.load('weights/best.pt')['model'].float() model.eval() # 模拟真实卫星图流式输入:每张图分块推理,再拼接结果 for tile in satellite_tiler('input.tif', tile_size=1024): pred = model(tile) # 单块推理 merge_results(pred, global_bbox_list) # 坐标映射回原图 # 输出带地理坐标的GeoJSON,供GIS软件加载 save_geojson(global_bbox_list, 'output.geojson')

它验证了两件事:1)模型能否处理超大图(不OOM);2)输出能否对接GIS工作流(坐标系转换正确)。若跳过这步,你训出的模型只能在test_batch0_pred.jpg里画框,进不了应急指挥系统。


4. 推理与部署:OpenCV不是摆设,是绕过PyTorch推理瓶颈的快捷通道

4.1detect.py的卫星场景定制化改造

标准YOLOv5的detect.py直接调model(),但本项目重写了run_inference():

def run_inference(source, weights, conf_thres=0.3, iou_thres=0.4): model = attempt_load(weights, map_location=device) stride = int(model.stride.max()) dataset = LoadImages(source, img_size=1024, stride=stride) for path, img, im0s, vid_cap in dataset: img = torch.from_numpy(img).to(device) img = img.float() / 255.0 # 归一化 if len(img.shape) == 3: img = img[None] # expand for batch dim # 关键:OpenCV后处理替代PyTorch NMS pred = model(img)[0] # [1, 25200, 6] → xyxy, conf, cls pred = non_max_suppression(pred, conf_thres, iou_thres) # 用OpenCV画框(比matplotlib快5倍) for det in pred: if len(det): for *xyxy, conf, cls in det: c1, c2 = (int(xyxy[0]), int(xyxy[1])), (int(xyxy[2]), int(xyxy[3])) cv2.rectangle(im0s, c1, c2, (0,255,0), 2) cv2.putText(im0s, f'collapse {conf:.2f}', (c1[0], c1[1]-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,0), 2) cv2.imwrite(f'inference/{Path(path).stem}_pred.jpg', im0s)

这里non_max_suppression虽仍用PyTorch版,但最终可视化强制走OpenCV——因为cv2.rectangle在1024×1024图上耗时0.02s,plt.imshow+plt.savefig要0.3s,批量处理100张图差30秒。

4.2onnx.py:ONNX不是终点,是跨平台部署的起点

onnx.py导出的不是通用ONNX,而是带卫星图预处理的定制图:

# onnx.py 关键修改 def export_onnx(): model = attempt_load('weights/best.pt', map_location='cpu') model.eval() dummy_input = torch.randn(1, 3, 1024, 1024) # 插入预处理节点:CLAHE增强 + 归一化 class SatellitePreprocess(nn.Module): def forward(self, x): # 这里应调用OpenCV的CLAHE,但ONNX不支持cv2 # 所以退而求其次:用torch实现近似CLAHE(见utils/clahetorch.py) x = clahe_torch(x) return x / 255.0 preproc = SatellitePreprocess() traced_preproc = torch.jit.trace(preproc, dummy_input) torch.onnx.export(traced_preproc, dummy_input, 'preproc.onnx', ...)

导出的preproc.onnx和model.onnx需串联使用。若直接导出model.onnx并跳过CLAHE,推理结果mAP掉12%——这就是为什么onnx.py必须存在。

4.3test.py:不是demo,是边界case压力测试清单

test.py里藏着5个必跑case:

  1. test_shadow_area():在建筑物阴影区放人工倒塌标签,测模型是否误判阴影为坍塌;
  2. test_small_debris():生成5×5像素碎砖块,验证最小可检目标尺寸;
  3. test_adjacent_roofs():两栋紧邻房屋,一栋塌一栋没塌,测定位精度;
  4. test_cloud_cover():叠加20%云层遮挡,测鲁棒性;
  5. test_night_image():用近红外通道模拟夜间成像,测多光谱有效性。
    每个case输出test_batchX_pred.jpg和test_batchX_gt.jpg,肉眼比对框偏移像素数。我第一次跑test_adjacent_roofs()发现框偏移达12像素(超允许误差8px),追查发现是models/yolov5s_downhouse.yaml里stride=32导致定位网格太粗,遂改用yolov5m(stride=16)重训。

5. 避坑指南:卫星图检测的五个血泪经验,少踩一个都得多调三天

5.1 现象:训练loss下降但val/mAP不升,甚至负增长

原因:卫星图标注噪声大,labels/目录下存在大量“疑似倒塌”但未确认的模糊标注,模型学到错误模式。
解决:运行utils/label_quality_check.py,它用cv2.contourArea()计算每个bbox内像素方差,剔除方差<50的伪标签(平滑区域如水泥地易被误标)。实测清理后mAP提升6.2%。

5.2 现象:detect.py推理结果框抖动,同一张图多次运行框位置偏移2–3像素

原因:torch.backends.cudnn.benchmark = True启用后,CuDNN对不同输入尺寸选不同卷积算法,导致浮点计算路径不一致。
解决:在detect.py开头强制关闭:

torch.backends.cudnn.benchmark = False # 关键!卫星图需确定性推理 torch.backends.cudnn.deterministic = True

5.3 现象:onnx.py导出失败,报错RuntimeError: ONNX export failed: Couldn't export operator aten::adaptive_avg_pool2d

原因:yolov5s_downhouse.yaml里加的AdaptiveAvgPool2d层不被ONNX 1.10支持。
解决:替换为固定尺寸池化:

# 原配置 - [-1, 1, AdaptiveAvgPool2d, [1,1]] # 改为 - [-1, 1, nn.AvgPool2d, [4,4]] # 用4×4平均池化近似全局池化

5.4 现象:test.py中test_cloud_cover()case召回率暴跌,但test_shadow_area()正常

原因:云层遮挡导致近红外波段信噪比骤降,而模型只用了可见光三通道。
解决:修改dataset.py,在__getitem__中加入近红外通道:

# 读取四通道TIFF(R,G,B,NIR) img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # shape=(H,W,4) img = img[:,:,:3] # 先用RGB训练,后续再融合NIR # 后续在model head加NIR特征融合分支(见models/common.py新增FusionLayer)

5.5 现象:inference/下生成的_pred.jpg框颜色发紫,绿色框变成品红

原因:OpenCV默认BGR顺序,而cv2.rectangle传入(0,255,0)是BGR,显示为绿色;但若输入图是RGBA模式(带alpha通道),cv2.cvtColor()会错乱。
解决:在detect.py中强制转BGR:

if len(im0s.shape) == 3 and im0s.shape[2] == 4: im0s = cv2.cvtColor(im0s, cv2.COLOR_BGRA2BGR) # 关键修复

6. 进阶技巧:用results.txt反向调试,把评估指标曲线变成调参导航图

6.1results.txt不是日志,是逐样本诊断报告

训练完runs/train/exp_downhouse/results.txt不是简单汇总,而是按epoch记录每个batch的详细指标:

Epoch 187: box_loss=0.0213, obj_loss=0.0345, cls_loss=0.0121, precision=0.812, recall=0.756, mAP@0.5=0.728, mAP@0.5:0.95=0.409

但真正有用的是runs/val/exp_downhouse/labels/下的.txt文件——每个预测框都带confidence和IoU:

# test_batch0_pred.txt 0 0.421 0.567 0.082 0.091 0.87 # class, x_center, y_center, width, height, confidence 0 0.432 0.571 0.079 0.088 0.32 # 同一目标两个低置信度框 → NMS阈值太高

我习惯用pandas读取所有results.txt,画confidence分布直方图:若峰值在0.2–0.4区间,说明模型输出普遍保守,需调低conf_thres;若集中在0.7–0.9,则iou_thres该调高防漏检。

6.2 用precision-recall_curve.png定位最优置信度阈值

这张图横轴是recall,纵轴是precision,曲线下面积是mAP。但它的真正价值是找操作点(operating point):

  • 若业务要求“宁可漏检不错报”(如灾情初筛),选曲线左端(recall=0.5, precision=0.92)→conf_thres=0.65;
  • 若要求“尽量不错过”(如保险定损),选右端(recall=0.85, precision=0.58)→conf_thres=0.25。
    我在detect.py里加了动态阈值开关:
if args.mode == 'screening': conf_thres = 0.65 elif args.mode == 'assessment': conf_thres = 0.25 else: conf_thres = 0.3

6.3train_batchX.jpg里的梯度热力图,比loss曲线更早预警过拟合

runs/train/exp_downhouse/train_batch1.jpg等图不是随便生成的,它是用utils/plots.py的feature_visualization函数绘制的backbone最后一层特征图:

  • 正常训练:热力图呈现清晰屋顶结构纹理;
  • 过拟合早期:热力图只亮在标注框边缘,内部变暗(模型记住了框位置,而非特征);
  • 严重过拟合:热力图全图均匀发亮(模型放弃学习,输出恒定响应)。
    我每次看到train_batch2.jpg里热力图开始“糊成一片”,就立刻停训,用--resume加载第150轮权重继续微调。

从那以后我每次训练完,都强制走一遍python test.py --case all+python utils/analyze_results.py --plot pr+open runs/val/exp_downhouse/train_batch2.jpg三连,哪怕多花2分钟。因为卫星图检测的坑不在代码里,而在数据和指标的细微偏差中——它们不会报错,只会悄悄让你的模型在真实场景里失效。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询