
简介面向空中无人机检测任务的专业数据集收录7000余张标注完成的旋翼无人机UAV图片类别统一标注为drone可直接用于多种目标检测算法的训练与验证。标签格式同时提供txt与xml两种适配YOLO系列和VOC格式等主流检测框架免去用户自行转换标注格式的额外步骤。整个RAR压缩包共22675个文件由7559个txt标注文件、7558个xml标注文件以及7558张jpg原始图片构成整体体积约876.78MB图片与两种标注一一对应便于直接进行数据划分、增广与模型训练。目前已有1111人学习下载在同类无人机检测数据集中具备一定参考热度。数据覆盖不同场景下的多种旋翼无人机类型适用于空中无人机检测、低空目标识别等方向下载后可直接用于YOLO、SSD、Faster R-CNN等常见算法的训练、精度对比与消融实验省去自行采集图像和人工标注的时间成本也适合研究人员快速验证检测模型在真实无人机图像上的效果。1. 空中无人机的检测数据集先想清楚目标是谁否则数据集白做“空中无人机的检测数据集”这句话业内往往有两种理解一种是“以空中无人机为检测目标”的数据集用在反无人机、空域管控、无人机自主避障上另一种是“用无人机做平台去检测地面目标”的数据集比如航拍工地、车辆、农作物。两种方向的数据采集方式、标注规范和训练策略差别极大。我见过不少新人上来就搜“无人机数据集”结果下载了一个航拍高空视角的数据集拿来训练自己的反无人机系统迁移效果一塌糊涂。这篇笔记我按“以无人机为检测目标”这条更难、更缺公开资源的主线来讲因为这类数据集最需要自己动手做也最容易在“小目标天空背景”上翻车。适合正在做低空安防、电力巡线、无人机避障的工程师也适合想用 YOLO 跑通一个无人机检测 demo 的研究者。结论先说不要指望一次拿到完美数据集仿真合成和真实采集结合先让流程跑通再去一点点补数据。2. 两类数据源怎么选仿真合成数据与真实航拍数据的分工2.1 仿真数据为什么是起步首选真实空中无人机的航拍图像难拿。无人机目标小、速度快、背景以天空和地景为主想用无人机飞手去拍另一架无人机不仅需要空域条件还要考虑安全风险和相机跟拍难度。常见做法是用游戏引擎或者物理渲染器生成合成数据。比如用 Unreal Engine 配 AirSim或者用 Blender 渲染带 alpha 通道的无人机模型再贴到随机背景上。这种做法的好处是标注是自动生成的相机位置、无人机姿态、光照角度全部可控一个晚上就能生成几千张不同距离、不同遮挡程度的数据。spacedrone 这类开源无人机项目也提供了仿真环境参考思路基本都是先在虚拟环境里把算法验证清楚再上真机。仿真数据的关键参数有三个渲染分辨率、相机视场角、目标在图像中的像素尺寸。分辨率建议至少 1920x1080视场角控制在 3060 度之间这样远处无人机不会被压得过小。目标像素尺寸是后面所有工作的核心我一般会统计一下确保训练集里大目标大于 64x64 像素、中目标32x64、小目标小于 32x32都有一定比例。如果全是小目标模型学不到细节如果全是大目标实飞时一上远距离就抓瞎。为什么先仿真而不是先采真实数据因为模型迭代快。你改一个标注规范、换一个检测器仿真数据可以立刻重新生成标注永远是对的。真实数据采集一次的成本高而且标注无人机小目标非常痛苦尤其是只有十几个像素的目标人眼都看不清是不是无人机。所以起步阶段用仿真数据把整个训练—验证流程跑通是性价比最高的路径。2.2 真实数据采集相机、焦距、距离分布的关键真实数据不可替代因为仿真背景再怎么像也没有真实天空的云层变化、光照反射和运动模糊。真正要落地时至少要采集三个维度距离、角度、天气。相机方面常见做法是用 4K 安防相机或微单接长焦镜头。为什么小目标检测对像素极其敏感同样一架无人机在 50 米外1080p 相机下可能只有 10 个像素宽4K 下能有 20 个像素检测难度完全不一样。焦距建议不低于 50mm 等效焦距不然广角画面里无人机太小标注都标不准。采集时把距离分成几档近距515 米、中距1550 米、远距50150 米每档都拍。角度上不要只拍水平视角俯仰方向也要有因为实际场景里无人机可能在高空、低空、侧飞出现。采集环境要覆盖晴天、阴天、逆光、顺光、清晨、傍晚。如果你做的是反无人机系统还得把“地面建筑、树木、电线杆”这些背景拍进去否则模型只见过天空一遇到复杂地景就会把树枝的晃动也当成候选。我一般会在采集时记录一组元数据拍摄时间、天气、距离、相机焦距、目标大致像素大小方便训练后分析是哪一类数据在拉低指标。2.3 公开数据集摸底比对几个候选值不值得用数据集方向代表资源内容倾向是否适合无人机检测训练理由遥感船只HRSC2016高空遥感图像中的舰船目标不适合直接训练是下视视角目标形态、背景与空中无人机差异太大但小目标标注思路可借鉴航拍检测DOTA 系列航拍遥感多类别目标部分适合预训练场景是高空下视没有天空背景无人机作为目标几乎没有可用来预训练通用特征反无人机专用Drone-vs-Bird、Anti-UAV 等公开反无人机数据集实拍含无人机、鸟类等适合做迁移学习起点数据量有限但贴近真实并且很多包含连续帧可以做视频检测鸟类目标检测各类鸟类检测数据集天空背景中的鸟适合做辅助负样本外观与无人机相似用来加负样本能显著降低误检率这张表是我的选择逻辑不是完整的资源清单。HRSC2016 是我经常被问到“能不能直接拿来训练无人机检测”的数据集结论是不能它是遥感舰船检测的经典数据集视角完全不对。但它的水平框标注规范值得抄特别是对小目标的包围框如何处理做了很多约定。DOTA 则可以拿去做骨干网预训练让模型先学会航拍视角下的边缘、纹理特征再去学无人机目标。反无人机专用数据集质量参差不齐下载前一定要看它给出的图片分辨率和目标最小像素如果全是近距离大目标你用在远距离场景上会死得很惨。这里顺便说一个会被忽略的细节公开数据集下载后第一件事不是看数量而是跑一个统计脚本算一下每张图的目标个数、目标宽高分布、目标与图像边缘的距离。我之前用过一个号称包含几万张无人机图像的数据集统计之后发现 90% 的目标都大于 96x96 像素训练出来的模型在 30 米外几乎全漏。所以数据集的“可用性”必须基于你的目标尺寸分布来判断而不是基于数量。3. 从零构建无人机检测数据集标注规范与最小实现3.1 类别定义把干扰物标成独立类别偷懒我最常看到的问题是把所有空中飞行物都标成“drone”结果模型把鸟、风筝、塑料袋全判成无人机。这不是模型笨而是你的标注把相似外观的类别混在一起了。正确的类别定义至少要有四类无人机、鸟、风筝、其他飞行物。其中“鸟”尤其重要因为鸟的轮廓和无人机在远距离时几乎一样如果不把鸟作为负样本单独标出来检测器只能靠纹理去硬分而小目标根本没有纹理可看。如果你做的是特定场景比如机场反无人机还要考虑镜头里出现的飞机、直升机。我一般会加一个“airplane”类别哪怕样本量少也比最后把飞机误检成无人机好。另外不要用“背景”作为一个标注类别背景是通过负样本天然存在的不是靠包围框标出来的。负样本图完全没有无人机的图需要单独放在一个文件夹里数量是正样本图的三分之一到一半用来压住整体误检率。标注框的约定也要统一。无人机很小的时候包围框是包含旋翼还是只框机身我建议包含整个无人机外形的最小外接水平框包括旋翼因为旋翼是运动模糊下最稳定的特征。但要注意如果旋翼转起来在图像里是半透明的要按人眼看到的轮廓框不要脑补一个更小的框。标注工具用 LabelImg 或者 X-anylabeling 都行关键是团队内必须有一份命名规范图片统一按date_sequence_camera_weather.jpg命名标注 XML 一一对应避免后面清洗时不知道这张图是什么条件下拍的。3.2 标注格式转换把 XML 转成 YOLO 的 Txt现在 YOLO 系列用的训练格式不是 XML而是每张图对应一个 txt 文件每行是class_id cx cy w h四个坐标值都是相对于图像宽高的 01 归一化值。下面这个脚本是我常用的转换逻辑用 Python 标准库就能跑不需要额外装深度学习框架。import xml.etree.ElementTree as ET import os def voc_xml_to_yolo(xml_file, out_txt, class_names): tree ET.parse(xml_file) root tree.getroot() width float(root.find(size/width).text) height float(root.find(size/height).text) with open(out_txt, w) as f: for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue category_id class_names.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 求中心点坐标和宽高并归一化到 0~1 cx (xmin xmax) / 2.0 / width cy (ymin ymax) / 2.0 / height w (xmax - xmin) / width h (ymax - ymin) / height # 保险处理越界坐标截断避免出现中心点在图像外 cx max(0.0, min(1.0, cx)) cy max(0.0, min(1.0, cy)) w max(0.0, min(1.0, w)) h max(0.0, min(1.0, h)) f.write(f{category_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n) class_names [drone, bird, kite, airplane] # 使用示例遍历所有 xml 文件同名输出 txt xml_files [f for f in os.listdir(.) if f.endswith(.xml)] for xml_file in xml_files: voc_xml_to_yolo(xml_file, xml_file.replace(.xml, .txt), class_names)这段代码的核心在归一化和越界截断。YOLO 训练时要求目标中心点必须落在图像内否则会出现 loss 异常。我见过有人直接把标注框的负坐标保留结果训练到一半 loss 突然变大查了半天才发现是数据里有一个目标的xmin是负数转换脚本把它原样写进去了。所以转换阶段宁可多做一步截断也不要相信标注工具不会产出越界框。转换后还要做一个验证读取 txt把所有框画回原图人眼抽查 50100 张。常见做法是写一个可视化脚本把类别名和框画在图上重点看小目标框是否和实际轮廓对齐。这一步能发现两类问题一是坐标归一化时由于图像宽高读取错误导致所有框整体偏移二是漏标很多难以辨认的小目标没被框出来导致模型学到“忽略小目标”。3.3 数据增强小目标检测的专用策略普通的数据增强随即翻转、色彩抖动、Mosaic对无人机检测来说远远不够。Mosaic 虽然能提升整体鲁棒性但它会把目标缩放得很小小目标在拼接图上可能只有几个像素训练时梯度贡献接近于零。所以我的做法是双路径先用 Mosaic 做全局增强再单独对“小目标样本”做一个裁剪复制增强。下面这是用 albumentations 库对一张图做自动化增强的例子。重点不是增强本身而是如何保留小目标。import albumentations as A import cv2 import numpy as np # 定义小目标复制增强从图中随机裁剪一块包含小型目标的区域粘贴到另一位置 def copy_paste_small_targets(image, bboxes, max_copies2): img image.copy() new_boxes bboxes.copy() small_boxes [b for b in bboxes if (b[2] - b[0]) 64 and (b[3] - b[1]) 64] np.random.shuffle(small_boxes) for box in small_boxes[:max_copies]: x1, y1, x2, y2 [int(v) for v in box[:4]] patch img[y1:y2, x1:x2] if patch.size 0: continue # 新位置偏移限制在图像边缘内 dx np.random.randint(32, max(32, int(img.shape[1] - x2) - 10)) dy np.random.randint(32, max(32, int(img.shape[0] - y2) - 10)) nx1, ny1 x1 dx, y1 dy img[ny1:ny2, nx1:nx2] cv2.resize(patch, (x2 - x1, y2 - y1)) new_boxes.append([nx1, ny1, nx1 (x2 - x1), ny1 (y2 - y1), *box[4:]]) return img, new_boxes # 调用方式在训练流水线里 image cv2.imread(img.jpg) # bboxes: [x1, y1, x2, y2, class_id]需要先做归一化或保持像素坐标 aug A.Compose([ A.RandomBrightnessContrast(p0.5), A.HueSaturationValue(p0.3), ], bbox_paramsA.BboxParams(formatpascal_voc, label_fields[labels]))这段代码的自学点在于我只对像素尺寸小于 64x64 的目标做复制因为小目标本身样本量少复制后在更多位置出现能告诉模型“小目标可能出现在画面任何位置”。大目标复制没有意义因为大目标占用空间大复制容易遮挡原图而且大目标数量通常不会稀缺。如果你用的是 YOLOv8 的官方训练脚本也可以在augment.py里挂自定义增强但为了快速验证常见做法是用 albumentations 先生成增强后的图片再做一个增强后的离线数据集。缺点是需要多几倍的磁盘空间但排查问题方便模型训练时不用背锅到增强代码上。还有一个热门的增强策略是“拉普拉斯过采样”对小目标类别按复制概率过采样同时在大目标样本里随机裁剪局部放大让模型在同一张图里看到不同尺度的目标。我自己试下来它对提升远距离召回率的效果比单纯翻图片数量明显。4. 训练与验收集用 YOLOv8 跑通一个最小可用的检测器4.1 环境准备与训练命令到了训练这步数据集目录结构要固定下来。常见做法是这样组织dataset/ images/ train/ val/ labels/ train/ val/ dataset.yaml其中 dataset.yaml 是 YOLO 系列的配置文件指定类别名和图片路径。下面是一个最小示例# dataset.yaml path: ./dataset train: images/train val: images/val names: 0: drone 1: bird 2: kite 3: airplane接下来用 ultralytics 包训练。命令行一条就能跑通yolo detect train datadataset.yaml modelyolov8n.pt \ epochs150 imgsz640 batch16 patience20 \ project./runs_yolo namedrone_test device0这条命令里的关键参数为什么这么设我解释一下。imgsz640是输入分辨率640 是速度和精度的折中但对小目标不够后面我会讲怎么调。batch16取决于你的显存如果显卡是 12G 左右16 是安全的显存不够就降到 8同时把workers设小一点不然数据加载会拖累 GPU 利用率。patience20是早停轮数如果验证集 mAP 连续 20 个 epoch 不涨就停止防止炼丹浪费时间。训练开始后不要只盯着 loss 曲线。YOLOv8 在终端会打印每个 epoch 的box_loss、cls_loss、dfl_loss和验证集mAP50。我一般会立即打开runs_yolo/drone_test/下的results.png看趋势。如果 loss 在前 20 个 epoch 就快速收敛到接近 0但 mAP 还在低位说明模型过拟合到训练集中的某个固化模式通常是因为数据多样性不够或者标注噪声太大。训练完成后最好的模型是best.pt不是最后的last.pt。换用best.pt去测试然后进入验证阶段。4.2 参数调优分辨率与 Anchor 的取舍小目标是无人机检测永恒的痛点。如果你的验证集上小目标 AP 很低第一个要调的就是imgsz。把 640 改成 1280模型输入图像分辨率翻倍目标像素随之变大特征提取器能看到的细节更多。代价是显存占用和推理速度显著上升在 GPU 上跑还行Jetson 这类边缘设备基本吃不消。分辨率之外YOLOv8 的 Anchor 是自动学习的不需要像老版 YOLO 那样手动设。但自动学习不代表你不用检查。我建议训练后打印一下自动聚类得到的 Anchor 尺寸看是不是覆盖了你数据集中目标的典型宽高比。无人机在图像里通常是横着飞或者斜飞宽高比接近 1:1 或 2:1如果 Anchor 全是 1:1 的方形斜飞的大长宽比目标就容易被漏检。不过自动学习一般能照顾到不放心就用yolo detect train ... cfgdefault.yaml看默认配置然后根据数据分布微调。还有两个容易被忽略的参数degrees15可以给目标加上小角度旋转增强因为无人机在画面里不一定是正位的scale0.5控制随机缩放幅度这个值不要太大否则小目标被缩得更小。我在配置里通常加这样几行# augment 部分写在 yaml 里会被训练脚本自动合并 degrees: 15.0 scale: 0.3 flipud: 0.3flipud是垂直翻转天空背景里目标和太阳的相对位置会影响阴影垂直翻转能增加一点多样性。但如果你的数据集里无人机总是带地面环境垂直翻转会把地面翻到上面去形成不真实的场景这种情况就不要开flipud。4.3 模型评估指标mAP 之外还要看什么训练结束大家习惯性报一个 mAP0.5比如 0.9就觉得效果很好。实际做无人机检测mAP 高并不代表可用。无人机是小目标通常使用 COCO 定义的 AP_S像素面积小于 32x32 的目标来单独评估。如果全数据集 mAP 0.9AP_S 只有 0.2那这个模型在远距离场景就是废的。用 YOLOv8 官方的 val 命令可以直接得到按类别的 APyolo detect val datadataset.yaml modelruns_yolo/drone_test/weights/best.pt \ imgsz640 splitval输出里会包含每个类别的Class AP50和AP50-95以及按面积划分的Small、Medium、LargeAP。我的一线经验是无人机检测至少要保证 AP50 大于 0.8同时 AP_S 大于 0.5才有实际应用价值。如果 AP_S 低于 0.3说明当前数据里的小目标没有提供足够的学习信号要么加样本要么提高imgsz要么换更强的模型如yolov8s或yolov8m。这里还要提一个验证集划分的坑。很多数据集整理者按文件顺序随机划分但无人机检测场景下同一段连续拍摄的视频分成训练和验证时很容易泄漏视频相邻帧相似度极高如果训练集里第 100 帧验证集里第 101 帧模型相当于见过答案验证集指标虚高。正确做法是按视频片段划分也就是同一个视频的所有帧必须全部进训练集或全部进验证集不能打散。数据集目录里如果每个视频一个子文件夹划分脚本要按文件夹维度进行。5. 空中无人机数据集落地避坑5条血泪踩坑记录5.1 现象训练损失很低实飞时却什么都检测不到发生情况我很早之前用合成数据训练训练集 loss 降到 0.02验证集 mAP 达到 0.95觉得自己已经搞定。结果把模型部署到相机上对着窗外一架 100 米外的小型多旋翼无人机拍画面里的目标没有任何检测框。原因合成数据的背景和真实天空差异太大而且我在渲染时把无人机贴在了纯色蓝天上模型学到的是“在蓝色大面积区域寻找深色团块”一遇到白色云层背景就失去判断力。解决用真实天空照片替换渲染背景在合成数据里加入亮度随机扰动、高斯模糊和压缩伪影模拟不同相机成像差异。更彻底的做法是收集一段真实航拍视频用合成数据做预训练再用真实数据微调。经过这轮调整实飞检测才恢复到训练时的水平。所以合成数据最忌讳“太干净”要人为加噪声。5.2 现象小目标漏检严重召回率惨不忍睹有段时间我在验证集上专注查看小目标检测效果发现所有远距离帧几乎全部漏检。原因其实在数据增强因为训练时开了默认的 Mosaic增强后小目标被进一步缩小很多目标小于 8x8 像素卷积核根本提取不到有效特征模型学到了“忽略极小目标”的捷径。解决关闭 Mosaic 或者把小目标样本单独不上copy_paste增强并且把imgsz从 640 提到 1280。有了这两步AP_S 从 0.25 提升到 0.52漏检问题明显好转。同时要把那些过小的目标从训练集中筛掉小于 6x6 像素的框人类都难以确认对训练反而有害。5.3 现象把鸟识别成无人机误检率居高不下无论怎么调阈值鸟类总能被框成无人机。原因在于标注时我只标了无人机没有给鸟单独的类。模型不知道鸟的存在只能把与无人机外形相似的鸟强行归入无人机。解决增加一个 bird 类从公开鸟类数据集中裁剪出天空背景下的鸟图片复制粘贴到训练集中。操作之后无人机误检率降了一半。在这里你会发现仅仅靠负样本的不完整也会导致模型“看到相似物体就报警”。所以任何无人机检测数据集都应该包含干扰物类别而不是只做“无人机 vs 背景”二分类。5.4 现象仿真数据训练的模型在真实场景泛化差一次实际部署中我用 90% 仿真数据、10% 真实数据训练结果在真实场景的验证集上 AP50 只有 0.34。原因仿真数据中无人机模型的旋翼是静态建模而真实无人机在飞行时旋翼高速旋转在图像上形成动态模糊和半透明效果静态渲染和真实外观差别巨大。解决在仿真渲染时对旋翼加旋转模糊或者直接用真实无人机贴图替换 3D 模型。另外我还在合成阶段加了运动模糊模拟相机快门时间内的位移真实感有很大提升。泛化差距的核心不是模型而是仿真数据没有覆盖真实低层次特征。5.5 现象数据不平衡模型只认近处大目标统计训练集后我发现无人机目标小于 32x32 的数量只占总目标数的 8%大于 96x96 的占 60%。训练出的模型在近处表现很好一到远距离就直接无视因为大目标占主导了。解决对距离分层采样把远、中、近距离样本控制成大致 3:4:3 的比例并对小目标类别进行过采样。同时用前面提到的裁剪复制增强多造一些中距离样本。数据不平衡属于最常见也最隐蔽的问题因为整体 mAP 很好看直到你要用 AP_S 评估才暴露。6. 进阶技巧给检测器加一个“大小目标分离”的验证集来验收最后这一节我给一个我每次做完无人机检测模型必做的验收方法按目标真实像素尺寸把验证集拆成三个桶分别计算 AP而不是只给一个总体 mAP。这个技巧能直接回答“我的模型在 50 米外到底能不能用”也是容易被新手忽略的模型边界判定法。具体做法是在划分验证集时对每张图的目标框取面积按面积的中位数分成小、中、大三档目标短边小于 32 像素、3296 像素、大于 96 像素。然后用同一个模型分别在这三个子验证集上跑val命令得到一个分桶的 AP 表。如果小桶输出很低剩下的工作方向很明确提高输入分辨率、收集远距离样本、增强小目标。如果大桶输出很低那问题更多出在模型容量或类别混淆上和距离无关。我平时会在代码里这么生成分桶验证集import os, cv2, numpy as np def split_val_by_size(label_dir, targetsmall): # 按目标短边尺寸分桶返回对应的图片列表 buckets {small: [], medium: [], large: []} for lbl in os.listdir(label_dir): boxes [] with open(os.path.join(label_dir, lbl)) as f: for line in f: cx, cy, w, h map(float, line.split()[1:]) short_side min(w, h) # 归一化后的短边比例 boxes.append(short_side) # 你的原图宽度假设是1920计算像素短边 if boxes: max_short max(boxes) * 1920 if max_short 32: buckets[small].append(lbl) elif max_short 96: buckets[medium].append(lbl) else: buckets[large].append(lbl) return buckets这个脚本里我用“每个文件最大目标的短边”作为该图的桶归属。如果同一张图里有大有小我建议按最大目标归桶因为图级验证集不能一图多桶。然后按桶生成三个 yaml 文件分别用yolo detect val dataval_small.yaml modelbest.pt跑出各自 AP。这样一来你对外报告效果时可以说“全量 mAP 0.8850 米外小目标 AP 0.55”这个说法对落地才有参考价值。我习惯在项目验收报告里同时放三张 P-R 曲线和一组分桶指标避免甲方只拿总 mAP 说事。每次这么做都能提前暴露一批实飞才能发现的问题。老实说无人机检测数据集最后拼的不是“有多少张”而是“小目标样本有多全、干扰类别标得有多准、验证集拆得有多细”。这三个点都做到模型就已经赢了一大半。希望这个分桶验收法能帮你避免我当年翻过的那些车。本文还有配套的精品资源点击获取