YOLOv5遥感目标检测实战:高分卫星图像小目标检测调优指南
简介本资源是一套基于YOLOv5框架实现的卫星图像目标检测完整项目面向人工智能、遥感、计算机视觉等方向的本科生、研究生及工程实践者解决高分辨率遥感影像中典型地物如车辆、建筑、船舶等自动识别与定位问题适用于毕业设计、课程设计、科研原型验证及算法入门进阶。压缩包共132个文件包含16个核心Python训练/推理脚本、17个配置用YAML文件含数据集划分、模型结构与超参设置、45张可视化结果PNG图、9张原始与标注JPG样本、4个Linux部署Shell脚本、4个预训练PT模型权重以及Dockerfile、README.md和LICENSE等工程化支持文件整体大小233.82MB。已有41人学习下载项目经导师指导并获95分高分答辩评价所有代码均实测可运行配套文档详述数据预处理流程、训练日志分析、mAP计算逻辑及TensorBoard事件文件events.out.tfevents解读方法便于复现、调优与二次开发。1. 卫星图像里找飞机、船、车辆YOLOv5不是拿来即用的“检测器”而是需要重调锚框、重设输入分辨率、重设计后处理逻辑的专用检测框架在遥感图像分析场景中直接把YOLOv5官方权重往卫星图上一跑mAP常掉到20%以下——不是模型不行而是卫星图像和COCO数据集存在三重错配目标尺度差异大一艘船在0.5米分辨率图中仅占3×8像素、长宽比极端跑道、桥梁、输电塔接近1:10、背景干扰强云层、阴影、水体反光导致误检率飙升。这个项目标题里的“高分项目”并非指分数高而是指“高分辨率遥感图像”High-Resolution Remote Sensing Imagery下的工程级落地方案。它不提供开箱即用的exe而是一套完整闭环从GeoTIFF格式预处理、多尺度切片策略、自适应锚框聚类到针对小目标优化的FPN增强结构、支持WGS84坐标回注的检测结果导出。适合已有遥感数据但缺乏CV工程经验的测绘院所、国土调查团队也适合想把YOLOv5真正吃透而非仅调参的算法工程师——你得亲手改models/yolo.py里的Detect层输出通道数得重写utils/general.py中的non_max_suppression以兼容旋转框IoU计算还得在val.py里注入地理坐标系校验逻辑。2. 用YOLOv5s在Sentinel-2影像上跑通最小检测流程从原始GeoTIFF到带经纬度坐标的JSON结果2.1 卫星图像预处理必须绕过OpenCV默认读取陷阱卫星图像常为16位GeoTIFF直接用cv2.imread()会丢失动态范围且忽略地理信息头。正确做法是用rasterio读取并做归一化import rasterio import numpy as np def load_satellite_image(tif_path): with rasterio.open(tif_path) as src: # 读取前3波段R,G,B自动处理nodata值 img src.read([1, 2, 3]) # shape: (3, H, W) transform src.transform # 用于后续坐标转换 # 归一化到[0,1]避免float32溢出 img img.astype(np.float32) img (img - np.min(img)) / (np.max(img) - np.min(img) 1e-8) return img.transpose(1, 2, 0), transform # 转为(H,W,3) # 示例调用 img_array, geo_transform load_satellite_image(data/sentinel2_202305.tif)注意rasterio读取的数组是(C,H,W)顺序YOLOv5要求(H,W,C)必须用transpose若图像含红外波段如Landsat8的Band5需按遥感任务选择波段组合如NDVI增强时用NIRRed不能简单取前3通道。2.2 切片策略决定小目标召回率上限卫星图像单张可达10000×10000像素直接resize到640×640会导致舰船等目标缩为1像素点。必须采用滑动窗口切片并控制重叠率# 使用ultralytics自带的slice工具需修改源码支持地理坐标保留 python tools/slice_dataset.py \ --image-dir data/raw_tifs/ \ --output-dir data/sliced/ \ --slice-height 640 \ --slice-width 640 \ --overlap-height-ratio 0.25 \ --overlap-width-ratio 0.25 \ --no-pad \ --min-area-ratio 0.1关键参数说明--overlap-height-ratio 0.25垂直方向25%重叠确保细长目标如飞机跑道不被切碎--min-area-ratio 0.1丢弃切片中有效目标面积占比低于10%的碎片减少无效推理--no-pad禁用补零避免边缘伪影干扰检测。切片后生成data/sliced/images/和data/sliced/labels/后者包含每个切片对应的.txt标注文件YOLO格式且保留原始GeoTIFF的transform信息用于结果回注。2.3 修改YOLOv5模型输出以适配遥感坐标系原版YOLOv5输出归一化坐标0~1需结合geo_transform转为WGS84经纬度。在models/yolo.py的Detect.forward()末尾插入# 假设batch中每张图对应一个geo_transform从dataloader传入 if hasattr(self, geo_transforms) and self.geo_transforms is not None: for i, (x, transform) in enumerate(zip(pred, self.geo_transforms)): # x.shape (num_boxes, 6) - [x,y,w,h,conf,cls] if len(x) 0: # 将归一化坐标转为像素坐标 h, w self.img_size, self.img_size x[:, [0, 2]] * w x[:, [1, 3]] * h # 像素坐标转地理坐标使用affine变换 from affine import Affine aff Affine.from_gdal(*transform) # 批量转换中心点 centers x[:, :2].cpu().numpy() lats_lons np.array([aff * (cx, cy) for cx, cy in centers]) x[:, :2] torch.tensor(lats_lons).to(x.device)此修改使模型输出直接为(lat, lon, width_deg, height_deg, conf, cls)省去后处理坐标转换步骤。3. 针对卫星图像的YOLOv5超参数重调锚框聚类、输入分辨率、损失函数权重三要素3.1 锚框必须用真实卫星数据重新聚类COCO默认锚框10,13, 16,30, 33,23, ...完全不适用于遥感目标。需用训练集标注文件做K-means聚类import numpy as np from utils.general import xywh2xyxy def kmeans_anchors(dataset_path, n_clusters9, img_size640): boxes [] for label_file in Path(dataset_path).glob(*.txt): with open(label_file) as f: for line in f: cls, x, y, w, h map(float, line.strip().split()) # 转为像素尺寸YOLO格式是归一化需乘以img_size w_px, h_px w * img_size, h * img_size boxes.append([w_px, h_px]) boxes np.array(boxes) # K-means聚类使用IOU距离 from sklearn.cluster import KMeans kmeans KMeans(n_clustersn_clusters, random_state0).fit(boxes) anchors kmeans.cluster_centers_ # 按宽高比排序便于分配到不同检测头 anchors anchors[np.argsort(anchors[:, 0] / anchors[:, 1])] return anchors.astype(int) # 输出结果示例单位像素 # [[ 24, 48], [ 32, 96], [ 48, 128], [ 64, 256], [ 96, 192], # [128, 320], [160, 448], [192, 512], [256, 640]]提示聚类前务必确认标注文件中的w,h是相对图像尺寸的比例值YOLO标准格式否则聚类结果失效若数据集含大量极小目标16px需降低n_clusters至6并手动合并相似尺寸锚框。3.2 输入分辨率必须满足“最小目标≥8像素”原则卫星图像中最小可检目标如小型车辆在0.5米分辨率下约2×4米对应图像尺寸约4×8像素。YOLOv5最小检测单元为stride32故输入尺寸需满足input_size ≥ 32 × max(min_target_width_px, min_target_height_px)→input_size ≥ 32 × 8 256但实际需留余量推荐设为640或768。在train.py中设置# train.py关键参数 parser.add_argument(--imgsz, typeint, default640, helptrain, val image size (pixels)) parser.add_argument(--rect, actionstore_true, helprectangular training) # 启用矩形推理节省显存 parser.add_argument(--cache, typestr, nargs?, constram, defaultram, help--cache images in ram (default) or disk)启用--rect后batch内图像按长宽比分组避免统一resize导致的形变--cache ram将预处理后图像缓存至内存加速训练需≥64GB RAM。3.3 损失函数权重调整表抑制背景噪声强化小目标定位YOLOv5默认损失权重obj_loss:cls_loss:box_loss 1.0:0.5:0.05在遥感场景下易被大面积背景主导。需在models/yolov5s.yaml中修改损失项原权重卫星图像推荐值调整理由box_loss0.050.15小目标定位误差对IoU影响更大需加权obj_loss1.00.7云层、水体易产生高置信度误检降低目标存在性权重cls_loss0.50.8类别区分难度高如军用舰船vs民用货轮需强化分类修改后需重新生成模型配置# models/yolov5s_sat.yaml nc: 3 # number of classes depth_multiple: 0.33 width_multiple: 0.50 anchors: - [24,48, 32,96, 48,128] # P3 - [64,256, 96,192, 128,320] # P4 - [160,448, 192,512, 256,640] # P5 ... loss: box: 0.15 obj: 0.7 cls: 0.8训练命令python train.py \ --data data/satellite.yaml \ --cfg models/yolov5s_sat.yaml \ --weights yolov5s.pt \ --epochs 300 \ --batch-size 16 \ --name satellite_yolov5s_v14. 高分项目必备的地理坐标回注与可视化从检测框到GIS矢量文件的全链路4.1 将检测结果写入Shapefile并保留属性字段检测输出为(lat,lon,width_deg,height_deg,conf,cls)需转为ESRI Shapefile格式供GIS软件加载import geopandas as gpd from shapely.geometry import box import pandas as pd def detections_to_shapefile(detections, class_names, output_path): detections: list of [lat,lon,w_deg,h_deg,conf,cls_id] class_names: [ship,plane,vehicle] geometries [] attributes [] for det in detections: lat, lon, w, h, conf, cls_id det # 创建WGS84坐标系下的矩形注意lon为xlat为y geom box(lon - w/2, lat - h/2, lon w/2, lat h/2) geometries.append(geom) attributes.append({ class: class_names[int(cls_id)], confidence: float(conf), width_m: w * 111320, # 近似转换为米赤道处 height_m: h * 111320 }) gdf gpd.GeoDataFrame(attributes, geometrygeometries, crsEPSG:4326) gdf.to_file(output_path, driverESRI Shapefile) # 调用示例 detections_to_shapefile( pred_results, [ship, plane, vehicle], outputs/detections.shp )注意box()函数参数顺序为(minx, miny, maxx, maxy)对应(lon_min, lat_min, lon_max, lat_max)crsEPSG:4326声明WGS84坐标系确保QGIS/ArcGIS能正确渲染。4.2 在原始GeoTIFF上叠加检测框的Python脚本避免用PIL绘图导致地理精度丢失直接用rasterio写入新图层import rasterio from rasterio.plot import show import matplotlib.pyplot as plt def overlay_detections_on_tif(tif_path, detections, output_path): with rasterio.open(tif_path) as src: # 读取RGB波段 rgb src.read([1, 2, 3]) # 创建绘图对象 fig, ax plt.subplots(figsize(12, 12)) show(rgb, axax, transformsrc.transform, cmapgray) # 绘制检测框转换为像素坐标 for det in detections: lat, lon, w_deg, h_deg, conf, cls_id det # WGS84转像素坐标 row, col ~src.transform * (lon, lat) w_px w_deg / (src.transform.a) # transform.a为经度方向像素大小 h_px h_deg / (-src.transform.e) # transform.e为纬度方向像素大小负值 rect plt.Rectangle( (col - w_px/2, row - h_px/2), w_px, h_px, linewidth2, edgecolorred, facecolornone, labelf{class_names[cls_id]} {conf:.2f} ) ax.add_patch(rect) ax.set_title(Satellite Image with Detections) plt.savefig(output_path, dpi300, bbox_inchestight) plt.close() overlay_detections_on_tif( data/sentinel2_202305.tif, pred_results, outputs/overlay_result.png )此脚本生成的PNG图严格保持原始GeoTIFF的地理配准关系可导入GIS软件进行空间分析。4.3 评估指标必须加入地理精度约束传统mAP忽略坐标误差而遥感应用要求定位误差≤5米。需自定义评估函数def compute_geo_ap(detections, ground_truths, threshold_m5.0): threshold_m: 允许的最大地理距离误差米 from sklearn.metrics import average_precision_score # 计算所有检测框与真值框的Haversine距离米 distances [] labels [] for det in detections: lat_det, lon_det det[0], det[1] min_dist float(inf) matched False for gt in ground_truths: lat_gt, lon_gt gt[0], gt[1] dist haversine_distance(lat_det, lon_det, lat_gt, lon_gt) if dist min_dist: min_dist dist # 若距离小于阈值标记为TP labels.append(1 if dist threshold_m else 0) matched True if not matched: labels.append(0) # FP # 按置信度排序计算AP confidences [det[4] for det in detections] ap average_precision_score(labels, confidences) return ap def haversine_distance(lat1, lon1, lat2, lon2): from math import radians, cos, sin, asin, sqrt R 6371000 # 地球半径米 lat1, lon1, lat2, lon2 map(radians, [lat1, lon1, lat2, lon2]) dlat lat2 - lat1 dlon lon2 - lon1 a sin(dlat/2)**2 cos(lat1) * cos(lat2) * sin(dlon/2)**2 c 2 * asin(sqrt(a)) return R * c该函数输出geo_ap5m比传统mAP更能反映实际业务效果。5. 三个必查的卫星图像检测失败原因及对应调试命令5.1 检测框全部偏移——检查GeoTIFF的坐标系是否为WGS84错误现象检测框集中在图像左上角或整体偏移数十公里。根因输入TIFF使用UTM投影如EPSG:32650但代码默认按WGS84解析。验证命令# 查看TIFF坐标系 gdalinfo data/sentinel2_202305.tif | grep Coordinate System # 若输出含UTM zone 50N需重投影 gdalwarp -t_srs EPSG:4326 -r bilinear \ data/sentinel2_202305.tif \ data/sentinel2_wgs84.tif5.2 小目标完全漏检——验证切片后标注文件是否被截断错误现象训练日志显示box loss持续为0验证时无任何检测输出。根因切片时未启用--min-area-ratio导致小目标被裁剪后面积占比过低标注文件被清空。调试命令# 统计所有切片标注文件的目标数量 find data/sliced/labels/ -name *.txt | head -20 | \ xargs -I {} sh -c echo {}: $(wc -l {}) # 若某文件输出为xxx.txt: 0说明该切片无有效标注5.3 推理速度骤降5倍——确认是否启用了CUDA Graph优化错误现象单图推理耗时从200ms升至1s以上GPU显存占用异常高。根因torch.compile()在YOLOv5中尚未稳定支持启用后反而拖慢。修复方法在detect.py开头添加# 禁用torch.compileYOLOv5 v7.0默认启用 import torch torch._dynamo.config.suppress_errors True torch._dynamo.config.verbose False并在推理命令中显式关闭python detect.py \ --weights runs/train/satellite_yolov5s_v1/weights/best.pt \ --source data/sliced/images/ \ --device 0 \ --nosave \ --no-trace \ # 关键禁用TorchScript trace --half # 启用FP16加速本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →