简介:无人机目标检测数据集,面向目标检测算法研究者与开发者,适用于训练和优化YOLO、Faster R-CNN等主流模型,并可用于无人机避障、低空安防等实际场景。数据集包含7000多张无人机实拍图像,刻意覆盖不同尺寸和尺度的目标,有助于模型学习更泛化的特征。压缩包共两万二千六百七十五个文件,其中七千五百五十九个txt文件对应YOLO标签格式,七千五百五十八个xml文件对应PASCAL VOC标签格式,另有七千五百五十八张jpg原图,整体大小约877MB。txt格式简洁高效,适合直接接入YOLO系列框架;xml格式包含更丰富的元数据,便于Faster R-CNN、Mask R-CNN等算法解析与扩展。数据集统一围绕“drone”类别进行标注,边界框和类别信息完整,免去人工标注的繁琐,可支撑从模型训练到部署调优的全流程。目前已有两千二百四十八人学习下载,对需要高质量单类无人机数据集的科研团队或个人具有直接参考价值。
1. 目标检测无人机数据集,拿到 drone-data-2.zip 先想清楚用来干什么
无人机航拍目标检测和常规地面监控完全不同。飞行高度把目标像素压得极小,一辆车在 4K 航拍图里经常只占 20×20 像素,加上俯视视角造成目标姿态和背景干扰都与常规数据差异很大,直接用通用数据集训出来的模型往往漏检严重。drone-data-2.zip 这类无人机数据集的用处,就是提供俯视视角下带标注的航拍样本,作为目标检测模型迁移学习的起点。
五年以上经验的工程师拿到 zip 后,第一反应不该是急着解压训练,而是先回答三个问题:标注格式是什么、类别分布是否均衡、目标尺度集中在什么范围。无人机数据集里最常见的坑是标注框不贴目标、类别 ID 不连续、图像分辨率过高导致取块训练困难。这三个问题不解决,后面跑出的 mAP 都只是“看起来高”。
下面按处理航拍数据集的完整流程走一遍:解压统计、格式转换、YOLOv8 训练评估,最后落在无人机场景的三个提分技巧上。
2. drone-data-2.zip 解包后:先摸清目录结构、标注格式与数据分布
2.1 用列表参数查看压缩包内部,再决定如何解压
拿到 drone-data-2.zip 先不要直接unzip到底,先用列表模式看压缩包里有哪些东西:
unzip -l drone-data-2.zip | head -40 unzip drone-data-2.zip -d dataset/第一行只列文件不解压,重点看三件事:图片是否按序列分目录、标注文件是集中在 annotations 目录还是与图片混排、有没有 README 或类别说明文件。第二行把内容解压到指定目录,避免小文件散落得到处都是。
这类无人机数据集解压后常见组织如下:
dataset/ ├── images/ │ ├── seq_001/ │ └── seq_002/ ├── annotations/ │ ├── seq_001.json │ └── seq_002.json └── README.md提示:如果压缩包内没有 README,先打开一个标注文件确认格式,不要凭文件名猜坐标含义。
同一 seq 内的连续帧之间相似度很高,属于同分布样本。做训练集和验证集划分时,要按 seq 切分而不是按单帧随机切,否则同一航线的前后帧同时出现在两边,验证 mAP 会虚高,换到新航线上立刻露馅。
2.2 标注格式与 bbox 坐标体系的差异
无人机数据集的标注格式基本逃不出三种:COCO 的 JSON、Pascal VOC 的 XML、YOLO 的 TXT。三者对同一目标的框表示方式完全不同:
| 格式 | 常见后缀 | bbox 表示方式 |
|---|---|---|
| COCO JSON | .json | [x, y, w, h],像素绝对坐标,左上角原点 |
| Pascal VOC XML | .xml | (xmin, ymin, xmax, ymax),像素绝对坐标 |
| YOLO TXT | .txt | (cx, cy, w, h),中心点加宽高,归一化到 0~1 |
很多无人机数据集标注时用 COCO 或 VOC,训练 YOLO 系列模型前要转成 YOLO TXT。转换时最容易搞混的就是坐标语义:COCO 的 bbox 是“左上角 x、左上角 y、宽度、高度”,不是右下角;VOC 的 bndbox 才是“左上角与右下角两个点”。同一个框在两种格式里元素顺序完全不同,转换前先拿单张图验证,不要批量转完再回头排查。
拿到新数据集,我会随机抽两张图把标注画出来看一遍。坐标体系判断错了,画出来是框和物体完全不贴;类别 ID 判断错了,物体上会标成完全无关的名字。这个检查比看任何说明文档都可靠。
2.3 用脚本统计类别和数量,暴露长尾问题
解压之后我一般会写一小段 Python 看类别分布,判断这个数据集值不值得做完整训练:
import json from collections import Counter with open('dataset/annotations/annotations.json', encoding='utf-8') as f: data = json.load(f) cat_id2name = {c['id']: c['name'] for c in data['categories']} box_count = Counter(cat_id2name[a['category_id']] for a in data['annotations']) print('图片数量:', len(data['images'])) print('标注框数量:', len(data['annotations'])) for name, cnt in box_count.most_common(): print(f'{name:12s} {cnt:6d}')这段代码把 category_id 映射回类别名,再用 Counter 统计每个类别的框数量。无人机数据集中“person 1200、car 5000、truck 18”这样的分布是常态。truck 这种量级的类别在训练时几乎学不出来,需要单独决定是删除、合并还是补外部数据,硬放在训练集里只会拉低整体精度。
3. 把 drone-data-2.zip 的标注转成 YOLO 训练格式
3.1 为什么要统一成 YOLO 格式
YOLOv8 所在的 ultralytics 库虽然也能直接训练 COCO 标注,但大多数数据增强和部署链路默认读取 YOLO TXT。更实际的原因是,YOLO 格式每个 txt 文件和图片一一对应,某帧数据出问题可以单独删除修改,排查起来比埋在 JSON 里直观得多。
转换时要确认类别 ID 是否连续。COCO JSON 的 category_id 从 1 开始且不一定连续,YOLO 的类别 ID 从 0 开始且必须连续。中间缺一个 ID,训练时类别数和标签数对不上,日志里会报 class index 越界,或者混淆矩阵整体错位。这一点在两个格式之间的差异用一个表说得更清楚:
| 对比项 | COCO JSON | YOLO TXT |
|---|---|---|
| 组织方式 | 一个 JSON 集中存全部标注 | 每张图一个 txt |
| 类别 ID | 从 1 开始,可跳跃 | 从 0 开始,必须连续 |
| 坐标 | 像素绝对坐标 | 归一化相对坐标 |
| 检查便捷度 | 需要写脚本解析 | 直接打开即可读 |
3.2 一份可直接改用的 COCO 转 YOLO 脚本
把 COCO JSON 转成 YOLO 格式的 txt,常见做法是写一段转换函数,改输入输出路径就能用于整个压缩包内的所有标注文件:
#!/usr/bin/env python3 # coco2yolo.py —— 将 COCO JSON 转成 YOLO 训练格式 import json import os from pathlib import Path def coco2yolo(json_path: str, out_dir: str) -> None: with open(json_path, encoding='utf-8') as f: coco = json.load(f) images = {im['id']: im for im in coco['images']} # COCO 的 category_id 重映射为连续的 YOLO class id cat_map = {c['id']: idx for idx, c in enumerate(coco['categories'])} os.makedirs(out_dir, exist_ok=True) lines_by_img = {} for ann in coco['annotations']: img = images[ann['image_id']] x, y, w, h = ann['bbox'] # COCO bbox: [x, y, width, height] cx = (x + w / 2) / img['width'] # 转中心点并归一化 cy = (y + h / 2) / img['height'] nw = w / img['width'] nh = h / img['height'] cls = cat_map[ann['category_id']] lines_by_img.setdefault(ann['image_id'], []).append( f'{cls} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}' ) for img_id, lines in lines_by_img.items(): txt_name = Path(images[img_id]['file_name']).stem + '.txt' Path(out_dir, txt_name).write_text('\n'.join(lines) + '\n') if __name__ == '__main__': coco2yolo('dataset/annotations/annotations.json', 'dataset/labels')最关键的是cat_map重映射:COCO 的 category_id 从 1 开始且与顺序无关,YOLO 要求 0 开始连续,用 enumerate 建字典即可。坐标转换是把左上角加宽高的形式改成中心点加宽高,再各自除以图像宽高完成归一化。
输出时保留 6 位小数是为了保证精度又不让文本文件膨胀。数值越大表达同一像素位置越精细,但通常到 1e-6 已经足够覆盖 10000 像素以内的长边。
3.3 划分 train/val 目录并顺手核验标签
转出来的 txt 文件名必须和图片名精确一致,否则训练时找不到对应标签。目录按这个结构组织:
/work/drone-data-2/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/划分按 seq 而不是按单帧。如果压缩包里提供了官方划分文件,直接用官方划分,不要自己重新随机分。
划分完成后花 30 秒核验坐标越界和类别超范围:
find labels -name '*.txt' | xargs awk '{ if ($1<0 || $1>3) print FILENAME, $0 }'这里假设数据集只有 3 个类别,类 ID 取值应小于等于 3。坐标越界的核验类似,检查 $3、$4、$5、$6 是否落在 0 到 1 之间。无人机数据尤其要做这一步,因为 4K 图在边界处的标注框很容易出现归一化后越界的情况。
4. 无人机视角下的目标检测训练配置与数据增强
4.1 小目标密集分布场景,默认参数需要动这几项
通用目标检测训练配置按常规数据集设定,直接套在无人机数据上会明显掉点。影响最大的是输入分辨率:YOLOv8 默认 imgsz=640,一张航拍图里车只有二三十像素,下采样后只剩几个像素,不可能检出。这类数据我一般把 imgsz 提到 1024 或 1280,用显存换检出率。
其他需要调整的增强参数整理成一个表:
| 参数 | 默认值 | 无人机场景建议 | 调整理由 |
|---|---|---|---|
| imgsz | 640 | 1024~1280 | 小目标需要更高的输入分辨率 |
| degrees | 0.0 | 20~40 | 俯视图无固定“上”方向,旋转增强直接提升泛化 |
| flipud | 0.0 | 0.5 | 上下翻转对航拍图同样有效 |
| scale | 0.5 | 0.3~0.6 | 过大会让本就细小的小目标缩没 |
| close_mosaic | 10 | 15 | 最后若干轮关闭 mosaic,避免小目标被切碎影响收敛 |
逻辑在于:无人机是俯视视角,目标没有地面图像里常见的“正立”约束,旋转和翻转成为成本最低的增强手段;而 scale 需要克制,因为很多目标本身只有几十像素,再缩小就直接消失了。
4.2 一条完整的训练命令与参数说明
把上面的思考落到命令上,用 YOLOv8s 做基础模型,我一般这么写:
yolo detect train \ data=drone_data.yaml \ model=yolov8s.pt \ epochs=120 \ imgsz=1024 \ batch=16 \ device=0 \ degrees=30 \ flipud=0.5 \ scale=0.4 \ close_mosaic=15 \ project=runs/drone \ name=exp1data=drone_data.yaml指向数据集描述文件,里面定义 train、val 路径和类别名列表。model=yolov8s.pt用预训练权重做迁移,速度和精度平衡。imgsz=1024是影响结果最大的参数,显存不够先降 batch 到 8。close_mosaic=15让最后 15 个 epoch 关闭 mosaic 增强,避免模型在拼图形成的伪目标上过拟合。能用 GPU 就指定device=0;CPU 也能训练但速度慢一个数量级,建议先把 imgsz 降到 640 做通断验证,确认流程没问题再上全量。
4.3 类别不均衡的处理尺度
无人机数据集的类别长尾比常规数据集更严重。对占优的 person、car,增强参数按上面的表调整即可;对数量只有几十的类别,任何训练技巧都救不回分布,最好直接放弃或者在外部补同类数据。
判断标准是数样本数:最少类不足最多类的十分之一,模型基本只会把这个类学成背景,误检还会拉低整体精度。常见做法是把该类从 names 列表剔除,重新生成 labels,等拿到更多标注再合并训练。
5. 用 YOLOv8 完成目标检测评估与失败样例分析
5.1 在验证集上跑一次完整评估
训练结束后,先用保留的验证集做评估,不要只盯着训练日志里的 loss:
yolo detect val \ data=drone_data.yaml \ model=runs/drone/exp1/weights/best.pt \ plots=True \ imgsz=1024 \ batch=16plots=True会额外输出混淆矩阵、PR 曲线和预测对比图,这些图是判断模型哪里不行的一手材料。命令行打印的 metrics 包含 precision、recall、mAP50、mAP50-95,评估时重点看 mAP50-95,它对小目标更苛刻,能反映框精度的把握程度。
5.2 拆开目标尺寸看精度,而不是只盯一个 mAP
无人机数据集目标尺寸差异大,单个 mAP 会把问题掩盖住。Ultralytics 输出里包含按尺寸拆分的统计项,判读逻辑是:Small AP 明显低于 Medium 和 Large,说明小目标漏检是主要矛盾,下一步在 imgsz 和测试时增强上继续加码;Small 还行但 Large 崩了,大概率是标注本身有问题,比如大目标框不完整或类别标错。
| 现象 | 可能原因 | 下一步操作 |
|---|---|---|
| small AP 低 | 输入分辨率不够 | imgsz 提到 1280,或对图分块训练 |
| Large AP 也低 | 标注框与目标不贴 | 抽样检查原图标注 |
| 某类 precision 低 | 类别容易与背景混淆 | 降低该类权重或补充负样本 |
| 误检集中在边缘 | 切块边界问题 | 推理时用重叠滑窗 |
5.3 用预测图反查训练数据的标注质量
航拍数据标注质量参差不齐是常态。每次训练完我都会打开 plots 输出的预测图,专门找“没标全”的区域:图中明显有车但标签完全没覆盖,说明原始标注漏标率较高,这类数据对训练是负贡献。零星几张直接从训练集移走;大面积存在就要考虑这一批数据是否值得继续用作训练集。无人机数据集数量本来就少,花在清洗上的时间会直接反映在最终评估指标上。
6. 无人机目标检测提速与精度补偿的三个具体技巧
6.1 用测试时增强补小目标漏检
航拍小目标在单次推理时容易漏,测试时增强是见效最快的方式。评估和推理时打开 augment,模型对输入做多尺度变换后综合结果,小目标检出率有提升,代价是耗时翻倍:
yolo detect val model=runs/drone/exp1/weights/best.pt \ data=drone_data.yaml imgsz=1536 augment=Trueimgsz 提到 1536 且打开 augment 后,如果 Small AP 回升,说明模型没到表达上限,只是输入尺度不够。这种做法适合离线出结果,不适合实时推理链路。
6.2 对高度相似的临近帧做去重
航拍视频按帧抽取时,连续几帧几乎相同,进入训练集后会放大同一条航线对模型权重的影响。常见做法是计算相邻帧的感知哈希,相似度高于阈值只保留一帧:
pip install imagehash python - <<'EOF' import imagehash from PIL import Image from pathlib import Path files = sorted(Path('images').glob('*.jpg')) prev = None for p in files: h = imagehash.average_hash(Image.open(p)) if prev is not None and abs(h - prev) < 5: p.unlink() # 相似度过高,删除当前帧 else: prev = h EOF汉明距离小于 5 表示两帧在感知层面几乎一样。跑完再统计一遍类别分布,确认删掉的是不影响分布的冗余帧。
6.3 导出 TensorRT 引擎供机载推理
无人机机载平台算力有限,PyTorch 直接推理很难达到实时,落地时常见做法是导出 TensorRT engine:
yolo export model=runs/drone/exp1/weights/best.pt \ format=engine device=0 half=True imgsz=640导出后模型结构固定,推理时用yolo detect predict model=best.engine source=drone_photo.jpg即可。导出时的 imgsz 要与实际应用匹配,机载端因为算力限制通常退回 640,和训练时的 1024 不一致会有精度损失,实际项目要在速度与精度之间取一个中间值,而不是直接沿用训练参数。
本文还有配套的精品资源,点击获取