简介这份资源面向从事无人机航拍场景目标检测的开发者与学习者提供一套真实场景下的行人检测数据集可直接用于YOLO系列模型的训练与验证。数据采用labelimg标注标注框质量较高并同时提供voc、coco和yolo三种格式标签分别存放于不同文件夹便于适配不同检测框架。压缩包共2000个文件以1000个xml标注文件和990个txt标签文件为主另含少量html说明文档、py划分脚本与yaml配置文件整体约376.18MB。资源还附赠数据集划分脚本以及YOLO环境搭建、训练案例教程读者可根据需求自行划分训练集、验证集与测试集快速复现训练流程。目前已有1120人学习下载适合需要无人机航拍行人检测数据、希望省去标注与格式转换环节的读者参考使用。1. 无人机航拍行人检测为什么1000张图的数据集值得你认真跑一遍拿到「YOLO无人机航拍行人检测数据集」这个标题很多人第一反应是去搜 yolo预训练模型下载想直接套一个权重跑起来看效果。但真正做过无人机视角行人检测的人都知道通用 COCO 预训练模型在航拍场景下翻车是常态——俯视角度、小目标密集、光照剧烈变化、背景纹理单一这几个因素叠加起来模型很容易把行人当成电线杆或者把树冠阴影当成目标。这个数据集的价值不在于图片数量多而在于它同时提供了 voc、coco 和 yolo 三种格式标签外加划分脚本和训练教程等于把从数据准备到模型跑通的全链路都铺好了。适合谁用做无人机巡检、安防监控、航拍人流统计的算法工程师以及想入门 YOLO 目标检测但苦于找不到垂直场景数据集的学生和开发者。1000 张图不算大但足够你把 YOLO 训练流程完整走一遍理解小目标检测的难点在哪。2. 三种标签格式到底怎么选voc、coco、yolo 的转换逻辑与实操2.1 先搞清楚三种格式的存储结构和适用场景VOC 格式是 XML 文件每张图对应一个 XML里面记录图片尺寸、目标类别和边界框的左上角右下角坐标。COCO 格式是一个大的 JSON 文件所有图片的标注信息集中管理字段层级更深适合做多任务训练和标准化评测。YOLO 格式是每张图对应一个 txt 文件每行是类别索引 中心x 中心y 宽 高所有坐标都归一化到 0 到 1 之间。选哪个取决于你的训练框架如果你用 Darknet 原版或者 Ultralytics 的 YOLOv5/v8直接用 YOLO 格式最省事如果你要做跨模型对比或者用 MMDetectionCOCO 格式更通用VOC 格式则是很多老代码库的默认输入。提示不要三种格式混着用训练前确认你的 data.yaml 或配置文件指向的标签路径和格式一致。2.2 用 Python 脚本把 VOC 转成 YOLO 格式假设你拿到的数据集里 VOC 标签放在Annotations文件夹图片在JPEGImages你需要生成 YOLO 格式的labels文件夹。下面这个脚本我用了很多次处理 1000 张图大概十几秒。import xml.etree.ElementTree as ET import os from pathlib import Path # 类别映射根据你的数据集实际类别修改 classes [person] def convert_voc_to_yolo(xml_dir, img_dir, out_dir): xml_dir Path(xml_dir) img_dir Path(img_dir) out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) for xml_file in xml_dir.glob(*.xml): tree ET.parse(xml_file) root tree.getroot() # 获取图片尺寸 size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并转为中心点宽高 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) # 写入同名 txt out_file out_dir / (xml_file.stem .txt) out_file.write_text(\n.join(lines)) convert_voc_to_yolo(Annotations, JPEGImages, labels)逻辑说明先解析 XML 拿到图片宽高再把 VOC 的绝对坐标转成归一化的中心点坐标。参数方面classes列表必须和你的数据集类别顺序一致如果只有行人就写[person]。x_center和y_center保留 6 位小数足够YOLO 训练时不会因为精度损失影响收敛。注意有些 VOC 标注里会有difficult字段如果值为 1 表示难样本你可以选择跳过或者保留我一般保留因为航拍场景本身难样本就多丢掉反而降低模型鲁棒性。2.3 COCO 格式的 JSON 结构解析与按需转换COCO 的 JSON 文件包含images、annotations、categories三个核心字段。images里每张图有id、file_name、width、heightannotations里每条标注有image_id、category_id、bbox格式是[x, y, width, height]注意这里是左上角坐标加宽高不是中心点categories里是类别 id 和名称的映射。如果你要把 COCO 转成 YOLO核心就是遍历annotations根据image_id找到对应图片尺寸然后把bbox转成归一化中心点格式。很多开源脚本直接改改就能用但要注意 COCO 的bbox宽高是绝对像素值别搞混了。2.4 划分脚本怎么用训练集、验证集、测试集的比例控制数据集自带的划分脚本通常会把图片和标签按比例分到train、val、test三个文件夹。我一般用 7:2:1 或者 8:1:11000 张图的话训练集 700 到 800 张验证集 100 到 200 张测试集 100 张。如果脚本是按随机种子划分的记得固定种子不然每次跑出来的划分结果不一样实验没法复现。下面是一个简单的划分脚本示例import random import shutil from pathlib import Path def split_dataset(img_dir, label_dir, out_dir, ratios(0.7, 0.2, 0.1), seed42): random.seed(seed) img_dir Path(img_dir) label_dir Path(label_dir) out_dir Path(out_dir) # 只取有对应标签的图片 images [p for p in img_dir.glob(*.jpg) if (label_dir / (p.stem .txt)).exists()] random.shuffle(images) n len(images) n_train int(n * ratios[0]) n_val int(n * ratios[1]) splits { train: images[:n_train], val: images[n_train:n_train n_val], test: images[n_train n_val:] } for split, files in splits.items(): (out_dir / split / images).mkdir(parentsTrue, exist_okTrue) (out_dir / split / labels).mkdir(parentsTrue, exist_okTrue) for img in files: shutil.copy(img, out_dir / split / images / img.name) shutil.copy(label_dir / (img.stem .txt), out_dir / split / labels / (img.stem .txt)) print(f{split}: {len(files)} images) split_dataset(JPEGImages, labels, dataset_split)参数说明ratios控制三个子集的比例seed固定随机种子保证可复现。注意划分前要检查图片和标签是否一一对应缺失标签的图片直接跳过否则训练时 dataloader 会报错。3. 用 YOLOv8 在本地跑通训练环境、配置和第一个 epoch3.1 环境配置避开 CUDA 和 PyTorch 版本不匹配的坑YOLOv8 通过 Ultralytics 包安装命令很简单pip install ultralytics。但这里有个血泪经验——如果你的显卡驱动比较老PyTorch 版本和 CUDA 版本不匹配训练时会直接报CUDA error: no kernel image is available for execution on the device。我一般先确认显卡驱动支持的 CUDA 最高版本然后去 PyTorch 官网找对应版本的安装命令。比如 CUDA 11.8 就用pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118。装完之后跑python -c import torch; print(torch.cuda.is_available())输出 True 才算环境没问题。注意不要盲目装最新版 PyTorchYOLOv8 对某些版本的支持有延迟建议用官方文档推荐的稳定组合。3.2 准备 data.yaml 和目录结构YOLOv8 训练需要一个data.yaml文件里面指定训练集、验证集路径和类别名称。目录结构建议这样组织dataset/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── data.yamldata.yaml内容如下path: ./dataset train: train/images val: val/images nc: 1 names: [person]参数说明nc是类别数行人检测就是 1names是类别名称列表顺序要和标签里的类别索引对应。如果后面你要加类别改这两个地方就行。3.3 启动训练命令行参数怎么设一条命令就能跑起来yolo detect train datadataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 lr00.01逻辑说明modelyolov8n.pt表示用 YOLOv8 nano 预训练权重航拍小目标检测建议从 nano 或 small 开始显存不够就换 nano。epochs100对 1000 张图来说够了太多容易过拟合。imgsz640是输入分辨率如果显存允许可以调到 1280小目标检测效果会明显提升。batch16根据显存调整8G 显存跑 640 分辨率大概能到 16。lr00.01是初始学习率默认值就行如果 loss 震荡厉害可以降到 0.001。训练过程中关注几个指标box_loss和cls_loss是否稳定下降mAP50和mAP50-95是否在验证集上提升。如果box_loss降到很低但mAP不涨大概率是过拟合了可以加数据增强或者减少 epochs。3.4 训练完成后的验证和推理训练结束后权重保存在runs/detect/train/weights/best.pt。用下面的命令在测试集上跑推理yolo detect predict modelruns/detect/train/weights/best.pt sourcedataset/test/images saveTrue结果会保存在runs/detect/predict文件夹。如果想看混淆矩阵和 PR 曲线训练日志里已经生成了直接打开runs/detect/train下的图片就行。航拍行人检测的混淆矩阵通常会出现行人和背景的误判如果误检率高可以适当提高置信度阈值在推理时加conf0.5。4. 避坑指南航拍行人检测训练中最容易翻车的五个地方4.1 标签坐标越界导致训练报错现象训练启动后 dataloader 报IndexError或者AssertionError提示坐标超出 0 到 1 范围。原因VOC 转 YOLO 时有些标注框的 xmax 或 ymax 等于图片宽度或高度归一化后正好是 1.0但某些版本的 YOLO 要求严格小于 1。解决在转换脚本里加一行裁剪x_center min(max(x_center, 0), 1)宽高同理或者把越界框直接过滤掉。4.2 图片和标签文件名不一致导致漏加载现象训练时提示No labels found但明明 labels 文件夹里有 txt。原因图片是.jpg后缀标签是.txt但文件名大小写或者多了空格。解决写个脚本批量检查把图片文件名和标签文件名做交集不一致的打印出来手动改。我一般用path.stem来匹配避免后缀干扰。4.3 小目标检测 mAP 极低模型学不到东西现象训练 loss 正常下降但 mAP50 一直在 0.1 以下。原因航拍行人本身像素就少640 分辨率下可能只有十几个像素高YOLO 的 stride 下采样后特征几乎消失。解决把imgsz调到 1280 甚至 1536或者用 YOLOv8 的 P2 层配置需要改模型结构增加小目标检测头。另一个办法是切片推理把大图切成小图分别检测再合并。4.4 训练中 BN 层崩溃导致 loss 变 NaN现象训练几个 epoch 后 loss 突然变成 NaN或者报RuntimeError: CUDA error。原因batch size 太小或者学习率太高导致 BatchNorm 统计量不稳定。解决把batch调大至少 8 以上或者把lr0降到 0.001还可以在训练配置里加warmup_epochs3让模型先预热几个 epoch 再正常学习。4.5 验证集和测试集分布不一致导致指标虚高现象验证集 mAP 很高但测试集一跑就拉胯。原因划分脚本随机划分时验证集和测试集可能包含了同一段视频的连续帧导致数据泄漏。解决如果数据集来自视频抽帧划分时要按视频片段划分而不是按单张图随机划分。这个坑很隐蔽但影响很大血泪经验。5. 进阶技巧用切片推理和模型融合把航拍行人检测 mAP 再提一截5.1 切片推理把大图切小再检测小目标召回率明显提升航拍图通常分辨率很高直接缩放到 640 会丢失大量小目标信息。切片推理的思路是把原图切成有重叠的小块每块单独推理再把结果映射回原图做 NMS。Ultralytics 官方提供了sahi库来做这件事安装pip install sahi然后from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/detect/train/weights/best.pt, confidence_threshold0.3, devicecuda:0 ) result get_sliced_prediction( test_image.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_diroutput/)参数说明slice_height和slice_width是切片大小一般和训练分辨率一致overlap_height_ratio和overlap_width_ratio是重叠比例0.2 表示相邻切片有 20% 重叠避免目标被切一半。这个方案在航拍行人检测上通常能把 mAP50 提升 5 到 10 个点代价是推理速度变慢适合对精度要求高的场景。5.2 模型融合YOLOv8 和 RT-DETR 的互补YOLO 系列在航拍小目标上已经不错但如果你追求极致精度可以试试把 YOLOv8 和 RT-DETR 的检测结果做加权框融合WBF。RT-DETR 对密集小目标的检测能力更强但速度慢一些。两个模型分别推理然后用ensemble-boxes库做融合from ensemble_boxes import weighted_boxes_fusion # boxes_list 是每个模型的检测框列表格式 [x1, y1, x2, y2] 归一化 # scores_list 是对应置信度labels_list 是类别 boxes, scores, labels weighted_boxes_fusion( boxes_list, scores_list, labels_list, weights[1, 1], iou_thr0.55, skip_box_thr0.3 )参数说明weights控制每个模型的权重如果 YOLO 表现更好可以给 1.2iou_thr是融合时的 IoU 阈值0.55 比较通用skip_box_thr过滤低置信度框。融合后一般能再涨 2 到 3 个点但推理时间翻倍看你的业务能不能接受。5.3 一个我常用的验证习惯每次训练完我不会只看 mAP 数字而是把测试集里 mAP 最低的 20 张图挑出来用predict模式跑一遍肉眼看看漏检和误检长什么样。很多时候 mAP 低是因为某几张图标注质量差或者场景极端把这些图挑出来单独分析比盲目调参有效得多。这个习惯帮我省了很多后悔药也让我对数据集的边界有了更清楚的认识。希望帮到你。本文还有配套的精品资源点击获取