简介:本资源是一套面向计算机视觉与深度学习初学者及算法工程师的旋翼无人机目标检测专用数据集,聚焦YOLO、TensorFlow、PyTorch等主流框架的模型训练与验证需求。共包含1359张高质量PNG/JPG图像,全部标注完整,配套1097个PASCAL VOC格式XML文件(适配TensorFlow/PyTorch)和903个YOLO格式TXT文件(适配Darknet),总计2000个文件,压缩包大小为713.26MB,结构清晰、开箱即用。已有428人学习下载,说明其在无人机识别、农业巡检、城市安防等实际场景中具备较强实践参考价值。用户可直接加载标签进行数据增强、模型训练与mAP评估,无需额外格式转换;所有样本均严格限定为多角度、多光照、多背景下的旋翼无人机,排除固定翼干扰,显著提升模型泛化能力与检测精度。 很多做视觉算法的人,手头最缺的不是模型结构,反而是一套趁手的数据集。尤其是无人机视角的数据,和普通地面拍到的画面完全是两个世界——目标小、角度刁、光照复杂,背景还经常是纹理重复的地面或水面。我前阵子做巡检项目的时候,花了大力气整理了一套带标签的无人机数据集,一共1359张照片,PNG和JPG两种格式都有,标签文件也是齐的。这篇文章就是把这套数据集从整理、清洗、标注到格式处理的全过程捋一遍,里面有不少是实打实踩过的坑,希望能给同样在搞无人机视觉的朋友省点时间。
这套数据集主要面向目标检测和语义分割任务,适合用来做车辆识别、建筑物提取、植被覆盖分析这类场景。我自己用它跑过YOLOv8和DeepLabV3,效果还不错。如果你是刚入门无人机视觉方向的研究生,或者是做智慧城市、农业植保相关产品的工程师,这套数据的整理思路和配套工具链可以直接照搬。
1. 数据集整体设计与定位
拿到一批无人机原始航拍照片后,第一件事不是急着标注,而是想清楚这套数据最终要给什么任务用。不同的任务对数据的要求差别非常大,盲目照搬通用目标检测数据集的做法,往往会走弯路。
1.1 核心需求解析:1359张照片能做什么
1359张这个规模,放在深度学习数据集里不算大,但也没到完全不够用的程度。COCO的训练集有12万张,VOC有1.6万张,看起来1359张确实寒酸,但这里面有个关键区别——无人机航拍图的单张信息密度远高于普通地面照片。一张4000x3000的航拍图,里面可能包含上百个独立目标,车辆、屋顶、树木、道路全都拍进去了。
所以处理无人机数据集时,我从来不建议直接整图丢给模型训练。正确做法是把大图切成patch,比如1024x1024或者640x640的小块,这样一来,1359张大图轻松能扩展出一万多张小图,训练数据量一下子就充实了。这也是我为什么在整理的时候特别注意保留原图大尺寸的原因,分辨率不够的素材在切patch以后根本没法用。
1.2 标签体系是怎么设计的
这套数据的标签体系我花了不少心思。最开始定的方案是模仿COCO的80类,但后来发现完全不实用。无人机俯视视角下,很多COCO的类别根本看不清,比如人这种目标在50米高度往下拍就是几个像素点,标注师的准头再高也难免标偏。
我最终采用的是一套四类标签方案:车辆、建筑、植被、道路。这个分类的考量是:
- 这几个类别是无人机巡检、城市管理、农业监测中最常遇到的,实用性最高
- 四个类别在俯视视角下有明确的视觉特征,标注时不容易产生歧义
- 类别少意味着每个类别的样本量更充足,小数据集的训练效果更有保障
标签格式我统一转成了YOLO的txt格式,也就是每行记录类别id和归一化后的中心点坐标、宽高。这套格式不管配合YOLOv5、YOLOv8还是DETR都能直接用,转成COCO的json格式也就是一段脚本的事。
2. 原始素材采集与清洗
数据整理的过程中,最耗时耗力的不是标注,反而是前期的素材筛选和清洗。无人机飞一个架次可能产出上千张照片,但能合格进入数据集的,往往不到三分之一。我自己在清洗阶段处理掉的主要是三类问题:模糊、重叠、无效信息。
2.1 无人机原始素材从哪里来
无人机的型号不同,采集策略也不同。我用的素材一部分是自己用大疆御3飞出来的,一部分是公开的无人机影像库。自己飞的时候有两个心得:一是云台角度固定为90度正射,这样拍出来的图视角统一,标注时更容易上手;二是飞行高度尽量稳定在80到120米之间,这个高度范围内地面车辆的尺寸差不多是40到80像素,标注的时候人眼识别率高,模型学起来也更容易。
公开影像库的素材来源比较复杂,不同无人机、不同相机参数拍出来的图混在一起,色彩和噪声水平差异很大。这个阶段我一般会做一次全量色彩直方图统计,把明显偏色或者过曝的图挑出来。筛选标准是看亮度直方图的主峰位置,偏离正常区间的直接删掉,这类图就算硬留下来,训练时也会让模型对光照条件产生错误的偏置。
2.2 数据去重的几个实用办法
无人机航拍有个特点,同一片区域会反复覆盖,导致大量图片内容高度重叠。这种近乎重复的数据放进数据集里非常坑,模型训练时会反复看到几乎一样的样本,直接在验证指标上造假高。
我用的去重方法分两步走。第一步是简单的MD5哈希去重,处理完全一样的文件;第二步是感知哈希去重,我写了个Python脚本,把每张图缩成8x8的灰度图再计算平均哈希值,两张图的汉明距离小于等于5就判定为重复,挑分辨率高的那张保留。
这一步做完,1359张图就是从最初的五千多张里面筛出来的。整个过程自动化程度不高,中间还人工翻了好几遍,但没办法,数据质量这种事情,偷懒到最后都是模型自己买单。
3. PNG和JPG两种格式的取舍逻辑
市面上真正能用的数据集,很少会把同一种数据同时保存成PNG和JPG两个版本。我之所以会同时保留两种格式,是有具体业务考虑的。
3.1 两种格式在数据集中的角色划分
JPG压缩率极高,3000万像素的照片压到85%质量,单张也就2MB上下,存存储空间非常友好。但JPG是有损压缩,边缘会出现振铃效应和色块失真,如果直接用JPG图做像素级的语义分割标注,标注边缘和图像真实边缘之间会有像素级的偏差。
PNG是无损格式,图像细节保留完整,边缘锐利,但是文件体积通常是JPG的5倍以上。
我的处理策略是:标注图(语义分割掩膜)统一存成PNG,因为mask图不能有任何压缩失真;训练原图统一存成JPG,因为模型训练时做数据增强会随机裁剪和缩放,JPG带来的微小噪声反而可以当作一种天然的正则化。1359张照片里,大约60%是JPG,40%是PNG,主要看来源图的原始格式。
3.2 格式转换中的信息损失问题
格式转换看起来是小事,但处理不当会白丢信息。比如从PNG转JPG的时候,默认的编码质量如果设在75甚至更低,画面里的细小纹理(比如树冠的间隙、车辆的轮廓)会被明显涂抹掉。我实测下来,质量参数据设在90到95之间,人眼基本分辨不出差异,文件体积也不会失控。
还有一个比较容易忽略的点是色彩空间。无人机照片一般是sRGB,但如果有些图在导出时被转换成了Adobe RGB或者P3色域,直接统一转成JPG后颜色会发灰。我处理时会把所有源图先转成sRGB再统一转JPG,这样就避免了训练和推理时颜色不一致的问题。
3.3 图像文件元数据的处理细节
在用Python读取无人机照片的时候,有些图片没有标准的EXIF信息,会导致一些库默认按None处理,造成切片时报错。我一开始也遇到过这种情况,后来用PIL打开图的时候,会先检查一下getexif()的输出,为空就补一条空的EXIF记录再保存,虽然看起来是无用功,但后续所有基于EXIF的批量操作都会顺畅很多。
这部分处理的代码很简单:
from PIL import Image import os img = Image.open(src_path) exif = img.getexif() if not exif: # 补充空EXIF,避免后续处理报错 img.save(dst_path, format=img.format, exif=exif)4. 标注工作流与质量把控
标注是数据集整理里最磨人、也最影响模型上限的环节。1359张图,市面上商用的标注工具都能干,但真把标注的“手感”做出来,是需要自己整理一套规范的。
4.1 标注工具选型对比
我试过LabelImg、LabelStudio和X-AnyLabeling,最后选了X-AnyLabeling作为主力工具。原因有几个:
- LabelImg是纯手动框框,效率太低,1359张图全靠手画得画到天荒地老
- LabelStudio功能全面但界面偏重,启动慢,而且默认标注格式是COCO,转YOLO还得多一步
- X-AnyLabeling内置了SAM分割模型,可以先用模型预打点再人工微调,几百框的图几分钟就能标完
标注工具不是越复杂越好,关键看能不能适配自己的标注场景。我只有一个GPU机器,X-AnyLabeling在CPU上跑SAM效果不算好,但用它的交互式标注工具,框四个角就能自动拟合一个目标的轮廓,效率比纯手动高一大截。
4.2 标注边界规范的制定
边界怎么定义,直接决定模型学出来的预测框是什么样的。我在标注说明里明确写了三条规则:
- 车辆类:以车辆的最小外接矩形为准,不能把阴影算进去;但车辆顶部反光引起的亮斑要包含在框里
- 建筑类:屋顶边缘为准,墙体外沿不算;如果屋顶颜色和地面几乎一致,用道路分割线来辅助判断
- 植被和道路:这两类主要是语义分割用的,多边形标注,道路的边缘碰到树冠遮挡时按道路规划走向延伸,不能直接断开
这个规范看着细,但真正标注的时候非常必要。一开始没有这些规则,两个标注员对同一张图的标注结果IoU只有0.7左右,质量参差不齐。用规则约束之后,不同人的标注结果IoU能稳定在0.85以上。
4.3 质检环节怎么落地
我自己对质检的要求是三个人工检查加一个算法检查。人工检查主要是看标注框和目标是否对齐,有没有漏标和错标。算法检查就更硬核一点,我会写脚本检查三类问题:
- 标签坐标是否越界(比如坐标值不在0到1之间)
- 框的宽高是否为负或为0
- 框的大小是否过小(小于5个像素的目标,保留但是标记出来,如果同类目标太多的话,直接剔除这一批框)
做质检的时候,有个小经验很实用:把标注框画在图上,输出成一张整图的缩略图,然后用肉眼快速翻页看。人眼对异常框的敏感度远高于机器,一下子就能看到哪里标歪了。
# 统计数据集标注分布的小脚本 import os annotations_dir = "labels" class_counts = {} total_boxes = 0 for f in os.listdir(annotations_dir): if not f.endswith(".txt"): continue with open(os.path.join(annotations_dir, f), "r") as fh: for line in fh: parts = line.strip().split() if len(parts) != 5: print(f"格式错误: {f}") continue cls = parts[0] class_counts[cls] = class_counts.get(cls, 0) + 1 total_boxes += 1 print(f"总标注框数: {total_boxes}") for cls, count in sorted(class_counts.items()): print(f"类别 {cls}: {count} 个框")5. 数据集工程化整理的完整流程
数据集的最终价值取决于它能不能被快速接入训练和推理流程。我见过很多标注得很认真的数据集,最后因为目录结构混乱、图片和标签对不上而让人抓狂。整理数据集的工程规范,某种程度上比标注本身更重要。
5.1 目录结构与命名规范
我采用的是YOLO标准目录结构,同时兼容VOC的格式。命名规则定了三条:
- 图片文件统一命名为
DJI_0001.jpg、DJI_0002.jpg这种序号格式,不使用原始文件名(原始文件名经常有不同无人机厂商的特殊编码) - 图片和标签文件名必须一一对应,只是后缀不同
- 图片和对应标签放在同级目录,便于后续划分和读取
完整的目录结构长这样:
dataset/ ├── images/ │ ├── train/ │ │ ├── DJI_0001.jpg │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ │ └── ... ├── labels/ │ ├── train/ │ │ ├── DJI_0001.txt │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ │ └── ... ├── masks/ │ ├── train/ │ └── ... └── data.yaml这里的data.yaml是YOLO训练时用的配置文件,里面声明了数据集路径、类别数和类别名称:
path: /path/to/dataset train: images/train val: images/val test: images/test nc: 4 names: ['vehicle', 'building', 'vegetation', 'road']5.2 数据划分的策略:按飞行架次分,不按图片分
很多人划分训练集、验证集和测试集的时候,直接随机抽样,这个习惯在无人机数据上是个坑。因为连续拍摄的航拍图之间重叠度很高,随机抽样会使得同一个区域同时出现在训练集和验证集里,造成验证指标虚高。
我的做法是按飞行架次划分。每一批无人机任务产生的数据作为一个整体,三个架次进训练集,一个架次进验证集,一个架次进测试集,这样能最大限度模拟真实部署时的场景——模型必须对没见过的区域做出判断。
我划分的比例是8:1:1,即1087张训练、136张验证、136张测试。如果后续图数量增加,这个比例也会随之变化,但按架次分组的原则不会变。
5.3 数据增强在不同阶段的应用位置
我在这个数据集上做了不少数据增强。标准的翻转、旋转、缩放、颜色抖动都在我的增强列表里,但对于无人机数据,有两个增强操作特别有效:随机裁剪和马赛克增强。
随机裁剪其实就是把大图切成小块的过程,这个在训练前用脚本一次性完成即可,不建议在训练时在线做,太吃IO性能。马赛克增强则放在训练的输入pipeline里,YOLOv8和YOLOv5都原生支持,直接把4张图拼接成一张输入模型。
值得注意的是,语义分割任务的数据增强方式和目标检测不同。分割任务我一般只做随机翻转、旋转和尺度扰动,不做马赛克拼接,因为拼接会让物体的边界变得不连续,分割网络很难学明白。
6. 常见问题与排查技巧实录
数据整理的过程中,我遇到了一些比较典型的数据工程问题,这里挑几个有代表性的记录下来,可以当成一个速查表来用。
6.1 标签文件和图片文件名对不上
最头疼的问题之一。文件名多了个空格、后缀大小写不一致、或者从Windows传到Linux后编码变化,都可能导致标签匹配失败。
我写了一个校验脚本,遍历所有图片文件,检查对应的label文件是否存在。如果发现缺失,就打印出来,人工判断是漏标了还是文件名不一致。如果是文件名不一致,用脚本批量重命名就行。
import os from pathlib import Path def validate_dataset(images_dir, labels_dir): img_files = list(Path(images_dir).glob("*.jpg")) + list(Path(images_dir).glob("*.png")) missing = [] for img in img_files: label = Path(labels_dir) / (img.stem + ".txt") if not label.exists(): missing.append(img.name) return missing missing = validate_dataset("images/train", "labels/train") print(f"缺失标签文件数: {len(missing)}") for m in missing[:20]: print(m)6.2 图片打开失败或者色彩异常
有一小部分图打开后颜色是灰色的,看起来像JPG解码失败。我排查后发现问题出在色彩配置上,这些图没有嵌入ICC Profile,部分解码器会默认按不带色彩管理的模式处理,导致颜色偏灰。
解决办法是统一用PIL重写图像数据,并强制指定sRGB色彩空间。这一步可以把几乎所有设备上预览的颜色都校准到一致。
6.3 标注框泄漏到图片外
人工标注的时候,很容易把图片边缘附近的物体框画到图片外面去。这种框在训练时会引入大量负梯度,模型学到的东西不干净。
我的处理方式是写脚本把所有坐标硬截断到有效范围,框的中心点如果已经在图片外面了就剔除,宽高如果截断后小于2个像素也直接去掉。这个操作很简单,但很有效,能明显减少训练时不稳定的情况。
另外,如果读取标注文件时发现坐标越界的比例超过5%,说明标注环节出现了系统性问题,不是个例,应该回到标注环节去检查到底哪里出了问题,而不是简单靠脚本修完继续往下走。
6.4 数据可视化检查的实操方法
我习惯在训练前做一次全量可视化检查。方法很简单,把标注好的框画在原图上,拼成一张大图,快速浏览。
import cv2 import numpy as np def draw_boxes(image_path, label_path): img = cv2.imread(image_path) h, w = img.shape[:2] if not os.path.exists(label_path): return img with open(label_path, "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls, cx, cy, bw, bh = parts cx, cy, bw, bh = map(float, (cx, cy, bw, bh)) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, cls, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) return img这个脚本会在标注不对的时候很快暴露问题,比对着数字去看txt文件直观太多了。
7. 训练前的最后检查与数据使用建议
数据集整理的最后一公里,是训练前的一些琐碎检查。这些检查虽然不起眼,但能避免很多训练中途崩溃的尴尬情况。
7.1 类别平衡与样本量核对
我会跑一遍所有标签的类别分布统计,目的不是追求完美的均衡,而是要清楚自己手上有多少筹码。如果发现车辆类有5000个框,植被类只有800个框,那就要做好后续处理方案——比如重采样、加权重,或者直接少用一些严重的类别不平衡算法。
1359张图统计下来,我的类别分布大致如下:
| 类别 | 标注框数 | 占比 |
|---|---|---|
| 车辆 | 6234 | 42.7% |
| 建筑 | 3482 | 23.9% |
| 植被 | 2912 | 19.9% |
| 道路 | 1970 | 13.5% |
这种分布不算太离谱,但车辆类明显偏多。我在训练时给车辆类设置的loss权重稍微低了一点,其他三个类别略高,实测mAP有2到3个点的提升。
7.2 缓存与数据读取性能优化
训练时最大的瓶颈往往是数据读取。机械硬盘上直接跑训练的话,IO会成为训练速度的上限。我的做法是在训练前把所有数据打到内存里,或者用lmdb/webdataset这类格式打包,在小数据集上效果非常明显。
服务器内存足够时,直接创建一个内存盘来放数据集,速度提升立竿见影。如果内存不够,就退一步把单张图压缩到适当分辨率再存成TFRecord格式。总之无论如何,别让数据读取成为训练管线里的瓶颈。
8. 个人实操心得:数据集的复用与持续迭代
整个数据集从原始素材到最终交付,前后用了将近三周时间。回头看,最大的心得是:数据集不是一次性产品,是需要持续迭代的基础设施。
第一版1359张图,帮我把YOLOv8的mAP50从0提升到了0.81,这个成绩离实用还有距离,但已经能跑通整个检测pipeline了。如果后续继续采集新的飞行任务数据,我会把这些新素材按照同样的流程清洗、标注、质检、划分,增量并入现有数据集,而不是重新从头整理。
另外一个小建议:标注数据的时候,尽量多标一些边缘情况。比如阴天光照下的车辆、部分被树冠遮挡的建筑、多种植被混合的草地,这些困难样本在训练时价值极高。一套数据集里如果全是“漂亮”的图,模型在真实场景中的泛化能力会大打折扣。
最后分享一个我在格式处理上的小技巧:所有图片统一用脚本再转一遍的时候,一定要记录下转换前后的文件大小和像素尺寸。发现某个文件转换后尺寸异常,说明它可能是特殊编码或者损坏文件,提前处理掉,就能避免训练途中因为一个坏图崩溃整个流程。
本文还有配套的精品资源,点击获取