简介:面向人工智能目标检测研究者与开发者的旋翼机卫星影像数据集,专项用于训练和评估基于深度学习的旋翼机识别定位算法,可服务于无人机监控、遥感图像分析、搜索救援等场景。压缩包共2000个文件,以jpg图像、xml标注文件和txt说明为主体,内置images、annotations、info.txt三个模块,其中images存放卫星原图,annotations存放XML标注,info.txt提供数据说明,jpg与xml一一对应,整体约271MB。目前已有923人学习使用。数据集中旋翼机为唯一目标类别,标注覆盖有目标与无目标样本,XML提供精确边界框坐标,适合作为YOLO、Faster R-CNN等主流目标检测模型的训练与调参基准。清晰的文件结构便于开展数据预处理、数据增强和mAP等指标评估,无论是算法对比、消融实验,还是面向垂直场景的检测落地,都能提供稳定可靠的支撑。
1. 卫星图上找旋翼机,难的不是算法,而是没数据
卫星图上的旋翼机和你在自然照片里见到的完全不是一回事:一架约 10 米长的直升机在 0.5 米分辨率的影像里只占 20×20 像素,旋翼阴影和停机坪标线几乎融为一体;多旋翼无人机更是只有 3~5 像素,和传感器噪点没有肉眼区别。直接套用 COCO 预训练模型,第一轮跑下来 mAP 往往不到 0.2。问题不是模型不够强,而是大多数通用目标检测数据集里根本没有针对“旋翼机 + 卫星视角”的样本。下面我按数据集构建流程讲清楚怎么从历史卫星图做一套能用的旋翼机检测数据集,并用 YOLOv8 训到可用状态。适合做遥感目标检测、人工智能大作业或无人机巡检方向的人读,重点是类别定义、切片、标注和训练参数,而不是算法理论空谈。
2. 旋翼机卫星图目标检测数据集的类别定义、分辨率与标注格式
2.1 先定义“旋翼机”在卫星图里的视觉特征
常见做法是把旋翼机分成两类:直升机(helicopter)和多旋翼无人机(multicopter)。直升机机身为长条形,主旋翼在正上方时会产生圆形阴影,停机坪上一般有 H 标志或圆形标线;多旋翼无人机在卫星图上只是一个暗色十字或圆形斑点,需要用更陡的阈值才能和地表纹理区分开。如果数据源分辨率偏低,我一般建议先合并成单一类“rotorcraft”,等样本量超过 500 后再拆分,否则类别间差异会被网络学成噪声。
实际标注时要注意区分固定翼飞机和车辆。固定翼飞机机翼细长,沿跑道方向排列,阴影与机身夹角不呈十字;车辆反射率高、轮廓方正,且通常汇聚在停车区。建议在标注规范里写入排除规则:目标长度小于 5 像素或大于图像宽度 1/5 的不标;被建筑物遮挡超过一半的不标;旋翼阴影不算额外目标。否则标注员会把同一个目标的机身和阴影标成两个框,导致训练时 cls loss 居高不下。
2.2 影像分辨率和切片策略:像素尺寸决定检测难度
历史卫星图分辨率通常为 0.3~2 米。0.3 米影像中,10 米长的直升机约占 33 像素;2 米影像中只有 5 像素。采集时优先选最高可用分辨率,并在工程上把输入分辨率提升到 1024 或 1536。常见做法是用 1024×1024 切片训练,重叠 128~256 像素,避免目标正好落在切片边界。
下表是分辨率和目标像素的对应关系,按全尺寸旋翼机(约 10 米长)估算:
| 影像分辨率 | 目标像素尺寸 | 适合的模型输入 |
|---|---|---|
| 0.3m | 约 33×33 | 1024~1280 |
| 0.5m | 约 20×20 | 1280~1536 |
| 1m | 约 10×10 | 1536 或切片后局部放大 |
切片时不要对地面分辨率做任意缩放。如果原图是 0.5m 分辨率,切成 1024×1024 后直接输入模型;屏幕上放大多少都没用,模型实际看到的仍是 1024 像素,不会因为显示尺寸变大而看得更清楚。处理小于 10 像素的目标,正确做法不是继续放大图,而是采集更高分辨率影像或在时相上多取几张图做融合。
2.3 用水平框还是旋转框:标注格式的取舍
卫星图中的旋翼机朝向任意,密集停机坪上相邻目标会互相重叠。水平框(HBB)实现简单,但两个相邻直升机如果停成 V 字形,水平框重叠区域的 IoU 很高,训练时置信度互相抑制。旋转框(OBB)能更紧凑地贴合目标,YOLOv8-OBB 和 DOTA 格式默认支持。
| 格式 | 表达方式 | 优点 | 缺点 |
|---|---|---|---|
| HBB | cx, cy, w, h | 标注快,工具多 | 密集场景框噪声大 |
| OBB | 四个角点坐标 | 贴合方向,mAP 更准 | 标注成本高,工具支持少 |
数据量少于 300 张时,我一般先标注 HBB 快速验证流程;确认场景可行后再用 OBB 重新标注一轮。如果一开始就要求团队每个目标都标旋转框,很容易在标注阶段耗尽人力。实际项目中,把倾斜摆放的直升机用水平框标注,训练出的框是歪的,验证时 mAP50 可能不低,但 mAP50-95 会明显下降,因为定位不够紧。
2.4 参考 DOTA 与 KITTI 能借到什么
公开遥感数据集 DOTA 中有 helicopter 类别,但以机场场景为主,样本偏向大型直升机,缺少多旋翼无人机和停机坪背景。KITTI 是车载视角数据集,它不能直接用于卫星图训练,因为视角、目标尺度和背景分布完全不同;不要因为能下载到 KITTI 数据集就拿来预训练,域差异过大会让模型在真实任务中掉点,甚至比从 COCO 预训练还差。
可以借鉴的是它们的标注思想和数据划分方式:KITTI 按场景文件划分训练/验证,避免同一路段的连续帧跨集合。卫星图也一样,按地理位置划分,防止同一片机场的相邻切片同时出现在训练集和验证集,否则训练时已经见过了验证区域的纹理,指标虚高,换到新机场就崩。
3. 从历史卫星图到标注数据:SASPlanet 取样、GDAL 切片与格式转换
3.1 用 SASPlanet 获取历史卫星图,只取最高缩放级别
SASPlanet 是一个 Windows 下的地图浏览下载工具,支持 Google、Bing、Esri 等在线影像源,也能按多级缩放批量下载。使用步骤:
- 打开 SASPlanet,框选机场或停机坪区域;
- 在操作菜单中选择“下载”,缩放级别选允许的最高级别,通常 17~19 级对应约 0.6~0.3 米地面分辨率;
- 勾选“保存为 JPEG/PNG”并关闭低级别拼接,避免生成过度压缩影像;
- 下载完成后用“生成 KMZ/拼接图片”导出整块大图,导出时带上坐标系参考。
注意:地图源影像有商业版权限制,建议只用于个人学习或内部评估,不要直接发布到公开数据平台。如果做公开数据集,应改用可商用影像源或购买存档影像。SASPlanet 的优势是能拿到同一区域不同年份的影像,这对后面的跨季节验证很有用。
3.2 用 GDAL retile 做重叠切片
拿到大图后,推荐用 GDAL 自带工具切片,命令如下:
gdal_retile.py -ps 1024 1024 -overlap 128 -targetdir tiles rotor_area.tif参数说明:
-ps 1024 1024指定切片宽高为 1024×1024;-overlap 128让相邻切片重叠 128 像素,保证跨边目标在至少一个切片中完整出现;-targetdir tiles指定输出目录;- 输入
rotor_area.tif需要先使用gdal_translate将位深转成 8-bit,否则部分影像显示为黑色。转换命令是gdal_translate -ot Byte -scale 0 255 input.tif temp.tif,影像范围本身没有变化。
切片后需要检查重叠切片中的重复目标。训练时如果原样喂给网络,同一个目标会在两张切片里重复出现,验证集 mAP 会虚高。建议以目标中心所在切片为准,其他切片中删除该目标。
提示:切片后先抽 20 张人工检查,确认目标没有被切碎再进入标注,不要直接用脚本开始标几千张。
3.3 标注与转换:从 LabelMe JSON 到 YOLO OBB
切片完成后用 X-AnyLabeling 或 LabelMe 标注,我习惯用外接旋转矩形工具,导出 JSON。接下来把 JSON 转成 YOLO OBB 格式,每行保存类别和八个归一化角点坐标,顺序为左上、右上、右下、左下:
import json def labelme_to_yolo_obb(json_path, categories, img_w, img_h): with open(json_path) as f: data = json.load(f) lines = [] for shape in data["shapes"]: if shape["label"] not in categories: continue pts = shape["points"] if len(pts) != 4: continue # 归一化;按行排一次,方便回查,不是严格凸包排序 pts = [ (p[0]/img_w, p[1]/img_h) for p in pts ] pts = sorted(pts, key=lambda p: (p[1], p[0])) cls_id = categories.index(shape["label"]) coords = [str(round(v, 6)) for p in pts for v in p] lines.append(f"{cls_id} " + " ".join(coords)) return lines # 使用 categories = ["rotorcraft"] lines = labelme_to_yolo_obb("tile_001.json", categories, 1024, 1024)这段代码的关键是把 polygon 的四个点转成 [0,1] 范围内的归一化坐标。YOLO-OBB 训练时 Ultralytics 会重新计算角点顺序,所以排序不严格也能训练;但统一顺序有利于你人工回查标签。导出后一定要用可视化工具在图上画框检查,最常见的坑是 LabelMe 导出 JSON 的四点顺序不固定,有的点是顺时针,有的点是逆时针,转换后框还是同一个,但训练时角度信息变得不一致,会导致 OBB loss 震荡。
3.4 数据划分与难负样本
划分时按“位置”分,而不是随机分。我习惯用图片名做哈希分组:
import os, hashlib, shutil def split_group(img_name): h = hashlib.sha256(img_name.encode()).hexdigest() return int(h, 16) % 10 for img_name in os.listdir("tiles"): group = split_group(img_name) if group < 2: shutil.move(f"tiles/{img_name}", f"val/images/{img_name}") elif group < 3: shutil.move(f"tiles/{img_name}", f"test/images/{img_name}") else: shutil.move(f"tiles/{img_name}", f"train/images/{img_name}")这个脚本把约 20% 分到验证,10% 分到测试,70% 分到训练。需要注意的是,SASPlanet 下载的同一片区域会生成连续编号的切片,直接按顺序随机切会让验证集和训练集高度相似。哈希分组能让相邻切片大概率落进不同组,但同一机场仍然可能横跨训练和验证。更严格的做法是手动记录每个切片所属的区域编号,按区域分组。
如果正样本只有几百个,模型会倾向于输出大量背景误检。此时需要额外采集不含旋翼机的纯背景切片,作为负样本放入训练集。负样本不需要标注文件,YOLO 在训练时会自动把没有目标的图片当作全背景样本计算 loss。
4. 用 YOLOv8 训练自己的旋翼机卫星图数据集:目录、参数与失败排查
4.1 数据集目录结构与 yaml 配置
Ultralytics 期望的目录结构如下:
datasets/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ └── val/ └── rotorcraft.yamlrotorcraft.yaml写法:
path: datasets/rotorcraft train: images/train val: images/val test: images/test names: 0: rotorcraft如果没有 val 目录,训练会自动从 train 中拆分,但拆分结果不可控,务必自己划分好。YAML 中的 names 顺序必须和标签文件中的类别索引一致,否则模型输出类别名错位。真实项目里我遇到过标签文件第一行写的是1 rotorcraft,而 yaml 里names只有这一个类,训练没有报错,但最终预测框全部显示为 unknown,排查了一整晚。
4.2 训练命令与关键参数
以 OBB 模式为例,训练命令:
yolo obb train data=datasets/rotorcraft/rotorcraft.yaml \ model=yolov8s-obb.pt \ imgsz=1024 epochs=300 batch=8 \ device=0 cache=True参数选择逻辑:
yolov8s-obb.pt适合中小数据集,参数量适中;如果是 0.3m 高分辨率影像,可以换成yolov8n-obb.pt先跑通,再用 s 调优。imgsz=1024不要低于 640,否则小目标被压缩成 3~5 像素,检不出。epochs=300并不代表一定要训满 300 轮,用patience=50早停,验证集 50 轮不涨就停。batch=8需要约 11GB 显存,如果 OOM,优先降batch而不是降imgsz,因为降imgsz对小目标影响更大。cache=True在首次训练时把图片缓存到内存,加速第二次运行,但会占额外内存;机器内存不够就改成cache=ram。
4.3 看训练日志:哪些指标值得关注
训练完成后,Ultralytics 会输出 P、R、mAP50、mAP50-95。mAP50 只能判断目标是否大致检测到,mAP50-95 更能反映框的定位精度。对于小目标,额外看类别对应的 AP,一般以验证集上 32×32 以下目标为主。
下表列出常见的异常和处置方向:
| 日志信号 | 可能原因 | 调整策略 |
|---|---|---|
| P 低且 R 高 | 大量背景误检 | 增加负样本,降低置信度阈值 |
| R 低 | 目标过小或标注缺失 | 提高 imgsz,增加重叠切片 |
| mAP50 高但 mAP50-95 低 | 框不贴合 | OBB 标注角度误差大 |
| val loss 上升 train loss 下降 | 过拟合 | 减少 epochs,加增强 |
如果验证集上 R 持续偏低,优先去看失败样本:如果大部分图片只有两个像素的小点,说明该目标在原始分辨率下就是不充分的,只能用更高分辨率影像或数张影像时序融合,而不是继续增加训练轮次。模型不会无中生有,信息量不够时堆算力没有意义。
4.4 训练失败的最常见原因:标签错误在训练前就要排除
YOLO 训练不检查标签是否越界。如果某个标签的角点 x/y 超出 [0,1],训练会在 loss 计算时报 NaN,之后所有指标变成 0。排查方法:
import os, sys bad_files = [] for f in sorted(os.listdir(sys.argv[1])): path = os.path.join(sys.argv[1], f) for line in open(path): vals = [float(v) for v in line.split()[1:]] if any(v < 0 or v > 1 for v in vals): bad_files.append((f, line.strip())) for f, line in bad_files: print(f, line) print("bad label files:", len(bad_files))这个脚本遍历标签目录,检查每个标签行的第 2~9 个字段是否都在 0~1 内。运行方式:
python check_labels.py datasets/rotorcraft/labels/train另一个常见问题是类别索引从 1 开始而不是从 0 开始,造成所有标签都偏移一位。建议第一版只用一个类别rotorcraft,把names[0]作为唯一类,跑通后再增加直升机、多旋翼无人机等子类。
5. 用 SAHI 做大图推理,验证和上线的最后一步
大图推理不能直接把整个卫星影像塞给 YOLO。常见做法是用切片推理(SAHI)把大图切块、推理、再合并,SAHI 对小目标检测特别有效,因为它天然支持重叠切片。第一步先导出模型到 ONNX,省掉训练环境依赖:
yolo export model=runs/obb/train/weights/best.pt format=onnx imgsz=1024然后运行 SAHI:
sahi predict \ --source test_tiles/ \ --model_type yolov8 \ --model_path runs/obb/train/weights/best.pt \ --slice_size 1024 \ --overlap_ratio 0.2 \ --postprocess_type NMS \ --postprocess_match_threshold 0.5参数说明:--slice_size 1024与训练 imgsz 一致,不要小于 1024;--overlap_ratio 0.2对应 204 像素重叠,防止小目标被切;--postprocess_match_threshold 0.5控制切片间重复框的 NMS 保留阈值,阈值越高越容易保留重复框。如果你的 SAHI 版本显式支持 OBB,可以把--model_type改成yolov8_obb;如果不支持,退化成水平框也能用,但验证时离散场景会有较多重复高置信度框。
输出检测结果后,用以下方式量化小目标指标:把真实标签按目标面积分成small、medium、large,用 Ultralytics 的YOLO.val接口分别算ap_s、ap_m、ap_l。如果ap_s低于 0.3,说明模型看到的小目标信息仍然不足,应该回去增加训练集里的小目标比例,而不是调整验证阈值。
最后一个技巧:不要只用同一季节的卫星图。保留一条春季影像作为测试集,其余日期做训练/验证,这样能验证模型跨季节的稳健性。遥感影像的季节变化常表现为植被从绿色变黄,旋翼机颜色也会跟着变化。训练 mAP 高不代表到了新一季影像还能用,时间维度的验证才是旋翼机检测真正落地的最后一道关卡。
本文还有配套的精品资源,点击获取