ARTICLE DETAIL

资讯详情

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

YOLOv5遥感小目标检测实战:卫星图像中的飞机舰船识别

YOLOv5遥感小目标检测实战:卫星图像中的飞机舰船识别 简介本资源是一套基于YOLOv5框架实现的卫星图像目标检测完整项目面向人工智能、遥感、计算机视觉等方向的高校学生、科研人员及工程实践者解决低分辨率、小目标密集场景下的遥感影像识别难题适用于毕业设计、课程设计、科研原型验证与竞赛备赛。压缩包共132个文件涵盖16个Python主程序含训练/推理/可视化模块、17个YAML配置文件定义模型结构与数据路径、45张结果示意图与9张原始/标注样本图另有Dockerfile、Shell脚本、预训练.pt模型及日志文件整体大小233.82MB结构清晰、开箱即用。已有41人学习下载项目已通过导师评审并获95分高分答辩成绩所有代码均经实机测试可稳定运行。用户可直接部署复现实验效果亦可基于现有模块快速拓展至舰船、车辆、建筑等特定地物检测任务配套文档详述数据预处理、模型微调策略与评估指标分析方法。1. 卫星图像里找飞机、舰船、港口YOLOv5不是拿来跑COCO就完事的——它得在0.3米分辨率下扛住云层遮挡、低对比度和小目标漏检卫星图像目标检测和通用场景检测根本不是一回事。你拿YOLOv5在COCO上训出95% mAP放到WorldView-3或GF-2影像上可能连一艘30米长的渔船都框不住——不是模型不行是输入尺度、信噪比、标注粒度全变了。这个高分项目答辩95分没走“下载预训练权重→微调→导出ONNX”这种快餐流程而是从遥感成像特性出发重构了整条链路用滑动窗口重叠抑制解决大图切片导致的边界截断在models/yolov5s.yaml里把最小检测尺度从32×32压到16×16用utils/plotting.py重写了带地理坐标系映射的可视化模块框出来的结果能直接叠在QGIS里查经纬度。它适合两类人一类是正在写遥感方向毕设的学生需要可复现、可答辩、有文档支撑的完整闭环另一类是工程团队想快速验证算法在真实卫星数据上的鲁棒性不希望花两周调参却卡在数据预处理环节。项目里所有代码都在Ubuntu 20.04 PyTorch 1.10 CUDA 11.3环境下实测通过连events.out.tfevents.*日志文件都保留着训练过程的Loss曲线不是“能跑就行”的玩具工程。2. 为什么必须改YOLOv5的anchor机制卫星图像中小目标检测失效的底层原因与anchor重聚类实操2.1 卫星图像目标尺寸分布 vs COCO默认anchor的致命错配YOLOv5官方anchor基于COCO统计在640×640输入下三个尺度的anchor宽高比集中在[0.5, 2.0]区间最小anchor尺寸约32×32像素。但卫星图像中典型目标尺寸如下港口集装箱吊机单个吊臂在0.3米分辨率下约12×48像素军用舰艇如052D全长约160米 → 533像素但舰桥等关键部件仅20×30像素飞机跑道标记白色线条宽度常为3~5像素提示直接沿用默认anchor会导致小目标在P3/P4特征层上正样本匹配失败——因为anchor与真实bbox的IoU 0.2被判定为负样本梯度无法回传。这不是数据量问题是先验设计缺陷。2.2 基于真实卫星数据集的anchor重聚类全流程项目使用K-means对自建卫星数据集含1276张GF-2影像标注21,438个目标进行anchor重聚类。关键步骤如下2.2.1 数据准备与bbox归一化# 进入data目录确保labels/下为YOLO格式txt文件每行cls x_center y_center w h归一化到[0,1] cd /path/to/project/data/satellite_dataset python tools/generate_anchors.py \ --dataset-dir ./ \ --img-size 640 \ --n-clusters 9 \ --max-iter 1000generate_anchors.py核心逻辑读取所有labels/*.txt提取每个bbox的原始宽高单位像素按YOLOv5的三个预测层stride8/16/32将bbox分配到对应尺度P3层stride8宽高均≥16像素 → 归一化后w,h∈[0.025,1.0]P4层stride16宽高均≥32像素P5层stride32宽高均≥64像素对每个尺度分别运行K-means避免大目标主导聚类中心2.2.2 生成新anchor并注入模型配置执行后输出anchors_kmeans.txt内容示例# P3 layer (stride8) 16,24 18,36 22,48 # P4 layer (stride16) 32,64 40,88 48,112 # P5 layer (stride32) 64,128 80,160 96,192将此结果填入models/yolov5s_sat.yaml的anchors:字段# models/yolov5s_sat.yaml ... anchors: - [16,24, 18,36, 22,48] # P3/8 - [32,64, 40,88, 48,112] # P4/16 - [64,128, 80,160, 96,192] # P5/32 ...2.2.3 验证anchor匹配质量修改train.py中的check_anchors函数在训练前插入验证逻辑# utils/autoanchor.py 行120附近 def check_anchors(dataset, model, thr4.0, imgsz640): # ... 原有代码 ... # 新增打印各尺度匹配率 for i, layer in enumerate(model.model[-1].anchors): matched (iou thr).sum(dim1).float().mean() print(fP{i3} anchor match rate: {matched:.3f} (thr{thr})) # 输出示例P3 anchor match rate: 0.872 (thr4.0)注意thr4.0表示IoU阈值YOLOv5默认为4.0非0.5。若P3层匹配率0.7说明小目标anchor仍需优化——此时应检查是否误将超小目标10像素纳入聚类或增加P3层anchor数量。2.3 卫星图像特有的数据增强策略为什么Mosaic会破坏地理一致性通用Mosaic增强在卫星图像中会产生三类问题地理坐标失真四图拼接后经纬度连续性断裂影响后续GIS叠加分析辐射差异放大不同图像的太阳高度角、大气校正参数不同拼接处出现明显色块小目标稀释原图中占1%面积的目标在Mosaic中被压缩到0.25%特征进一步弱化项目采用替代方案增强类型参数设置作用RandomPerspectivedegrees0, translate0.1, scale0.1, shear0, perspective0仅做平移缩放保持几何拓扑HSVhgain0.015, sgain0.7, vgain0.4降低饱和度增益sgain避免云层过曝区域失真CopyPastep0.3, min_area_ratio0.005将小目标如车辆复制粘贴到空旷区域提升小目标密度# data/augmentations.py class SatelliteAugment: def __init__(self): self.transform Compose([ RandomPerspective( degrees0, translate0.1, scale(0.9, 1.1), shear0, perspective0, p0.5 ), HSV(hgain0.015, sgain0.7, vgain0.4), CopyPaste(p0.3, min_area_ratio0.005) ])3. 大图推理不OOM滑动窗口NMS后处理的内存优化实现与地理坐标还原3.1 卫星影像尺寸与GPU显存的硬约束一张标准GF-2全色影像0.8米分辨率尺寸为24000×24000像素。若直接resize到640×640输入细节损失严重若保持原图送入YOLOv5显存需求计算如下输入张量[1,3,24000,24000]→ 占用显存 ≈ 24000²×3×4 bytes ≈ 6.9 GB加上Backbone中间特征图C3/C4/C5总显存超24GB远超单卡V10032GB极限项目采用动态滑动窗口策略而非固定大小切片窗口尺寸1024×1024适配显存步长51250%重叠避免边界目标漏检重叠抑制在NMS后对跨窗口检测框做地理距离去重3.2 滑动窗口推理核心代码实现# inference/sliding_window.py def sliding_window_inference(model, img_path, window_size1024, stride512, conf_thres0.25, iou_thres0.45): model: YOLOv5模型已加载权重 img_path: 卫星影像路径支持.tif/.jpg window_size: 切片尺寸像素 stride: 步长像素 conf_thres: 置信度阈值 iou_thres: NMS IoU阈值 # 1. 读取影像保持原始分辨率 img cv2.imread(img_path) # 或使用rasterio读取tif h, w img.shape[:2] # 2. 初始化结果容器 all_detections [] # 存储[xyxy, conf, cls, geo_x, geo_y] # 3. 滑动窗口遍历 for y in range(0, h - window_size 1, stride): for x in range(0, w - window_size 1, stride): # 裁剪窗口 window img[y:ywindow_size, x:xwindow_size] # 推理YOLOv5标准流程 results model(window) # 返回pandas DataFrame detections results.pandas().xyxy[0] # 4. 坐标还原将窗口内坐标转为全局坐标 if not detections.empty: detections[xmin] x detections[xmax] x detections[ymin] y detections[ymax] y # 5. 添加地理坐标需预先加载GeoTIFF的affine transform # 此处简化假设已知影像左上角经纬度及分辨率 # 实际项目中使用rasterio.DatasetReader.transform detections[geo_x] detections[xmin] * 0.3 116.0 # 示例经度 detections[geo_y] 39.0 - detections[ymin] * 0.3 # 示例纬度 all_detections.append(detections) # 6. 合并所有检测结果 if not all_detections: return pd.DataFrame() merged pd.concat(all_detections, ignore_indexTrue) # 7. 全局NMS按地理距离去重非IoU final_detections geo_nms(merged, distance_thresh10.0) # 10米内视为同一目标 return final_detections def geo_nms(df, distance_thresh10.0): 基于地理坐标的NMS计算两点间Haversine距离 from sklearn.metrics.pairwise import haversine_distances coords df[[geo_y, geo_x]].values # lat, lon dist_matrix haversine_distances(coords, coords) * 6371 # km → meters keep [] for i in range(len(df)): if i not in keep: keep.append(i) # 删除距离distance_thresh的其他框 to_remove np.where(dist_matrix[i] distance_thresh / 1000)[0] for j in to_remove: if j ! i and j not in keep: keep.remove(j) if j in keep else None return df.iloc[keep].reset_index(dropTrue)3.3 地理坐标还原的关键参数表参数说明获取方式项目中示例值resolution影像空间分辨率米/像素影像元数据或产品说明书0.3WorldView-3ul_lon,ul_lat左上角经纬度GeoTIFF的transform或RPC文件116.0,39.0epsg坐标参考系统影像头文件或GIS软件读取EPSG:4326WGS84distance_thresh地理NMS距离阈值根据目标实际尺寸设定如舰船长150m→设50m10.0适用于车辆注意geo_nms中haversine_distances要求输入为(lat, lon)且单位为弧度。项目中rasterio读取的transform可直接转换像素坐标到地理坐标from rasterio.transform import from_origin transform from_origin(ul_lon, ul_lat, resolution, resolution) # pixel_to_geo(x_px, y_px) → (lon, lat)4. 训练过程可视化与关键指标解读如何从events.out.tfevents中提取有效信息4.1 TensorBoard日志解析不只是看Loss曲线项目保留了完整的TensorBoard事件文件events.out.tfevents.*但直接tensorboard --logdirruns/train会显示大量冗余信息。需针对性提取三类关键指标4.1.1 小目标检测专项指标YOLOv5默认只输出box_loss,obj_loss,cls_loss但卫星图像需关注P3_box_lossP3层最小尺度的定位损失反映小目标回归精度small_obj_recall宽高均32像素的目标召回率需自定义metric在train.py中添加监控# train.py 行250附近 if ni % 100 0: # 计算小目标召回率 small_mask (targets[:, 3] * targets[:, 4]) (32/640)**2 # 归一化面积0.0025 small_targets targets[small_mask] if len(small_targets) 0: small_recall ((pred[:, 4] 0.5) (pred[:, 5:] 0.5)).sum() / len(small_targets) writer.add_scalar(Metrics/small_obj_recall, small_recall, ni)4.1.2 日志文件结构解析events.out.tfevents.*文件包含多组tf.Summary可用tensorboard命令导出CSV# 提取所有scalar数据 tensorboard --logdirruns/train --bind_all --port6006 # 在浏览器打开 http://localhost:6006 → 右上角Export CSV # 或用Python直接解析 from tensorboard.backend.event_processing import event_accumulator ea event_accumulator.EventAccumulator(./runs/train/exp/events.out.tfevents.1599910333.C-000015-GPU.31726.0) ea.Reload() print(ea.scalars.Keys()) # 查看所有可提取指标 # 输出[train/box_loss, train/obj_loss, train/cls_loss, val/box_loss, ...]4.2 高分项目答辩必答的三个技术点4.2.1 为什么不用YOLOv8v5在卫星场景仍有不可替代性轻量级部署优势YOLOv5s2.5MB在Jetson AGX Orin上推理速度达42 FPSYOLOv8s3.8MB仅31 FPS对边缘端卫星接收站至关重要anchor机制可控性v5的anchor可手动重聚类v8默认使用task-aligned anchor难以针对遥感小目标定制训练稳定性v5的autoanchor在小数据集1000张上收敛更鲁棒v8易出现loss震荡4.2.2 如何验证检测结果的地理精度项目提供tools/geo_validation.py输入检测框和真实GIS矢量Shapefile输出平面位置误差RMSE检测框中心到真实多边形最近点的距离方向误差检测框长轴与真实目标航向角偏差尺寸误差检测框面积与真实多边形面积比值python tools/geo_validation.py \ --det-path runs/detect/exp/labels/ \ --gt-shp data/gt_ports.shp \ --crs EPSG:4326 \ --output-report validation_report.csv4.2.3 Docker部署时的CUDA兼容性陷阱Dockerfile中指定nvidia/cuda:11.3.1-cudnn8-runtime-ubuntu20.04但需注意主机NVIDIA驱动版本 ≥ 465.19否则CUDA 11.3不可用torch1.10.0cu113必须与cudnn8.2.1.32精确匹配项目requirements.txt已锁定版本若主机驱动过旧需降级至nvidia/cuda:11.1.1-cudnn8-runtime-ubuntu20.04并更换PyTorch提示运行nvidia-smi查看驱动版本再对照 NVIDIA官方CUDA版本支持表 选择镜像。5. 从检测结果到业务落地如何用OpenCV快速生成带地理坐标的热力图与目标统计报表5.1 热力图生成不只是颜色叠加要体现空间密度与目标类型权重卫星图像热力图需区分目标类型舰船/飞机/车辆并考虑地理投影畸变。项目采用加权核密度估计WKDE# tools/heatmap_generator.py def generate_heatmap(detections_df, output_path, resolution1000, kernel_size50): detections_df: 包含geo_x, geo_y, cls_id列的DataFrame resolution: 输出热力图像素尺寸用于GIS叠加 kernel_size: 高斯核半径米 # 1. 按类别分组赋予权重舰船权重2.0车辆1.0 weights {0: 1.0, 1: 2.0, 2: 1.5} # cls_id → weight detections_df[weight] detections_df[cls_id].map(weights) # 2. 投影到平面坐标系WGS84 → UTM transformer Transformer.from_crs(EPSG:4326, EPSG:32650, always_xyTrue) # UTM Zone 50N utm_x, utm_y transformer.transform( detections_df[geo_x].values, detections_df[geo_y].values ) # 3. 构建二维直方图带权重 x_bins np.linspace(utm_x.min(), utm_x.max(), resolution) y_bins np.linspace(utm_y.min(), utm_y.max(), resolution) H, xedges, yedges np.histogram2d( utm_x, utm_y, bins[x_bins, y_bins], weightsdetections_df[weight] ) # 4. 高斯模糊kernel_size对应地理距离 H_smoothed gaussian_filter(H, sigmakernel_size / (xedges[1]-xedges[0])) # 5. 保存为GeoTIFF带地理参考 transform from_origin(xedges[0], yedges[-1], xedges[1]-xedges[0], yedges[1]-yedges[0]) with rasterio.open( output_path, w, driverGTiff, heightH_smoothed.shape[0], widthH_smoothed.shape[1], count1, dtypeH_smoothed.dtype, crsEPSG:32650, transformtransform ) as dst: dst.write(H_smoothed.astype(rasterio.float32), 1) return output_path # 使用示例 heatmap_path generate_heatmap( detections_df, output/ship_density.tif, resolution2000, kernel_size100 # 100米半径高斯核 )5.2 自动生成统计报表MarkdownLaTeX混合输出项目report/generate_report.py可一键生成含图表的PDF报告python report/generate_report.py \ --input-detections runs/detect/exp/labels/ \ --output-pdf report/satellite_detection_report.pdf \ --title GF-2影像目标检测分析报告 \ --date 2023-09-15生成内容包括目标类型分布饼图Matplotlib置信度分布直方图标注阈值线0.5/0.7地理分布散点图底图使用Cartopy加载自然地球数据详细表格目标ID、类型、经纬度、尺寸、置信度注意LaTeX编译需安装texlive-latex-recommended和texlive-fonts-extraDocker环境中已预装。若本地编译失败可设置--export-md生成Markdown版用Typora直接渲染。5.3 快速验证用一行命令测试任意卫星影像封装为可复用CLI工具# 安装后直接调用 yolov5-satellite detect \ --weights runs/train/exp/weights/best.pt \ --source data/test/spot6_img.tif \ --img 1024 \ --conf 0.3 \ --save-txt \ --save-conf \ --project runs/detect \ --name spot6_result \ --geo-output # 启用地理坐标输出--geo-output参数会自动读取输入影像的GeoTIFF元数据在runs/detect/spot6_result/labels/中生成.txt文件含经纬度在runs/detect/spot6_result/geo_results.json中输出GeoJSON格式结果这样从下载资源到产出第一份带坐标的检测报告全程不超过5分钟。本文还有配套的精品资源点击获取
返回列表