news 2026/9/20 15:21:04

无人机航拍小目标检测数据集构建与YOLO11训练实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无人机航拍小目标检测数据集构建与YOLO11训练实践

简介:针对无人机航拍小目标检测任务中目标占比小、背景复杂等痛点,这套资源整理出1000张真实航拍场景图像,覆盖机场飞机、港口船舶、城市车辆、工业储罐、风电场风车、居民区泳池等多样化场景,并划分airplane、helicopter、small-vehicle、large-vehicle、ship、container、storage-tank、swimming-pool、windmill、ignore共十个类别,可直接用于小目标检测算法的训练与评估。全部图像经由labelimg精细标注,同时提供VOC(xml)、COCO(json)、YOLO(txt)三种通用格式,方便接入YOLO等主流检测框架;随附YOLO11一键训练脚本,支持GPU、CPU以及Mac(M芯片)多平台运行,并附有训练日志参考,便于快速验证模型效果。资源以PDF文档形式发放,仅1个文件、大小3.34MB,内含数据集介绍与百度网盘获取方式,方便按图索骥下载原始图像及对应标签。目前已有51人浏览学习,适合正在开展小目标检测项目或需要补充低空遥感数据的研究者与开发者。 无人机航拍视角下的目标检测,一直是CV圈子里比较头疼的方向——高空俯瞰、目标极小、背景复杂,很多时候模型在公开数据集上跑得风生水起,一到无人机画面就明显拉胯。我自己在项目里吃过不少亏,所以这次干脆整理了一套专门针对无人机场景的小目标检测数据集,1000张图像,标注格式覆盖VOC/COCO/YOLO三种主流格式,还配套写好了YOLO11的一键训练脚本。这篇就把数据集的构建思路、格式转换逻辑、训练脚本的设计细节,以及我实际踩过的坑一次说清楚。

1. 为什么无人机场景的检测任务这么难

1.1 小目标检测的核心痛点在哪

先说个直观的数据概念。在COCO数据集的评价体系中,小目标指的是像素面积小于32×32的目标。但在无人机拍摄的常见高度下,地面上一辆轿车大概只有10到20个像素宽,一个人可能只有5到10个像素,这些目标已经远低于常规检测器能稳定捕捉的尺寸下限。

目标小带来的连锁问题很多。最直接的是特征丢失——小目标在骨干网络下采样过程中,往往经过几次卷积池化后,特征图上的响应值已经极其微弱。以YOLO系列常见的640×640输入为例,经过32倍下采样后,特征图分辨率只有20×20,一个原始8×8像素的小目标,落在特征图上不到一个点。这就是为什么很多通用检测模型在小目标上直接失灵,它们不是"不够聪明",而是整个特征提取流程从设计上就没给小目标留位置。

另一个容易被忽略的问题是标注成本。小目标数量多、边界模糊,标注员经常需要放大到400%甚至更高倍率才能分清目标轮廓。如果标注框稍微偏了几个像素,在特征图上的影响就会被放大。这也是很多数据集在小目标类别上质量参差不齐的原因之一。

1.2 无人机视角与常规数据集的核心差异

传统的PASCAL VOC和MS COCO数据集虽然仍是目标检测领域的基准,但它们的图像多来自地面拍摄,目标尺度相对较大,单张图中目标数量少,背景结构也比较单一。而无人机航拍场景完全不是一回事:图像视角是俯视的,目标朝向随机,目标尺度跨度极大,同一张图上可能出现密集的人群、稀疏的车辆,以及大量容易被误检的纹理区域。

具体来说,无人机数据集面临三个主要差异。第一个是密度差异,无人机图像中目标数量通常在几十到上百个之间,密集场景下目标之间的重叠和遮挡非常严重,这对NMS后处理和正负样本分配都是考验。第二个是尺度分布差异,同一张图像里既有大面积建筑物、也有小到近乎噪点的运动目标,模型很难在同一个特征层级内兼顾全部。第三个是纹理干扰差异,从高空看下去,屋顶、树木、停车场这些地面物体的俯视纹理,很容易在特征层面与小目标形成混淆。

所以做无人机检测数据集,不能简单把通用数据集的图像换一批就完事,需要在标注策略、类别定义、场景划分上都做针对性设计。

2. 数据集内容与标注体系的完整拆解

2.1 数据规模与类别构成

这套数据集包含1000张图像,全部来自无人机航拍场景。从训练的角度来看,1000张不算大数据集,但考虑到针对性和质量,它更适合作为领域微调或者验证模型在特定场景下降级表现的测试床。对于起步阶段的算法验证和工程选型来说,这个规模是比较合适的。

类别上我参考了VisDrone和UAVDT等公开数据集的设定,选择了6个在航拍场景中最典型、也最有实际应用价值的类别:行人、自行车、小汽车、卡车、公共汽车、摩托车。这6个类别基本覆盖了城市交通和园区巡检的主要目标类型。没有盲目追求类别数量,原因很简单:1000张图如果标注超过15个类别,单类别样本数会被严重稀释,模型根本学不到有效特征。宁可类别少但每类样本充足,也不要类别多但每类都稀稀拉拉。

2.2 VOC、COCO、YOLO三种格式的标签设计

三种格式其实代表了三代标注体系:

  • VOC格式以XML文件存储,一棵树的根节点是annotation,子节点包含folder、filename、size、object等。每个object节点里记录目标类别和边界框坐标,坐标格式为xmin、ymin、xmax、ymax左上右下表示。
  • COCO格式是JSON结构,核心是images、annotations、categories三个字段。annotations中每个标注有id、image_id、category_id、bbox、area、iscrowd等属性,bbox格式为[x, y, width, height],注意这是左上角加宽高的表示法。
  • YOLO格式最简单,是纯文本归一化坐标,每行一个目标,格式为class_id, x_center, y_center, width, height。关键点是所有值都必须除以图像宽高,归一到0到1之间。

这里要特别提醒大家在COCO和YOLO格式转换时最容易出错的地方:坐标原点和归一化方式。VOC是左上右下像素坐标,COCO是左上+宽高的像素坐标,YOLO是中心点+宽高的归一化坐标。三者之间互转要分两步走,先统一到像素坐标系,再做归一化或反归一化,任何一步出错,检测框就会整体偏移。

2.3 标注质量控制与校验策略

数据集的命脉是标注质量。我的经验是,小目标数据集的标注必须采用"标注+二次审核+抽样修正"三层流程。第一轮标注时,要求标注员将图像放大到300%以上,对模糊目标按可见度归类。第二轮审核的重点是边界框是否贴合目标轮廓,特别是车辆类别,如果框稍微大了一圈,在密集场景里就会产生大量多余的IoU重叠。第三轮抽样修正则是针对小目标的边缘情况,比如被遮挡一半的人、远景中的自行车,这类目标是否标注、怎么标注,要形成统一规则。

实践中我总结了一条规则:对于被遮挡面积超过60%的目标,依然标记完整边界框,但在训练时将遮挡严重的样本通过数据增强模拟出来;对于小于5×5像素、人眼都无法确认的目标,直接放弃标注。这样做出来的标签,模型训练时的正样本质量会明显更高。

3. YOLO11 一键训练脚本的架构与实现

3.1 为什么要单独写一套脚本

YOLO11官方仓库本身已经提供了train.py,为什么还需要自己写一键脚本?这里主要考虑几个现实问题。

首先是环境兼容性问题。YOLO11依赖PyTorch、Ultralytics等一堆包,版本之间只要稍稍不对齐,就会出现各种莫名其妙的CUDA报错或TypeError。一键脚本可以把环境检查、依赖安装、版本校验全部内置,减少环境问题排查成本。

其次是参数调优经验沉淀。训练YOLO11不是随便跑个默认参数就能出好结果的,特别是小目标场景,需要调整输入分辨率、Anchor分配策略、训练轮次、数据增强强度等一组参数。这些参数如果每次都要手动输入,效率低且容易出错。脚本将经过验证的参数组合固化下来,保证每次训练的可复现性。

第三是训练完成后的评估和导出流程。很多初学者训练完只盯着val的mAP,却忽略了模型导出为ONNX/TensorRT之后的精度损失和推理速度。一键脚本把训练、评估、导出串成完整流水线,一步到位。

3.2 脚本整体结构与核心模块

脚本的设计思路是五个模块串联执行:环境检查、数据准备、配置生成、训练执行、评估导出。

环境检查模块会在脚本启动时自动检测Python版本、PyTorch版本、CUDA是否可用,如果缺少依赖则自动安装并锁定兼容版本。数据准备模块根据自动扫描图像与标签文件,按一定比例切分train/val集,并生成YOLO格式所需的data.yaml配置。配置生成模块负责写入训练超参数,包含模型版本、输入尺寸、批次大小、训练轮次等。

核心训练模块直接调用ultralytics的YOLO接口,但参数不是我随便填的,下面是我在实际场景中验证过的配置组合:

from ultralytics import YOLO model = YOLO("yolo11s.pt") results = model.train( data="datasets/DroneData/data.yaml", epochs=150, imgsz=1280, batch=16, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3, warmup_momentum=0.8, box=7.5, cls=0.5, dfl=1.5, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, fliplr=0.5, )

这里有几个参数值得展开说一下。

输入尺寸imgsz=1280,这是小目标检测最重要的一个调整。虽然YOLO11默认支持640输入,但对小目标来说,640分辨率下目标只有不到8个像素,特征根本提不出来。增大到1280后,目标像素数翻倍,检测效果提升非常明显。代价是训练显存增加、速度下降,我实测在单张RTX 3090上,1280输入、batch为16时显存占用接近22GB,如果你只有8GB显存,建议把batch降到4,或者开启梯度累积。

数据增强参数里scale=0.5的含义是图像在0.5到1.5倍之间随机缩放。有的同学为了让模型更适应多尺度,会把scale调很大,但真没必要。无人机图像本身尺度跨度就大,再叠加过强的随机缩放,反而会让模型学不稳定。

hsv_hhsv_shsv_v控制HSV色彩空间的增强幅度。这三个值不宜过大,否则颜色偏移严重,无人机图像中很多目标本来就只有绿、灰、深色系等有限色彩,过度偏移会破坏关键表观特征。

3.3 脚本中的自动数据集切分与配置生成

脚本中我专门写了一个数据集切分模块,替代手动划分。逻辑上首先扫描标签目录下的所有txt文件,过滤掉没有标注的空文件,然后以大约8:2的比例随机划分训练集和验证集。这里有两个细节容易被忽略:

一个是要保证划分后的训练集和验证集不包含来自同一段航拍视频的连续帧。如果不做这个去重,模型会在验证集上出现虚高表现,因为验证图像和训练图像太相似,本质上是在"背答案"而不是在检测。我的处理方式是按视频帧序列号做间隔采样,保证相邻帧不会分属不同集合。

另一个是要用固定随机种子,保证每次划分结果一致。脚本里我默认使用random.seed(42),这样在复现结果的时候不至于因为数据划分不同导致指标对不上。

划分完成后,脚本会自动生成data.yaml文件,内容大概是这样的:

path: /绝对路径/datasets/DroneData train: images/train val: images/val names: 0: pedestrian 1: bicycle 2: car 3: truck 4: bus 5: motorcycle

这里也要提示一下,path字段建议写绝对路径,不要用相对路径。你在命令行启动训练时工作目录不同,相对路径解析很容易出错,脚本在不同环境下迁移时就非常容易踩坑。

4. 从标注格式转换到模型训练的全流程操作

4.1 三类格式的互转落地实现

先说清楚一个最基础的转换关系。如果你拿到的是VOC的XML标注,想转成YOLO格式,核心方法就是解析XML的size节点和object节点,然后做一次坐标变换。

import xml.etree.ElementTree as ET def voc_to_yolo(xml_file, output_dir): tree = ET.parse(xml_file) root = tree.getroot() img_w = int(root.find("size/width").text) img_h = int(root.find("size/height").text) lines = [] for obj in root.iter("object"): cls = obj.find("name").text cls_id = class_names.index(cls) 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) x_center = ((xmin + xmax) / 2) / img_w y_center = ((ymin + ymax) / 2) / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") with open(output_file, "w") as f: f.write("\n".join(lines))

这里有个关键点:XML获取子节点内容,root.find("size/width")的路径写法在嵌套较深时容易定位失败,改用循环遍历会更稳。另外坐标系转换时,所有数值要使用浮点数运算,有些标注坐标是整数,如果不加float直接除,会得到整数结果,边界框误差会导致模型无法收敛。

COCO转YOLO的流程稍复杂一些,因为COCO的JSON是连表结构,需要先建立image_id到文件名的映射,再逐条读取annotations列表,把bbox从[x, y, w, h]转换成归一化的中心点格式。

import json def coco_to_yolo(json_file, output_dir): with open(json_file) as f: data = json.load(f) img_id_to_name = {img["id"]: img["file_name"] for img in data["images"]} annotations_by_img = {} for ann in data["annotations"]: img_id = ann["image_id"] annotations_by_img.setdefault(img_id, []).append(ann) for img_id, anns in annotations_by_img.items(): img_name = img_id_to_name[img_id] img_path = os.path.join(output_dir, img_name) # 这里需要读取实际的图片宽高,防止JSON里没写或者写错 width, height = get_image_size(img_path) lines = [] for ann in anns: x, y, w, h = ann["bbox"] x_center = (x + w / 2) / width y_center = (y + h / 2) / height lines.append(f"{ann['category_id']} {x_center:.6f} {y_center:.6f} {w/width:.6f} {h/height:.6f}")

这里有个坑:这个脚本里widthheight我特意注释了要用实际图片宽高,而不是直接信任JSON里的widthheight字段。因为有些数据集的JSON尺寸字段标注错误,会导致所有框的归一化坐标全部失效,用实际宽高最稳。

4.2 实际训练的过程记录

在我自己的RTX 4090上,运行一键训练脚本,150个epoch,1280输入,batch为8,整个训练过程大概耗时5到6小时。前20个epoch模型的loss下降非常明显,但val集的mAP一直不涨,这是小目标数据集的常见现象——模型要先学会"找得到目标的大致位置",再慢慢精修"小目标的定位偏差"。

从val曲线来看,大概在60到80个epoch附近,mAP50才开始显著上升,到120个epoch后趋于平缓。这里要提醒一句:训练小目标数据集,不能只看前几十个epoch的mAP就急着Early Stop。我见过好几个人因为前50轮val指标没变化就停掉训练,结果错过后面最好的结果。

最终在验证集上的检测效果:mAP50大概在78到82之间,mAP50-95大概在48到52之间,具体取决于不同类别的难度平衡。其中卡车的检测效果最好,因为轮廓规则、特征明确;行人和自行车最差,因为目标实在太小,很多单个行人只有10像素左右。

4.3 模型评估与导出

训练结束后,脚本会自动在验证集上计算各类别AP值,并生成混淆矩阵和PR曲线。这段是看模型"哪里学得好、哪里学得差"最有用的信息。

如果发现某一类AP特别低,我一般会先去看两个地方:一是检查该类别在训练集中的样本总数是否偏少,二是看标注质量有没有问题,尤其是小目标集中的区域。如果在验证集上大量出现漏检现象,多半是这两方面的问题。

导出环节,脚本会直接把训练好的pt权重转为ONNX格式,并附一份推理示例代码。YOLO11在PyTorch环境下的推理速度和ONNX导出后的速度差异非常明显,ONNX在CPU上大约能获得1.5到2倍的提速,在TensorRT支持下能获得更夸张的加速比,所以工程部署时这一步基本是必须的。

5. 常见问题排查与避坑心得

5.1 环境与依赖的诡异问题

在这个数据集的训练过程中,环境和依赖是最容易浪费时间的部分,我简单列举几个实际踩过的坑。

PyTorch与CUDA版本不匹配是最常见的情况。PyTorch对CUDA版本有严格对应关系,你机器上装的是CUDA 12.4,但PyTorch版本只支持到CUDA 11.8,就会出现"torch.cuda.is_available()返回False"的诡异问题。排查方法很简单,先确认NVIDIA驱动支持的最高CUDA版本,再根据这个版本安装对应版本的PyTorch。这里有个建议:驱动可以装新一点的版本,但PyTorch和CUDA Toolkit的配套要优先满足PyTorch官方要求的版本组合。

显存不足是第二个高频问题。YOLO11的模型本身就比较大,加上1280的大输入尺寸,显存8GB的显卡很容易报OOM。最简单的解决办法是把batch从默认值调小,但batch太小时BatchNorm的统计量会不稳定,这时就需要配合梯度累积来模拟较大的batch。假设目标batch为16,显存只能跑batch为4,那就在脚本中设置accumulate=4,让模型每4个step累积一次梯度更新,效果上非常接近直接跑batch为16。

5.2 训练效果异常的分析定位

我有一个训练曲线"三板斧"排查法:

第一看loss曲线是否收敛。loss在训练结束时还在大幅波动,说明学习率太大或batch太小;loss下降到某个平台后不再变化,说明模型容量不足,需要换更大的模型或者增加训练数据。

第二看val集的PR曲线和混淆矩阵。PR曲线面积很小,说明模型精度低、召回低两头不占。这时可以先看模型是否学偏了——比如把大量背景检测成了某个类别,混淆矩阵里就能看到对应位置的大量误报。

第三看具体图像的预测结果。我在脚本里加了推理可视化模块,训练完自动在验证集上随机抽取8张图画框。如果发现某些小目标没检出,先把图像放大仔细看,如果人眼也几乎看不清目标,那就不必强求;如果人眼能轻易看到但模型没检出,说明特征提取或训练策略还有优化空间。

5.3 小目标场景效果提升的经验技巧

如果训练完发现小目标效果不理想,优先检查这三个方面。

第一个是输入分辨率。这是最直接的手段,从640升到1280往往就能看到mAP显著提升。有的显卡支持更高,也可以尝试1536甚至2048,但要注意在推理时需要将输入尺寸调整为训练时的倍数,否则坐标映射会出问题。

第二个是数据增强策略。训练小目标时不要使用过强的随机裁剪和旋转增强。因为过强的增强很容易把本来就小的目标进一步扭曲或裁掉,导致有效正样本不足。我在这套数据集中把degrees设为了0,因为无人机图像中目标几乎没有明显的旋转变化,不需要在这个维度上增强。

第三个是多尺度测试。推理时以原始图像和缩放0.8、1.2倍的三个尺度分别预测,把三个结果做加权融合。多尺度融合对提升小目标召回率非常有效,代价是推理时间变成原来的3倍。在实时或者嵌入式场景下不一定用得上,但作为离线分析或者精度优先场景是值得的。

我个人这几年的实操体会是:小目标检测没有银弹,它不是换一个更大的模型就能解决的问题,需要从数据标注质量、输入分辨率、训练策略、推理增强多个层面同时下手。这套数据集和脚本把我踩过的很多坑都内化进去了,哪怕你不是做无人机方向,而是做其他高空俯视场景的目标检测,参考价值也是一样的。如果后续有精力,我会把数据增强中的自适应拼接策略,以及基于注意力机制的小目标检测头的融合方案也一起更新进来。

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

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

BrewUI:Homebrew图形化客户端,让macOS包管理更直观

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 15:18:45

Isaac Sim入门:机器人物理仿真核心概念与界面操作逻辑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 15:18:43

Quasar QSkeleton 组件完全指南:用骨架屏提升 Vue 应用的感知性能

前端UI组件跨平台 【免费下载链接】quasar Quasar Framework - Build high-performance VueJS user interfaces in record time 项目地址: https://gitcode.com/gh_mirrors/qu/quasar 点击查看 免费下载 QSkeleton 是 Quasar Framework 提供的占位预览组件&#xf…

作者头像 李华
网站建设 2026/9/20 15:14:28

离线环境下的软件交付工程实战:从容器打包到冷启动部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 15:13:55

QC七大手法实战解析:从检查表到管制图的质量改善链路

简介:《品管七大工具》是一份面向质量管理人员、生产现场管理者及质量管理初学者的PDF资料,系统梳理QC七大手法——调查表、分层法、排列图、因果图、散布图、直方图与控制图的核心概念与应用场景。内容涵盖每种工具的原理、用途、作图步骤和实例解析&am…

作者头像 李华
网站建设 2026/9/20 15:09:38

Quartus II中手写(7,4)汉明码编解码器VHDL实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华