news 2026/10/14 7:04:35

无人机航拍目标检测数据集总结:小目标、格式转换与训练实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无人机航拍目标检测数据集总结:小目标、格式转换与训练实战

搞目标检测的人,一开始都是拿经典目标检测数据集练手,可一旦转到无人机、航拍场景,很多人会直接傻眼:同一套模型,在航拍数据集上的表现往往明显缩水。这不是模型变懒了,而是数据分布完全不同。这篇目标检测-无人机、航拍数据集总结,我把这几年做航拍目标的经验重新过了一遍,重点聊聊数据集的差异、怎么选、怎么转换格式,以及训练和评估中实际踩过的坑。想看数据集清单的,可以直接跳第 2 节;想解决标注转换和训练问题的,建议从头往后读。

1. 航拍数据集的特殊之处:小目标、俯瞰视角与高密度遮挡

很多人第一次看到航拍数据会觉得很新鲜,但真正开始准备训练集时,才发现它和普通数据集完全是两回事。下面从数据本身的三个维度讲清楚。

1.1 俯瞰视角改变了“上下文”

传统目标检测数据集里,绝大多数目标是在正视角、近似平视场景下拍摄的。目标通常占画面比例较大,周围有一圈相对清晰的“上下文”,比如人站在马路边、车在车道中央,模型可以借助这些语义线索辅助识别。

航拍数据不一样。无人机和航拍设备的视角通常接近俯视,甚至完全垂直向下。目标在图像里是以头顶、车顶、舱顶的形式出现,很多在地面视角下很明显的特征会丢失:人脸看不到、车身侧面曲线看不到、人的姿态轮廓也只剩下一个俯视投影。于是模型必须依赖形状、颜色、纹理和周围环境的相对关系来做判断,这对数据集的多样性要求变得非常高。

我见过不少团队直接把普通场景训练出来的权重拿去做推理,结果画面里大部分物体都被框出来了,但类别基本是混乱的。原因不复杂:预测模型从没有在“俯视图”中学到过这类外观特征。航拍数据集不是简单换一批照片,而是换了一整套视觉表达体系。

1.2 小目标:不是小问题

无人机航拍图像的分辨率通常很高,动辄 4000×3000 甚至更夸张,但单个目标可能只有几十个像素。再极端一点,高度稍高的航拍画面里,一辆汽车在原始大图上可能只有 15×25 像素。

COCO 数据集把小于 32×32 的目标称为小目标,在普通场景里这个比例已经让人头疼。而航拍数据里,小目标占比常常超过一半,甚至接近七成。模型训练时如果统一把图像缩放到 640×640,原本 20 像素的小车会被压成不到 5 像素的色块,几乎等于直接抹掉了目标。这也是很多人在普通数据集上跑得好好的模型,一到航拍任务上 mAP 掉 20 个点以上的直接原因。

小目标问题还直接影响标注质量。因为目标太小,人工标注时稍微手抖,边界框误差就会占目标本身尺寸的 20% 以上。这种噪声在训练阶段会被模型当作真实特征去学习,导致检测框飘忽不定。

1.3 密集、遮挡与运动模糊叠加

航拍数据的另一个典型特征是“密”。一个停车场的航拍画面里可能有几十辆车,一条道路上有成排的车辆首尾相接,一辆车被另一辆遮挡一部分。目标检测本质上是把一个个独立目标框出来,但密集排列时目标之间的边界非常模糊,相邻目标太近,NMS 阶段经常顺手把两个真实目标合并成一个。

再加上无人机本身在移动,快门时间稍微长一点,运动模糊就会出现在标注框内。边缘模糊会导致模型在训练时学到“半透明”的目标特征。数据层面必须通过增强和难例挖掘去抵消,不能光靠调一个更强的骨干网络。

从数据集总结的角度来看,选数据时一定不能只看总图像数,还要看小目标占比、密集程度、遮挡比例和运动模糊程度。后面选型时这些都是硬指标。

2. 主流无人机与航拍目标检测数据集盘点

公开的无人机、航拍目标检测数据集其实不算多,真正能打、能长期用的就那么几个。这里不是背书,而是结合使用场景,把它们放在一起做横向对比。

2.1 必看的公开数据集一览

下面这几个数据集是航拍目标检测领域绕不开的,各有侧重。

数据集场景标注方式规模参考主要类别适合任务
VisDrone无人机俯视拍摄的城市、道路、乡村、校园等水平边界框上万张图、数十万目标框,还有大量视频帧行人、自行车、汽车、卡车、巴士、三轮车等行人检测、车辆检测、密集场景
UAVDT无人机视角的车流与道路目标水平边界框数十个视频序列、帧数过万汽车、巴士、卡车车辆检测与跟踪
UA-DETRAC城市道路场景,多为高位摄像头视角水平边界框100 多个视频序列,百万级标注框车辆车辆检测、跨摄像机跟踪
DOTA 系列航拍和卫星的大视角图像旋转边界框上千张到数千张大图,百万级目标实例飞机、船舶、油罐、球场、游泳池等旋转目标检测、多类别大场景识别

VisDrone 是最多人上手的第一站,包含的图像场景丰富程度很高,有密集的十字路口、有树冠遮挡、有低空视角。它最大的价值在于类别覆盖了常见城市场景,而且标了行人和车辆同时出现的情况,能一次性把多目标检测的问题都暴露出来。

UAVDT 和 UA-DETRAC 更适合单纯做车辆检测和跟踪。UAVDT 的无人机视角比较明显,目标尺度跨度很大;UA-DETRAC 虽然很多镜头不完全是无人机视角,但拍摄高度、俯视角度非常接近高位监控,适合做交通场景的检测与多目标跟踪机制验证。

DOTA 系列是另一个极端,它用旋转框来标注,所以当你的下游任务需要给目标一个更精确的姿态,而不是随便一个外接矩形时,DOTA 是最合适的参考。但要注意,DOTA 的图像尺寸非常大,包含大量卫星视角,目标类别也偏基础设施,并不适合直接迁移到普通无人机航拍场景,需要裁剪后才能训练。

2.2 只看图像数是不够的

拿 VisDrone 来说,表面上是上万张图像,但如果拆成训练验证测试,再过滤掉大量只有极小小目标的图像,真正能让模型稳定学到的有效样本会明显缩水。无人机数据集里常有同一个目标在连续多帧中出现的情况,直接随机划分训练集和验证集,很容易造成数据泄漏,也就是几乎相同的目标同时出现在训练和验证里,结果验证精度虚高。

我建议拿到数据集后,先做目标级统计:每张图的平均目标数、小目标占比、类别分布、同一个视频序列的连续帧范围,然后再决定怎么划分。类别分布尤其值得注意,很多公开数据集里“汽车”类占了将近一半,而“三轮车”或“巴士”可能少得可怜。如果直接训练,模型会被大类别带着跑,少数类别很容易被忽略。

2.3 怎么根据任务倒推数据集

选数据集没有绝对的“最好”,只有“最匹配”。我的习惯是先列需求,再对照表格。

  • 如果任务是识别“行人和非机动车”这类拥挤城市目标,优先找无人机视角的 VisDrone;
  • 如果任务是纯车辆检测与跟踪,UAVDT 更贴近无人机实拍,UA-DETRAC 可以补充高视角车辆形态;
  • 如果任务要求输出旋转框,例如检测飞机、船舶、露天设施,旋转标注数据集是唯一选择;
  • 如果任务只要计数,不要求精确边框,那计数类航拍数据集也能用,同时还能减轻标注负担;
  • 如果任务面向非常特定的场景,比如电力巡检、农业地块、搜救目标,公开数据集通常覆盖不全,最好自建少量种子集,再配合生成和增强。

航拍领域这些年还出现了不少面向“高空动作识别”“伪装目标检测”“无人机视角灾难场景”的开源数据集,但多数规模偏小,更适合做评测或预训练,不适合单独作为量产模型的唯一数据来源。总结起来,公开数据集负责提供基础分布,自采数据负责补充场景细节,两者配合才是主流做法。

3. 拿到数据集之后:先体检,再做标注格式转换

数据集下载下来不代表能直接训练。第一步是“体检”,第二步是“格式统一”。这一步处理不好,后面的训练全都会反馈为莫名其妙的低精度。

3.1 给数据集做一次快速体检

我会先写一个短脚本统计三件事:图像尺寸分布、标注框宽高分布、类别数量。脚本不用很复杂,直接用 Python 遍历一遍标注文件就能完成。

统计之后重点关注两个点。第一,最大图像和最小图像分辨率差了多少。如果一张是 4000×3000,另一张是 1920×1080,直接全部 Resize 到固定尺寸会损失大量信息,最好的做法是统一用滑动窗口切块,而不是统一缩放。第二,标注框是否存在越界或者宽高为 0 的情况。越是人工标注的数据集,这种脏数据越常见,必须清洗。

体检过程中我最常发现的问题是“标注格式混乱”。同一个数据集里,有的标注文件是 XML,有的是 JSON,有的是自定义 TXT,甚至还有纯坐标没有类别的情况。千万别默认格式都是标准的。

3.2 把 VisDrone 标注转成 YOLO 训练格式

我以 VisDrone 为例说明一套通用转换流程。VisDrone 的原始标注是逗号分隔文本,每行代表一个目标,典型字段包括目标框左上角坐标、宽高、得分、类别、截断状态、遮挡状态。而 YOLO 格式要求每行是:类别编号、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。

转换脚本可以直接用 Python 完成,下面是可复现的核心逻辑。

from pathlib import Path from PIL import Image ANNO_DIR = Path("VisDrone2019-DET-train/annotations") IMG_DIR = Path("VisDrone2019-DET-train/images") OUT_DIR = Path("merge_labels") # 注意类别编号从 1 开始 CLASS_NAMES = [ "pedestrian", "person", "bicycle", "car", "van", "truck", "tricycle", "awning-tricycle", "bus", "motor", ] def convert_annotation(anno_path: Path): stem = anno_path.stem img_path = IMG_DIR / f"{stem}.jpg" if not img_path.exists(): img_path = IMG_DIR / f"{stem}.png" with Image.open(img_path) as img: W, H = img.size lines = [] with anno_path.open("r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue parts = line.split(",") if len(parts) < 6: continue xmin = float(parts[0]) ymin = float(parts[1]) bw = float(parts[2]) bh = float(parts[3]) cat_id = int(float(parts[5])) if cat_id <= 0 or cat_id > len(CLASS_NAMES): continue xmin = max(0.0, min(float(xmin), W - 1)) ymin = max(0.0, min(float(ymin), H - 1)) bw = max(1.0, min(float(bw), W - xmin)) bh = max(1.0, min(float(bh), H - ymin)) x_center = (xmin + bw / 2.0) / W y_center = (ymin + bh / 2.0) / H w_norm = bw / W h_norm = bh / H class_id = cat_id - 1 lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}") out_path = OUT_DIR / f"{stem}.txt" out_path.write_text("\n".join(lines), encoding="utf-8") OUT_DIR.mkdir(parents=True, exist_ok=True) for anno_path in ANNO_DIR.glob("*.txt"): convert_annotation(anno_path)

这段代码里有几个不起眼但很重要的细节。第一,坐标必须落在图像范围之内,否则训练框架自动裁剪时会出现“负面积”或“零宽高”的报错。第二,边界框宽高不能小于 1 个像素,否则标签在模型下采样过程中很容易被丢弃。第三,坐标归一化后保留 5 到 6 位小数就够,不要保留十几个小数位,只会白白增加文件体积。

如果是 Pascal VOC 格式的 XML,解析逻辑大同小异,只需要把 XML 里的bndbox子节点读出来,再套用同样的归一化公式。

3.3 COCO JSON 转 YOLO 格式的关键点

COCO 格式也很常见,特征是注释集中在单个 JSON 文件里。如果只做简单转换,可以用pycocotools读取标注,然后按image_id组合边界框。关键在于类别顺序。COCO 格式自带categories字段,每类有一个id,转换时必须先构建{COCO类别id: 目标类别索引}的映射表。

import json from pathlib import Path from collections import defaultdict with Path("annotations/instances_train.json").open("r", encoding="utf-8") as f: coco = json.load(f) images = {img["id"]: img for img in coco["images"]} cats = {cat["id"]: idx for idx, cat in enumerate(coco["categories"])} anns_by_image = defaultdict(list) for ann in coco["annotations"]: anns_by_image[ann["image_id"]].append(ann) for image_id, image in images.items(): lines = [] W = image["width"] H = image["height"] for ann in anns_by_image[image_id]: if ann.get("iscrowd"): continue x, y, bw, bh = ann["bbox"] x_center = (x + bw / 2) / W y_center = (y + bh / 2) / H w_norm = bw / W h_norm = bh / H class_id = cats[ann["category_id"]] lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}") out = Path("labels") / f"{image['file_name'].rsplit('.', 1)[0]}.txt" out.write_text("\n".join(lines), encoding="utf-8")

COCO 转换最容易被坑的是bbox字段的坐标原点。COCO 的bbox是左上角坐标加宽高,不是中心点。很多人图省事直接把x当成中心点,结果所有框整体偏移半个框,训练出来精度低得离谱还找不到原因。

3.4 大图切块:航拍数据的标准操作

对高分辨率航拍图,我强烈建议做图像切块,而不是直接整体缩放。切块的好处有两个:一是小目标在局部块里不会继续缩小,保留了可学习的信息量;二是把一个大图拆成若干个可放进 GPU 的小图,内存压力更可控。

切块时要注意滑窗的步长。比如切 1024×1024 的块,滑窗步长设 512 到 768,相邻块之间会有重叠,目标不会因为刚好落在切缝上而丢失。推理阶段同样要切片,再把输出的框映射回原图坐标。如果训练时用 512 的步长、推理时也用 512 的步长,效果最稳定,不要训练和推理一套参数各干各的。

4. 数据增强、模型选型与训练评估经验

数据预处理完之后,真正容易拉开差距的是训练策略。这里只讲我踩过坑后认为最关键的几件事。

4.1 数据增强:不要无脑堆 Mosaic

航拍场景里,Mosaic 增强是一把双刃剑。它把四张图拼在一起再缩放,确实提高了背景多样性,但也会让已经很小的目标变得更小,甚至小到只剩一个点。更麻烦的是,四张图的边界框在拼接处会交错,容易产生错误的正样本。

我现在的做法是把 Mosaic 概率调低,比如只在训练前半段使用,后半段关闭,同时把拼接时的最小缩放比例限制在 0.8 以上,避免目标被缩太小。真正更有效的增强是随机旋转、水平垂直翻转、随机亮度对比度扰动,以及轻微的 HSV 色彩抖动。无人机航拍画面经常有阴影、反光和季节色差,色彩扰动可以模拟这些情况。

还有一个容易被忽略的增强:随机遮挡模拟。航拍目标经常被树冠、线缆或建筑遮挡,训练时随机把某一块区域涂黑或模糊,可以强迫模型学习目标的部分特征,提升实际场景的泛化能力。

4.2 模型选型与输入分辨率

无人机航拍检测不需要盲目追求大模型。实际部署在无人机边缘设备上时,算力、功耗、散热都非常有限,YOLOv8n、YOLOv8s 这类轻量模型往往是首选。如果想在精度上更进一步,可以试试 RTMDet 或者基于 DETR 的目标检测模型,后者在密集重叠场景里对目标之间的建模能力更强,但推理速度通常更慢,显存要求也高。

输入分辨率比模型规模影响更大。我测试过一个场景:同样一个轻量模型,640 输入时 mAP50 只有 60 左右,换成 1280 输入后直接提升到 72 以上。航拍小目标占主导,输入图像太小等于把小目标的信息量抹掉了。如果显存足够,优先训练 1280 或 1024 分辨率,而不是换更重的骨干网络。

训练时建议开启多尺度训练,随机让输入在 640 到 1280 之间浮动,这样模型对目标尺度的变化会更鲁棒。不过多尺度范围不要和推理分辨率差太多,否则训练学的和推理用的不是同一个分布。

4.3 评估指标要分尺度看

只看整体 mAP 会掩盖很多问题。航拍数据集里小目标占比高,整体 mAP 往往被大目标拉上去,小目标表现很差也可能看不出来。

我养成的习惯是把指标拆开看:mAP50、mAP50-95、AP_s、AP_m、AP_l,还有每个类别的单独 AP。如果AP_s明显低于AP_m,说明模型对小目标根本没有建模能力;如果某个类别整体 AP 都很低,就要先检查这个类别的样本量是不是太少。

验证集划分同样重要。航拍数据和普通图像不一样,同一个视频序列里相邻帧高度相似,直接随机划分会导致验证集过拟合到训练集。正确做法是按视频序列分组划分,保证一个视频的所有帧只出现在训练集或只出现在验证集里。这一步是很多人验证精度高、实际一测就露馅的根源。

5. 航拍目标检测实战问题与排查清单

把这几年的实战问题整理成一份排查清单,遇到类似情况可以直接对号入座。

5.1 小目标 AP 很低,怎么排查

先检查输入分辨率。如果训练输入小于 1024,优先提升分辨率。再检查增强策略,是否使用了过重的 Mosaic,导致目标被过度缩小。接着看标注框最小尺寸分布,如果标注框普遍小于 8 像素,人工噪声占比太高,应该把小目标定义为单独难度级别,而不是强行让模型从噪声中学。

最后考虑是否采用了切片推理。训练可以适当增大输入,推理阶段建议用滑窗推理,让每个目标至少在一个滑窗中占据足够大的比例。滑窗重叠率建议设在 25% 到 50% 之间,太低容易漏检,太高会增大重复框数量。

5.2 验证指标虚高,实际部署效果差

这个问题的头号原因是数据划分泄漏。同一目标在相邻几帧重复出现,随机划分时验证集和训练集里出现同一个车、同一个人,模型等于提前背过答案。解决办法是按序列划分。

另一个原因是“背景泄漏”。如果训练图和验证图来自同一个网格切块,相邻切块之间重叠区域太多,验证精度也会偏高。切块后的子图也要按原图分组拆分,不要把所有子图直接混在一起随机分。

5.3 训练损失正常但某些类别始终检测不到

大概率是类别不平衡和标注错误混合导致的。先看类别样本数,如果某类只有几百个框,而其他类有几十万个框,模型基本只会学大类。

最简单的处理方式是做类别下采样或重加权损失。但航拍数据里更实用的做法是“复制增强”:把稀有类别的图像复制若干份,叠加在正常数据流里,让模型在训练时看到它的频率增加。还可以把这几个类别单独作为难例挖掘对象,在训练过程中持续追加标注。

另外,我见过一次非常坑的现象:某个类别的标注框颜色转换脚本写错了,导致大量目标被归到别的类别里。这类问题不会让训练崩溃,但会让最终 AP 在某个类别上始终低得离谱。所以排查时要随机抽几十条标签可视化,而不是只看统计数字。

5.4 整理数据集的小习惯

最后分享一个我一直在坚持的整理习惯。所有数据集统一命名格式为日期_场景_目标类型_版本,不把“最最终版”这种命名带到工作里。标注文件统一放在annotations目录,训练图片放在images目录,转换后的标签放在labels目录,版本变更时整个目录一起打包,而不是只替换单个文件。

标注和脚本放在同一级目录里可以达到一个回归可控的效果:任何时候重新跑一遍脚本,都能从原始标注生成最新格式的数据,不会出现“上次改了一半找不到源数据”的窘境。

从我的实际体验来看,无人机、航拍目标检测的数据问题,往往比模型问题更隐蔽也更致命。一个精心设计的检测网络,碰到脏数据、错划分、小目标被压缩这三座大山,照样会翻车。先把数据总结清楚、转换干净、划分严谨,后面模型选型也好、优化也好,才有真正的意义。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 7:03:59

【单片机毕设案例分享】基于4G的老人跌倒检测与生理参数远程监护系统设计 基于物联网的老人跌倒报警4G定位与健康管理系统设计(032604)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于单片机&#xff0c;STM32单片机&#xff0c;51单片机&#xff0c;J…

作者头像 李华
网站建设 2026/10/14 7:03:48

Structured Streaming实战:从Kafka实时数据处理到底层机制

说实话&#xff0c;我第一次用Structured Streaming的时候&#xff0c;也以为它只是把老版Spark Streaming改了个名字&#xff0c;结果真上手之后才发现&#xff0c;这套API背后的设计思路完全换了套玩法。做实时数据处理这几年&#xff0c;从最早的DStream到现在的Structured …

作者头像 李华
网站建设 2026/10/14 7:03:35

前缀和算法详解:从一维到二维,掌握区间求和与差分优化

1. 从一个笔误开始&#xff1a;前缀和到底解决什么问题拿到这个标题的时候我愣了一下&#xff0c;“二位前缀和”明显是“二维前缀和”的笔误。但这个笔误其实挺常见&#xff0c;搜索平台上每天都有不少人带着这个错别字来查资料。既然题目给的是“一维和二位前缀和算法”&…

作者头像 李华
网站建设 2026/10/14 7:03:18

PS5新机配置全攻略:从初始化到常见问题排查

新入手PS5的朋友大概率都会经历这么一段折腾期——系统菜单翻来覆去研究、存储空间焦虑、画面参数拿不准、手柄连不上电脑、换了电视机以后显示效果忽好忽坏。我前后给三台不同型号的PS5做过完整的环境配置&#xff0c;也帮身边好几个朋友处理过类似问题&#xff0c;总结下来就…

作者头像 李华
网站建设 2026/10/14 7:03:12

1TB免费S3对象存储实战:从注册到rclone挂载与备份

你刷到过“1TB 免费 S3 对象存储”这类标题吗&#xff1f;对我来说&#xff0c;这个词组自带吸引力&#xff0c;也自带警报&#xff1a;真的免费&#xff1f;会不会只有三天试用期&#xff1f;流量是不是贵到离谱&#xff1f;前阵子我为了把一台小服务器上的备份挪走&#xff0…

作者头像 李华
网站建设 2026/10/14 7:02:54

OpenShell开源Web终端:部署实战、踩坑记录与团队运维集成指南

在浏览器里敲命令这事&#xff0c;以前听着像个玩笑&#xff0c;现在已经被不少团队用成了日常。我花了两周时间把一套叫OpenShell的开源Web终端方案完整跑通&#xff0c;从部署、踩坑到改造成自己顺手的样子&#xff0c;过程中发现网上关于它的资料还是太零散&#xff0c;所以…

作者头像 李华