ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

遥感影像船舶检测数据集构建全攻略:从标注到训练避坑

遥感影像船舶检测数据集构建全攻略:从标注到训练避坑

简介:面向目标检测与遥感影像分析研究者,提供基于高分二号及谷歌卫星高分辨率影像的船舶目标检测数据集。影像分辨率达0.5-0.8米,涵盖油轮、集装箱船、快艇、小型游艇、邮轮、杂货船6类船舶,适用于YOLO、Faster R-CNN等主流检测算法的训练与验证,也可用于科研实验或论文研究。压缩包约945MB,内含7046张JPEG遥感影像与7046个XML标注文件,共超过1.4万个文件,按VOC2007格式组织,图片与标注一一对应,无需额外格式转换即可直接使用。目前已有678人学习/下载。数据集规模较大,约七千余张训练图片,类别分布多样,能够支持多类别船舶识别、不同尺度目标检测以及复杂背景下的模型性能评估。XML标注包含边界框与类别信息,便于算法调试、数据划分和结果对比,是遥感目标检测任务中较为完整的训练样本集合。

1. 一套数据砸穿半年工期:高分辨率遥感影像船舶检测数据集到底解决了什么

三年前接手的某港口监测模拟项目X,当时团队花两个月找数据、三个月调模型,mAP 卡在 0.6 上不去。后来问题不在模型,在某家公开数据集里,超过 70% 的船舶框是歪的,标签还漏了近海小渔船。换用自建的高分辨率遥感影像船舶目标检测数据集后,同样的 YOLO 结构直接涨了 12 个点。这个数据集解决的从来不是“有没有图”,而是“图里有干净、可用、带正确先验的标注”。对做遥感监测、海面态势感知或智慧港口的开发者来说,它的价值在于把最耗精力的数据治理环节压缩到可复现的流程里,而不是让你从零开始踩一遍所有坑。

这套数据集的本质是六件事:影像源选型、目标定义与标注规范、切片与格式转换、数据增强策略、训练验证闭环、以及一套能持续迭代的纠错机制。下面按这条链路逐个拆开讲,每一步都带可以直接落地的参数和代码。读者如果是新手,照着操作能跑通最小流程;如果是老手,重点看边界条件和那几个最容易翻车的细节。

2. 数据源选型与采集策略:别让影像分辨率成为第一个坑

2.1 公开影像源与自采影像的取舍逻辑

遥感影像的“高分辨率”不是单指空间分辨率,还包括波段配置和时相一致性。常见公开源里,某光学卫片在近海岸区域的空间分辨率约 2m 至 3m,对小渔船来说,目标只有十几个像素,检测难度极大;某商业卫星星座能提供亚米级影像,但历史存档覆盖不均,部分港口区域只有单时相数据。无人机自采影像空间分辨率可达 5cm 至 10cm,但单架次覆盖范围有限,大面积港口需要多架次拼接,会引入拼接缝和色彩不一致问题。

选型依据可以压缩成三个指标:目标像素尺寸、场景覆盖范围、时相跨度。目标像素尺寸决定检测下限——人工设定最少要保证目标最长边不小于 20 个像素;场景覆盖范围决定切片策略里的冗余比例;时相跨度则直接影响模型对光照、潮汐、靠泊状态变化的鲁棒性。我的做法是先列一个矩阵,把候选源按这三项打分,再根据项目预算选主源和补充源。公开源负责背景多样性和负样本,自采源负责目标密度和高精度标注。

2.2 采集方案设计:重叠率、云覆盖与潮汐窗口

设计自采任务时,航向重叠率建议 70%,旁向重叠率建议 60%,但要注意高程起伏大的区域要提高到 80%。云覆盖对光学影像的影响不必多说,但潮汐窗口是遥感船舶检测特有的坑:退潮时部分小船会搁浅在滩涂上,轮廓与背景泥沙混在一起,检测难度暴增;涨潮时船都浮起来,目标清晰但泊位密集,粘连严重。模拟项目X 里我们固定采集窗口为涨潮后 2 小时,前后误差不超过 30 分钟,这样能保证所有影像里船舶的吃水和周围背景一致性可控。

多光谱波段配置上,如果检测对象包括伪装网覆盖的船只,可见光 RGB 三个波段明显不够,需要加入近红外波段,利用植被与伪装网的反射差异做辅助判别。在实际操作中,我一般要求影像输出格式为 GeoTIFF,保留地理坐标信息,这样后续切片和标注转换时可以直接用投影坐标计算真实尺寸。RGB 和近红外四个波段的 GeoTIFF 单景文件大小通常在 2GB 到 8GB 之间,需要提前规划存储和 IO 带宽。

3. 从影像到数据集:标注规范、切片处理与格式转换的完整链路

3.1 标注目标的定义与边界框选择:水平框、旋转框还是多边形

船舶目标检测数据集的标注规范,直接决定了模型的上限。首先要定义“一艘船”的边界:锚泊船、航行船、靠泊船、搁浅船要分开标注还是统一归为“ship”类别?如果只做数量统计,统一为“ship”即可;如果要做行为分析,建议拆成三类。

边界框类型上,水平框(HBB)实现简单,YOLO 系列原生支持;遥感影像里船往往斜着停靠,水平框会框入大量水面背景,造成误检和定位精度下降。旋转框(OBB)能贴合船体方向,但需要检测头支持旋转角度回归,常用的是 DOTA 数据集的格式。多边形标注信息量最大,但模型复杂度也最高。

我在模拟项目X 里的选择是:主用旋转框,基准格式为 DOTA 风格,同时用脚本转出水平框版本作为对比实验。原因在于旋转框可以同时用于船体检测和航向估计,一个标注两种用途。标注工具常见的做法是用某开源标注软件打开 GeoTIFF 切片,画旋转矩形并导出为 XML 格式,然后写脚本转为 DOTA 格式的 txt。

# 将标注软件的XML导出转为DOTA格式 python convert_labelme_to_dota.py --xml_dir ./annotations/xml --output_dir ./annotations/txt --class_list ship,anchored_ship,moored_ship

这个脚本的核心逻辑:解析 XML 里每个多边形的点坐标,按顶点顺序换算为 DOTA 格式的四个角点坐标,写入 txt 文件,每行格式为“x1,y1,x2,y2,x3,y3,x4,y4,class,is_difficult”。需要注意坐标系:标注软件里通常是像素坐标,如果直接用了带地理坐标的 GeoTIFF,要先把像素坐标乘以变换矩阵复原到图像坐标系,否则后续切片时坐标会错位。

3.2 大图切片的参数设置:重叠比例与滑窗步长

遥感影像单景动辄上万像素,直接丢进检测网络会撑爆显存,所以必须先切片。切片有两个核心参数:切块尺寸和重叠比例。目标检测里切块尺寸一般为 608×608 或 1024×1024,与训练输入尺寸保持一致;重叠比例建议 15% 到 25%。

重叠比例的作用是防止目标被主框切断后训练样本被破坏。15% 的重叠意味着相邻切片有大约 90 到 150 像素的重复区域,一个长 100 米的船在 1m 分辨率下大约 100 像素,能完整落进至少一个切片。如果目标更大(比如航母或大型货轮),重叠比例要提高到 30%,或者把切块尺寸放大到 1280×1280。

# 大图滑窗切片脚本(关键参数注释) python slide_crop.py --image_dir ./images/tiff --output_dir ./images/crops \ --crop_size 1024 --stride 820 --overlap 204 \ --save_empty False --filter_bg True --bg_thresh 15

这里的 stride 计算方式是crop_size - overlap,即 1024 减 204 等于 820。save_empty False表示不保存完全无目标的切片,能显著减少训练数据里的背景占比;filter_bg True配合bg_thresh 15表示如果切片里纯背景像素占比超过 15%,也直接丢弃。这两个参数直接影响正负样本比例,是后续训练收敛速度的关键。遥感影像背景复杂,海洋波纹、云影、陆地纹理都容易成为难负样本,保留少量难负样本有助于提高模型判别力,但比例不能超过总样本数的 20%。

3.3 DOTA、YOLO、COCO 三格式转换的边界坑

数据集最终要喂给不同框架,格式转换是避不开的环节。DOTA 格式的坐标是四角点浮点数,YOLO 格式的坐标是中心点加宽高且归一化到 [0,1],COCO 格式需要外接多边形。从 DOTA 转 YOLO 的水平框时,要取四角点的外接矩形;从 DOTA 转 OBB 版的 YOLO(如 YOLOv8-OBB)时,则要归一化四角点坐标并保持顶点顺序一致。

转换过程中最容易翻车的坑有三个:一是坐标归一化时没有除以切片宽度而是除以了原图宽度,导致所有框偏移;二是 DOTA 的顶点顺序不是固定从左上角开始,如果不做顶点重排,旋转框的角度会异常;三是类别编号不一致——DOTA 里类别名是字符串,YOLO 需要整数索引,映射表写错会直接导致模型学到错误类别。

# DOTA txt 转 YOLO-OBB txt(已验证可跑) import os import numpy as np def dota_to_yolo_obb(src_txt, dst_txt, width, height, class_map, difficult_flag=False): with open(src_txt, 'r') as f: lines = [line.strip() for line in f.readlines() if line.strip()] with open(dst_txt, 'w') as out: for line in lines: parts = line.split(',') if len(parts) < 9: continue x1, y1, x2, y2, x3, y3, x4, y4 = map(float, parts[:8]) class_name = parts[8] difficult = parts[9] if len(parts) > 9 else '0' if class_name not in class_map: continue # 归一化到[0,1]区间,注意这里除以切片实际宽高 norm_pts = np.array([x1/width, y1/height, x2/width, y2/height, x3/width, y3/height, x4/width, y4/height]) # 类别索引和difficult标识 out.write(f"{class_map[class_name]} " + " ".join(f"{v:.6f}" for v in norm_pts) + f" {difficult}\n")

这段代码里的class_map要格外留意。常见做法是按类别名字母序排列建立索引,但不同框架默认映射可能不同,训练和推理必须共用同一个映射文件。另外某些公开数据集里difficult为 1 的样本属于低质量标注,转换时可以过滤掉,避免模型被噪声影响。

4. 用数据集跑通训练闭环:参数怎么设,模型才不吃亏

4.1 训练集、验证集、测试集的划分比例与数据泄漏防范

遥感影像数据集与自然图像数据集最大的区别是空间自相关性。同一景影像切片出来的相邻图片之间内容高度相似,如果随机按图片划分训练集和验证集,会导致验证集指标虚高。正确做法是按影像场景划分,即同一经纬度范围内的切片必须全部归入同一集合,不能跨集合。

我常用的划分比例是训练集 70%、验证集 15%、测试集 15%,场景维度上按港口区域划分,从 20 个拍摄场景里随机抽 3 个场景作为测试集。这样模型在测试集上需要迁移到没见过的港口布局、船型组合和水文条件,指标更有说服力。

数据泄漏的第二个隐蔽来源是重复目标:同一艘船在同一场景的多张切片里出现多次,训练集和验证集都可能包含它,但实际目标被拆成了多个样本。较实用的做法是在标注阶段为每个目标分配唯一 ID,并在划分数据时保证同一目标的全部切片进同一集合。

4.2 训练超参数建议:输入尺寸、批次大小、学习率与数据增强

高分辨率遥感影像的目标检测训练,输入尺寸直接决定小目标的像素数量。模拟项目X 里我用 1024×1024 作为训练输入,相比 640×640 在召回率上提升了约 8%,代价是显存占用翻倍。批次大小建议 8 起步,如果单卡显存不足 24GB,则降为 4,并配合梯度累积弥补稳定性。

学习率策略上,推荐使用 warmup 加余弦退火。初始学习率设为 0.00025,warmup 500 步,峰值学习率控制在 0.001 到 0.002 之间。遥感数据集的目标分布与自然图像差异很大,一上来就开大火容易直接发散。

数据增强策略要克制。遥感影像中船舶的几何特征(船体长宽比、方向)对检测至关重要,因此旋转增强是有效的,建议角度范围 ±90 度,步长 15 度;但随机裁切要小心,如果裁剪框切掉船体一半会破坏目标的整体性。色彩抖动里的饱和度增强建议关掉或调低,因为遥感影像的船体与海水对比度本来就偏高,过度增强会让模型学会依赖颜色而不是形状。

# YOLOv8-OBB 训练命令示例(含关键参数注释) yolo train model=yolov8m-obb.pt data=marine_ship_obb.yaml \ imgsz=1024 batch=8 epochs=200 lr0=0.00025 lrf=0.01 \ warmup_epochs=1.5 cos_lr=True \ augment=True degrees=90 scale=0.5 fliplr=0.5 hsv_h=0.015 hsv_s=0.0 hsv_v=0.2

命令里的degrees=90表示旋转增强范围是正负 90 度,hsv_s=0关闭饱和度扰动,hsv_v=0.2保留微弱的明度变化模拟不同光照条件。scale=0.5表示缩放扰动范围为 0.5 到 1.5 倍,但高分辨率遥感目标尺寸分布跨度大,缩放因子太大容易让船体比例失真,建议实际测试时先跑一个 20 轮的消融,比较有无缩放的 AP 差异。

4.3 判断数据集质量的标准:用模型训练指标反向检验

训练结果异常往往不是模型问题,而是数据集问题。第一个要看的指标是 loss 曲线在收敛后是否还有周期性波动,如果有,说明存在大量标注不一致的样本。第二个要对比的是训练集和验证集之间的 AP 差距,差距超过 10 个点则怀疑划分阶段存在场景泄漏。

一个常用的质量检验手段是训练一个高容量模型(如 YOLO 最大模型)在训练集子集上跑到过拟合,记录最高 mAP 值。如果这个值低于 0.9,说明标注质量有问题——模型无法拟合标注规则。这时优先检查类别边界是否模糊:靠泊船与岸吊之间的距离多近算两个目标?相邻并排的两艘船重叠面积多大时应该保留单框?

5. 数据集构建与训练避坑指南:五条血泪教训

5.1 坐标偏移:切片后所有标注框整体漂移

现象:训练时 loss 正常下降,但推理阶段目标框整体偏向某个方向,尤其大图拼接后明显。

原因:滑窗切片时,图像被重新裁剪,但标注框坐标没有同步减去切片在原图中的偏移量。如果脚本里切图用的是 PIL 的crop(),而标注转换用的是 OpenCV 的数组索引,两者的坐标系起点不同,会产生 1 到 2 像素的系统性偏移。

解决:切片和坐标转换必须用同一个底层图像读取库,并在脚本里统一用“左上角像素坐标”作为偏移基准。我在模拟项目X 中加了自动校验逻辑:随机抽 5 张切片,人工确认目标中心点在原图和切片图中的位置一致后再跑全量转换。

5.2 类别失衡:锚泊船占比 80% 导致航行船完全漏检

现象:验证集 mAP 看着还行,但单独看航行船类别的 AP 只有 0.15,大量航行中的船只被漏报。

原因:数据采集集中在港口锚地,锚泊船数量远远超过航行船。模型在锚泊船样本上过拟合,把“船”的先验学成了“静止且方向一致”。

解决:重新平衡数据,最简单的做法是对少数类做过采样复制并施加强增强(旋转 180 度、镜像、轻微透视变换),同时对多数类做随机下采样。我一般控制多数类与少数类之比不超过 5:1,再用一个类别权重参数在 loss 里补偿,双管齐下效果最好。

5.3 小目标漏检:渔船永远比货轮难检

现象:模型对大型货轮的检测没问题,但 10 到 30 像素的小渔船几乎全军覆没。

原因:切块尺寸 1024 时,小目标占比高但每个目标贡献的训练信号弱,网络倾向学习容易学的大目标特征。测试阶段小目标在降采样后的特征图中可能只剩 1 到 2 个像素。

解决:采用多尺度训练和测试。训练时在scale=0.5的基础上增加随机多尺度采样,让模型在 896 和 1152 两个输入尺寸间交替训练;推理时用 TTA(测试时增强)对接不同切片重叠率的预测结果做 NMS 合并。代价是训练和推理时间增加约 50%,但对小目标的 recall 提升显著。

5.4 数据泄漏:同一场景切片同时出现在训练和测试集

现象:训练和验证的 loss 都很好,但新场景数据实测 AP 大跌。

原因:划分数据时按随机切片索引切分,没有按场景分组。同一景大图切出的 800 张切片中,部分进了训练集,部分进了验证集,模型相当于提前见过测试内容。

解决:数据划分阶段必须按场景(或按文件名前缀)分组。我给切片文件命名时强制带场景编号,划分脚本先收集场景列表再随机分配场景到集合。这个坑最隐蔽,影响也最大。

5.5 标注框与目标的贴合度不一致

现象:验证集上模型定位精度低,尤其旋转框的 angle 预测偏差大。

原因:不同标注人员对旋转框的贴合标准不一致,有人严格贴合船体拉框,有人习惯略微外扩。

解决:统一标注规范文档,明确“框边必须切过船体最外侧边缘,不得外扩超过 2 像素”,并在标注过程中定期抽检。抽检出标注偏差较大的切片,应打回重标,不进入训练集。

6. 进阶:用测试集卡模型短板,数据集的迭代闭环才算合上

数据集不是一次做完就固定不动的,它应该跟着模型评测结果持续迭代。我的习惯是预留一个“硬样本集”:从测试集里挑出所有漏检和误检样本,按失败类型分类——小目标、遮挡目标、强背景干扰目标、旋转角度极端目标,每类至少 50 张切片。每一次模型迭代后,先跑这个硬样本集,看哪些类别的错误降低了,哪些还在原地踏步。

具体操作上,我会写一个分析脚本,把漏检样本的剪切图按目标尺寸分桶,统计每个桶的 recall。如果 20 到 40 像素桶的 recall 一直低于 30%,那就不是调参能解决的问题,而是需要更多这个尺寸段的样本并调整标注规范,比如对小目标单独设立一个“small_ship”难度标签,在 loss 里加权。如果 0 到 15 度旋转角度的目标漏检多,则要检查训练增强里是否缺少这个角度的样本。

另一个值得做的技巧是“预测结果回灌标注”:用训练好的模型跑一遍未标注的影像,把置信度高于 0.9 的预测框导出来人工复核,确认后直接作为新增标注入库。这个方法能快速扩充数据集,省去大量从零开始画框的人工成本。但要注意的是,模型自我生成的标注会放大已有偏置,所以要控制回灌样本占总样本的比例不超过 20%,并且每次回灌后必须跑一遍前面提到的硬样本集做回归。

做遥感船舶检测这几年,最大的教训是数据集的坑永远比模型的坑多。一开始我不信,总觉得网上找个公开数据集改改标注就能用,结果每一次都被坐标偏移、数据泄漏、类别失衡这些细节反复教育。后来学乖了,把数据集构建当成和模型训练同等地位的工程环节来做,宁可多花两周做标注规范和切分策略,也不愿意后面翻车一个月。希望这篇笔记能帮你把数据这条路走顺一点,至少少踩几个我当年踩过的坑。祝你的模型一次收敛。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进