news 2026/9/10 10:34:05

无人机识别数据集与目标检测:从标注到YOLOv8训练实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无人机识别数据集与目标检测:从标注到YOLOv8训练实战

简介:针对无人机目标检测任务的数据集资源,适用于使用YOLO系列、Faster RCNN、SSD等深度学习框架的开发者与研究人员。资源内含9229张无人机图片及对应标注,图片与txt标签已划分训练集、验证集和测试集,并附带指定类别信息的yaml文件,可直接用于YOLOv5至YOLOv10等主流YOLO算法的训练,省去数据整理与格式转换环节。压缩包共2000个文件,以txt标签文件为主体,另有1个yaml配置文件,整体大小约814.16MB。当前已有339人学习。对需要快速构建无人机检测模型、开展算法对比或实验的读者来说,这份数据集能够显著降低数据准备门槛,帮助聚焦模型训练与调优。

1. 无人机识别数据集:目标检测里最像“找针”的任务

“无人机识别数据集”这个词在目标检测项目里经常被误解成“用无人机拍的交通数据集”,实际上它指的是把无人机当成待检测目标的数据集。反无人机安防、低空管理、机场净空巡检都要靠目标检测识别图像里的微型无人机,难点是非常具体的四个词:目标小、速度快、背景杂、像鸟。数据集中无人机目标常只占图像面积千分之几,而检测模型的基础指标严重依赖标注质量。后续章节用yolov8、mmrotate、切片推理等方法,把这一类数据集从采集标注到训练评估走一遍。适合要做目标检测模型落地的工程师,也适合刚拿到反无人机项目需要快速建立数据流程的团队。

2. 无人机识别数据集来源:公开集、自采与仿真合成怎么选

要训练一个能在真实边界场景下工作的无人机识别模型,第一步不是急着选模型,而是把数据源盘清。无人机识别数据集通常来自三个方向:公开下载的已有数据、团队自采的真实视频、三维渲染生成的合成图片。三者各有不可替代的价值,也各有明显短板,组合使用比只依赖一个来源更现实。

2.1 公开无人机识别数据集下载前先确认目标定义

公开数据集中,anti-UAV、Drone-vs-Bird这类是专门把无人机当目标的,另有一些遥感目标检测数据也把无人机列为小目标类别。下载后第一件事不是直接解压训练,而是确认它的目标定义:红外帧还是可见光帧,单目标还是多目标,最小目标像素是多少,是否带轨迹粒度的标签。这些标注语义相差很大,有的数据一帧里只有1个无人机,有的数据一帧有几十个,直接混用会打乱正负样本配比。

我一般会先对所有候选数据集跑一个分布统计脚本,把每张图的尺寸、目标数量、目标框面积占全图面积的比例算出来。

import cv2, glob, numpy as np from pathlib import Path for img_path in glob.glob('datasets/*.jpg'): img = cv2.imread(img_path) h, w = img.shape[:2] label_path = Path(img_path).with_suffix('.txt') if not label_path.exists(): print(f'{img_path}: no label') continue boxes = np.loadtxt(label_path, ndmin=2) area_ratios = [] for box in boxes: # 每行:类别 归一化中心x 归一化中心y 归一化宽 归一化高 xc, yc, bw, bh = box[1], box[2], box[3], box[4] area_ratios.append((bw * w) * (bh * h) / (w * h)) if area_ratios: print(f'{img_path}: size={w}x{h}, target_num={len(area_ratios)}, ' f'min_ratio={min(area_ratios):.5f}')

逻辑说明:脚本按YOLO格式的txt统计,ndmin=2保证空文件也能进入循环;把归一化宽高乘回真实像素,再计算目标占图像面积的比例。统计结果如果一半以上目标占比低于0.001,这个数据集就跑不进常规COCO预训练模型的舒服区。如果要合并多个公开集,切分时按视频或拍摄场景划分,不要直接按帧随机划分。相邻帧几乎一样,混进验证集会得到虚高mAP,部署后遇到新背景立刻打回原形。

2.2 自采数据:用云台相机连续帧截取真实目标

公开集覆盖不到自己项目里的背景、机型和光照,就必须自采。常见做法是用带自动跟踪的云台相机录制视频,让无人机从远到近、从逆光到顺光飞几个来回,把背景中的树、楼、云、鸟都拍进去。不要只挑清晰帧,模型要在低清、模糊、过曝的情况下工作,所以运动模糊、对焦失败的帧也要留一部分。

视频抽帧时不要均匀抽帧,否则运动慢的时候全是重复帧,快速移动时间隔又太远。我用ffmpeg的mpdecimate滤掉近似重复帧:

# 剔重后才抽帧,避免数据冗余 ffmpeg -i drone_raw.mp4 -vf "mpdecimate=hi=64*32:lo=64*32:frac=0.1,setpts=N/FRAME_RATE/TB" -r 5 sampled_frames/%04d.jpg

参数说明:mpdecimate根据像素差异剔除与上一帧高度相似的帧,hilo控制阈值,frac=0.1表示允许最多10%的像素变化就保留;setpts重算时间戳,防止删帧后跳变;-r 5限定每秒最多抽5帧。抽出来的图再交给标注软件按目标检测框标注。自采数据要额外记录相机焦距和拍摄距离,方便反推真实尺度。目标在传感器上占据的像素数可以用“目标尺寸乘以焦距,除以距离再除以像元尺寸”估算。如果最大监视距离下目标只有50像素,训练阶段就应当重点保证该像素区间有充足样本。

2.3 仿真合成样本:用渲染器制作并做domain randomization

真实数据很难覆盖所有气象和遮挡情况,仿真合成是性价比很高的补数据方式。在Unity或Unreal里摆放无人机模型,设置多角度灯光、云雾、景深模糊,渲染出带透明通道的PNG,再合成到真实背景照片上。由于渲染时可以拿到精确位姿,标注框是自动生成的,几乎不存在人工标注误差。

但合成数据最大的问题是“一眼假”,模型容易学到清晰的锐利边缘。我会在合成阶段做随机的gamma变换、加高斯噪声、增加运动模糊,并把无人机模型粗糙度调到与实际漆面接近,避免出现类似CG光斑。训练时可以先把合成数据单独预训练,再用真实数据微调,比较符合“先用大数量学结构,再用少量真实数据调风格”的流程。

来源成本标注精度背景覆盖主要风险
公开集参差不齐固定场景目标定义不一致
自采贴近项目现场样本分布偏,单一机型
仿真极高无限组合风格迁移难,边缘过锐

这张表格能直观对比三条路:公开集适合做底料,自采负责守住真实场景,仿真负责把罕见情况的数量顶上去。实际项目里没有绝对最优配比,我一般从公开集和自采1:1起步,逐步把仿真数据插进去,观察验证集mAP变化。

3. 无人机识别数据集的标注格式换算:COCO、YOLO、DOTA坐标关系

拿到一批数据源后,第一个绕不开的问题是格式不统一。很多标注工具导出COCO JSON,另一些输出VOC XML;无人机场景里常见的DOTA格式是四个点的多边形。如果没有统一的中间格式,训练脚本会反复踩坑。

格式单位目标表示是否支持旋转框
COCO像素[x, y, w, h]
YOLO归一化[cls, xc, yc, w, h]
DOTA像素四个顶点坐标

3.1 COCO与YOLO格式的归一化换算

最常用的目标检测格式是YOLO txt:每行一个目标,内容是“类别id 中心x 中心y 宽 高”,全部归一化到0-1。COCO JSON里的bbox则存成[x, y, w, h],单位是像素,且x、y是左上角坐标。转换时唯一容易出错的是除以图像宽高,而不是减去某个预设尺寸。

import json, cv2, numpy as np from pathlib import Path with open('annotations/instances_train.json') as f: coco = json.load(f) img_info = {img['id']: img for img in coco['images']} cat_map = {cat['id']: i for i, cat in enumerate(coco['categories'])} out_dir = Path('yolo_labels') out_dir.mkdir(exist_ok=True) for ann in coco['annotations']: img = img_info[ann['image_id']] h, w = img['height'], img['width'] x, y, box_w, box_h = ann['bbox'] # 像素坐标转归一化的中心点坐标 x_center = (x + box_w / 2) / w y_center = (y + box_h / 2) / h n_w = box_w / w n_h = box_h / h label_line = f"{cat_map[ann['category_id']]} {x_center:.6f} {y_center:.6f} {n_w:.6f} {n_h:.6f}\n" label_path = out_dir / (Path(img['file_name']).stem + '.txt') with open(label_path, 'a') as out_f: out_f.write(label_line)

逻辑说明:先把COCO里的类别ID映射成从0开始的连续ID;label_path用图片文件名的stem命名,保证和图片在同一目录下;用追加模式写入,因为同一张图会有多个标注。转换后要抽几张图叠加显示验证,避免宽高写反或类别映射错位。

3.2 旋转框标注:DOTA四点多边形与HBB

无人机在画面里常见倾斜姿态,水平框会把机臂和背景一起包进去。DOTA格式用四边形的四个点表示目标,但很多目标检测模型只支持水平框。这里是两种选择:一是直接取四点外包成水平矩形,适合桨叶旋转后外形接近圆形的情况;二是转成旋转框,交给支持OBB的模型训练。

用OpenCV把多边形转成旋转外接矩形:

import cv2 import numpy as np def poly_to_rotated_rect(poly): pts = np.array(poly, dtype=np.float32).reshape(4, 2) (cx, cy), (w, h), angle = cv2.minAreaRect(pts) # 统一长边为w,保证角度定义只有一套 if w < h: w, h = h, w angle += 90 return cx, cy, w, h, angle

参数说明:cv2.minAreaRect返回中心、宽高和旋转角度;为了统一角度语义,约定w永远是不小于h的边,后面的角度对应长边与x轴的夹角。实际训练OBB模型时,角度周期性问题会让loss震荡,同一份标注最好用作者给出的角度协议做校验。如果只是做水平检测,用多边形坐标的x、y最小最大值计算外包框即可,代价是斜体目标框面积膨胀,NMS时容易把两个邻近无人机框合并。

3.3 数据划分与类别文件

划分数据集时,常见做法是按“拍摄片段”或“场景目录”拆分,而不是按文件随机分。否则同一段视频的前后半帧会同时进入训练和验证,指标好看但没有参考价值。写一个分组划分脚本,把每个scene下的图片放到fold列表,再按比例切分即可。

训练前至少需要一个类别文件,yolov8风格如下:

path: /data/drone train: images/train val: images/val names: 0: drone 1: bird 2: background

注意:这类数据集的负样本也很关键。如果只有正样本没有背景负样本,模型会倾向于把任何相似纹理都判断成无人机,误检率会很高。建议在val集中加入纯背景图,并允许它们没有标注文件。

4. yolov8训练自己的无人机识别数据集:完整命令与参数

把统一后的无人机识别数据集交给yolov8训练,是目前开销最低、目标检测落地最快的方式之一。这里直接写我常用的环境准备、训练命令和参数调整思路,不绕弯。

4.1 环境准备与数据集目录

先创建项目目录,按yolov8约定摆放:images/trainimages/vallabels/trainlabels/val。要保证图片和txt标签有相同的文件名,缺标签的正样本会被当作背景图跳过,缺标签的负样本则会丢掉。安装依赖用pip即可:

pip install ultralytics

安装完成后,用yolo detect train启动训练。如果本机有NVIDIA GPU,ultralytics默认会使用CUDA;如果只有CPU,建议把模型换成yolov8n,并把batch降到2-4,否则训练速度会慢到没法迭代。

4.2 训练命令及关键参数

训练命令可以写成这样:

# 用小模型快速迭代,imgsz=640适合显存紧张的环境 yolo detect train data=drone.yaml model=yolov8n.pt \ imgsz=640 batch=16 epochs=100 lr0=0.01 \ optimizer=AdamW cos_lr=True patience=20 \ project=runs/drone name=base

参数说明:

  • imgsz=640是训练输入尺寸。对于无人机小目标,可以提升到1280,显存不够时先降低batch;
  • batch=16在有GPU时设为显存能容的上限,通常用batch=-1自适应即可;
  • lr0=0.01是初始学习率,数据规模大而目标小时可以降到0.005;
  • cos_lr=True用余弦退火,能减少后期loss震荡;
  • patience=20表示验证集指标连续20个epoch不涨就提前停止。

yolov8默认开启Mosaic增强,这对大目标很有用,但无人机识别数据中小目标居多,大片背景被裁掉后小目标可能消失。如果训练中期loss降不下去,可以关掉或降低Mosaic比例。这里给出常用的一组hyp参数参考:

参数通用值无人机识别建议原因
mosaic1.00.3保留小目标上下文
scale0.50.8模拟不同飞行距离
fliplr0.50.0避免左右不对称机型产生歧义
hsv_h0.0150.02微调颜色,防止过拟合背景

补充说明:fliplr设为0.0是我个人经验,少数机型的云台或天线只在单侧,水平翻转会让类别语义不准确。scale提高后,模型会在更多尺度上看到目标,但过大的scale会引入严重形变,需要看训练曲线调整。

4.3 训练后验证与导出

验证时为了看清模型的真实漏检情况,不要用默认置信度0.25做报告。低置信度候选对后续难例挖掘非常重要,先用0.001跑一遍:

# conf设低,把低置信度候选保留下来 yolo detect val model=runs/drone/base/weights/best.pt \ data=drone.yaml imgsz=640 conf=0.001 iou=0.5

参数说明:conf=0.001让所有高于千分之一的预测都输出,会看到很多漏检被转化为低分置信度候选;iou=0.5是用IoU阈值判定匹配成功,用于评估mAP@50。

验证通过后如果要部署到边缘盒子,导出ONNX或TensorRT:

yolo export model=runs/drone/base/weights/best.pt format=onnx imgsz=640

导出的best.onnx可以用ONNXRuntime在CPU或GPU上跑,也可以进一步量化为INT8模型;量化对小目标精度会有一定损失,需要结合验证结果决定是否启用。

5. 无人机小目标检测:切片推理与mmrotate旋转框回炉

很多无人机识别数据集训练出来的模型,mAP能到0.8,但实地测试时远处的无人机一个都检不出来。问题不是模型差,而是小目标在特征提取过程中信息消散了。

5.1 为什么无人机识别数据集在小目标上漏检

目标检测网络通常有5次下采样,最终特征图的步长达到32。一个10x10像素的无人机,在最后特征图上只占不到1个像素的激活区域。目标框太小,还容易在NMS阶段被周围高分背景候选压掉。更麻烦的是,训练阶段Anchor和候选框默认针对中等目标,大尺寸预训练模型里的先验与小目标不匹配,导致召回率很低。针对这个问题的第一道解法是提高输入分辨率,但显存占用上升,代价很大。第二道解法是切片推理,让模型在局部放大区域里找小目标,相当于把推理时的“等效焦距”拉长。

5.2 用切片推理把大图切块,提升小目标召回

切片推理在小目标检测里非常常见,做法是先把原图切成若干有重叠的patch,逐patch检测,再把结果映射回原图坐标。用sahi库实现这条流程可以省去很多坐标换算代码:

# 推理时用20%重叠避免目标被切断 sahi predict --model_type yolov8 \ --model_path runs/drone/base/weights/best.pt \ --source test.jpg --save_dir sahi_out \ --slice_width 512 --slice_height 512 \ --overlap_height_ratio 0.2 --overlap_width_ratio 0.2 \ --conf_threshold 0.15

参数说明:slice_width/height是切片尺寸,建议与训练imgsz一致;overlap_*_ratio控制重叠比例,0.2能缓解目标被切断的问题;conf_threshold比常规推理低,因为切片放大了目标,模型置信度会整体升高,但这个值仍要给后续NMS留空间。

切片推理的代价是N倍耗时。比如一张3840x2160的图,切成512x512加20%重叠,大约有60多个patch,在CPU上可能是几十秒。工程落地时需要对远景和近景做策略分流:近景目标足够大时直接整图检测,远景才走切片流程。

5.3 旋转框场景:用mmrotate训练DOTA数据集做回炉

如果无人机在数据集中呈现明显的倾斜姿态,水平框NMS会把斜着飞的两架机器误判成重叠,这时需要旋转框模型。mmrotate是目标检测生态里对旋转框支持最成熟的选择之一,DOTA数据集是它在遥感上的标准基准,无人机识别可以沿用这套训练管线。

先准备mmrotate环境,核心依赖是mmcv和PyTorch:

conda create -n mmrotate python=3.8 -y conda activate mmrotate pip install torch torchvision pip install openmim mim install mmcv pip install mmrotate

环境装完后,把自己的旋转标注按DOTA格式整理,再修改配置文件,把angle_version设为le90,训练命令通常是:

# 实际训练前需修改数据集的class_num和路径 python tools/train.py configs/oriented_rcnn/oriented_rcnn_r50_fpn_1x_dota.py --work-dir work_dirs/drone

这里要说明三点:一是该配置文件默认用于遥感目标,需要修改数据集的class_num、数据集路径和图像scale;二是旋转框模型的loss对角度敏感,训练前最好先做可视化确保角度定义一致;三是mmrotate对PyTorch版本要求较严,版本冲突时优先按它的官方环境组合固定版本。

6. 无人机识别数据集清洗与难例挖掘:用验证结果反向修订

最后需要回到数据集本身。模型已经训练完,但验证集里仍有一些mAP分析看不到的信息,比如哪些小目标被漏检、哪些背景被误报。反向修订数据集,比继续加epoch更有效。

6.1 统计漏检框的尺寸分布

把验证集里没有与真值匹配上的低置信度候选导出,统计它们的面积分布,能直接看出模型在哪一段距离失效。用ultralytics的predict模式把所有预测结果保存在predictions.json,再与标签做匹配,提取未匹配真值。

import json, glob, numpy as np preds = json.load(open('runs/drone/val/predictions.json')) gt_files = glob.glob('datasets/val/labels/*.txt') miss_areas = [] for pred in preds: img_name = pred['image_id'] + '.jpg' gt_path = 'datasets/val/labels/' + img_name.replace('.jpg', '.txt') gts = np.loadtxt(gt_path, ndmin=2) match = False for gt in gts: gt_area = gt[3] * gt[4] pred_box = pred['bbox'] pred_area = pred_box[2] * pred_box[3] iou = compute_iou(pred_box, gt_box) if iou > 0.5: match = True break if not match: miss_areas.append(gt_area) print('missed gt target areas:', np.percentile(miss_areas, [25, 50, 75]))

这里省略了compute_iou的实现,匹配含义是:IoU过0.5算命中;把所有未命中的真值框面积沿升序排列。如果中位数很小,说明切片推理必须设为常驻流程;如果中位数不小,说明数据分布里缺少和目标相近的背景干扰,要补负样本。

6.2 难例增强:裁剪硬例回灌训练集

从漏检真值框里裁剪出原图区域,按固定宽高放大后做随机旋转、亮度扰动,再作为小目标正样本回灌到训练集。注意不要重复得太厉害,一个硬例最多复制3次,否则模型会对这张图过拟合。同时,误报最高的背景区域也应该裁下来作为负样本,目标检测里的负样本需要形成文件,而不是放在背景图片里让模型自己忽略。负样本文件可以只写类别编号,不写框信息,yolov8会把它当作背景图处理。

6.3 数据质量验证:可视化检查脚本

改动数据集后,首先要做的是可视化检查。写一个小脚本把每张图的标签和预测框同时画出来,拼成4x4网格,人工过一眼往往能发现坐标偏移、类别错标、目标框太小等问题。

import glob import cv2 import numpy as np def draw_label(img_path, label_path): img = cv2.imread(img_path) h, w = img.shape[:2] if not label_path.exists(): return img for line in open(label_path): cls, xc, yc, bw, bh = map(float, line.split()) # 归一化坐标还原为像素坐标 x1 = int((xc - bw/2) * w) y1 = int((yc - bh/2) * h) x2 = int((xc + bw/2) * w) y2 = int((yc + bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) return img imgs = glob.glob('datasets/val/images/*.jpg')[:16] grid = np.hstack([ cv2.resize(draw_label(im, Path(im.replace('images', 'labels')).with_suffix('.txt')), (320, 320)) for im in imgs ]) cv2.imwrite('vis_check.jpg', grid)

脚本把前16张验证图的标签画出来并横向拼接,最终得到一张vis_check.jpg。脚本只处理了水平框,如果是旋转标注,需要改成画多边形。跑完脚本后重点看三类问题:标注是否紧贴目标物体、小目标是否在缩略图上肉眼可见、类别错标是否让相近目标的分布重合。无人机识别数据集修订完,再用上一章的命令重新训练一轮,模型提升往往比调参更明显。

本文还有配套的精品资源,点击获取

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

51单片机DS18B20温度报警器实战:单总线驱动与LCD显示

简介&#xff1a;本资源是一套基于51单片机的温度报警器完整开发工程&#xff0c;面向嵌入式初学者与单片机课程实践者&#xff0c;解决环境温度实时监测、阈值报警与断电参数保存等典型应用场景问题。压缩包共33个文件&#xff0c;70KB&#xff0c;涵盖核心源码&#xff08;4个…

作者头像 李华
网站建设 2026/9/10 10:32:33

4 步解锁 WeMod Pro:Wand-Enhancer 从克隆到生效的完整路径

4 步解锁 WeMod Pro&#xff1a;Wand-Enhancer 从克隆到生效的完整路径 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer 按下面的步骤走完&#xff…

作者头像 李华