☰
无人机航拍行人检测数据集:1000张图三套标签与YOLO训练全流程
2026/9/29 1:51:55 网站建设 项目流程

简介:这份资源面向无人机航拍场景下的行人检测任务,适合从事目标检测学习、课程设计或相关项目开发的中初级读者使用。数据集包含1000张真实航拍图片,场景丰富,均经labelimg精细标注,并同步提供voc、coco与yolo三种格式标签,可直接接入YOLO系列模型训练,省去格式转换的繁琐步骤。压缩包共2000个文件,以xml标注、txt标签为主,另含少量html教程、py脚本与yaml配置文件,整体约376MB,目录划分清晰,便于按格式取用。资源还附赠数据集划分脚本,可自行生成训练集、验证集与测试集,并配套YOLO环境搭建及训练案例教程,覆盖Windows与Linux两种平台,帮助读者快速跑通从环境配置到模型训练的完整流程。目前已有1120人学习下载,适合需要快速验证算法或搭建检测基线的人群参考使用。

1. 无人机航拍行人检测数据集:1000 张图、三套标签与一条能跑通的训练链路

拿到一份无人机航拍行人检测数据集,最怕的不是图少,而是标签格式对不上、划分方式说不清、训练脚本跑不起来。这份资源给的是 1000 张无人机视角航拍图,配套 VOC、COCO、YOLO 三种格式标签,外加划分脚本和训练教程。它解决的核心问题很具体:让你不用从零标注、不用自己写格式转换、不用猜目录结构,直接把数据喂进 YOLO 训练流程。适合做无人机视觉、安防巡检、人群计数、边缘部署验证的从业者,也适合想跑通一个完整检测项目的新手。下面按「数据长什么样 → 怎么转、怎么划、怎么训 → 坑在哪 → 怎么验证」的顺序拆开讲。

2. 三种标签格式的差异与选型:VOC、COCO、YOLO 到底该用哪套

2.1 三种格式的字段结构对比

同一批图,三种标签格式描述的是同一件事,但组织方式完全不同。VOC 是每张图一个 XML,坐标用左上角与右下角的绝对像素值;COCO 是一个大 JSON,所有图、所有框、类别都塞在一起,坐标是[x, y, width, height]绝对像素;YOLO 是每张图一个 txt,每行class x_center y_center width height,全部归一化到 0~1。选型不是看哪个高级,而是看你的训练框架吃什么。

格式文件组织坐标类型类别位置典型用途
VOC每图一个 XML绝对像素 xmin/ymin/xmax/ymaxXML 内 name 字段老版检测框架、标注工具交换
COCO单个 JSON绝对像素 x/y/w/hcategories 数组评测、多任务、实例分割
YOLO每图一个 txt归一化中心点+宽高行首 class idYOLO 系列直接训练

如果你用的是 Ultralytics 系的 YOLO,直接走 YOLO 格式最省事;如果要做 COCO mAP 评测或接别的框架,COCO JSON 更通用;VOC 更多是中间交换格式,标注工具导出常用它。这份资源三套都给,意味着你不需要自己写转换,但需要知道每套的目录该怎么摆。

2.2 目录结构怎么摆才不会被框架拒收

YOLO 训练对目录结构有硬要求,摆错了不会报「格式错误」,而是直接找不到图或找不到标签。常见做法是:

dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml

images/train和labels/train必须同名对应,图001.jpg对应标签001.txt。data.yaml里写清train、val路径和nc、names。很多人把 VOC 的 XML 和 YOLO 的 txt 混在一个目录里,框架会优先找 txt,找不到就跳过,最后训练集实际数量对不上,这是最常见的翻车点之一。

2.3 用划分脚本把 1000 张图切成 train/val

资源里带了划分脚本,核心逻辑就是按比例随机分,同时保证图与标签同步移动。如果你要自己写或改,参考下面这段:

import os, random, shutil # 原始目录:images 和 labels 平级,文件名一一对应 img_dir = "raw/images" lbl_dir = "raw/labels" out_dir = "dataset" val_ratio = 0.2 random.seed(42) # 固定种子,保证可复现 names = [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(".jpg")] random.shuffle(names) val_count = int(len(names) * val_ratio) val_names = set(names[:val_count]) for split in ["train", "val"]: os.makedirs(f"{out_dir}/images/{split}", exist_ok=True) os.makedirs(f"{out_dir}/labels/{split}", exist_ok=True) for n in names: split = "val" if n in val_names else "train" shutil.copy(f"{img_dir}/{n}.jpg", f"{out_dir}/images/{split}/{n}.jpg") shutil.copy(f"{lbl_dir}/{n}.txt", f"{out_dir}/labels/{split}/{n}.txt") print(f"train={len(names)-val_count}, val={val_count}")

逻辑说明:先收集所有图名,固定seed后打乱,按val_ratio切出验证集,再按 split 把图和标签成对复制。参数说明:val_ratio一般 0.1~0.2,1000 张图取 0.2 就是 800 训练、200 验证;seed必须固定,否则每次划分不同,实验无法对比。注意标签缺失的图要提前过滤,否则复制阶段会直接抛FileNotFoundError。

3. 从 VOC/COCO 转到 YOLO:转换脚本与四个边界坑

3.1 VOC XML 转 YOLO txt 的完整脚本

VOC 转 YOLO 的核心是读 XML 里的size拿到图宽高,再把xmin/ymin/xmax/ymax转成归一化中心点和宽高。下面这段可以直接抄:

import os, xml.etree.ElementTree as ET classes = ["person"] # 按你的 data.yaml 顺序改 cls_map = {c: i for i, c in enumerate(classes)} def voc_to_yolo(xml_path, out_txt): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") w = int(size.find("width").text) h = int(size.find("height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in cls_map: continue 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) # 归一化中心点与宽高 xc = (xmin + xmax) / 2.0 / w yc = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{cls_map[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}") with open(out_txt, "w") as f: f.write("\n".join(lines)) for f in os.listdir("voc_xml"): if f.endswith(".xml"): voc_to_yolo(f"voc_xml/{f}", f"labels/{f.replace('.xml', '.txt')}")

逻辑说明:逐 XML 解析,过滤非目标类别,按图宽高做归一化,输出 YOLO 行。参数说明:classes顺序必须和data.yaml的names完全一致,否则类别 id 会错位;坐标保留 6 位小数足够,再多没意义。常见做法是先跑一遍统计每类框数,确认没有类别被过滤光。

3.2 COCO JSON 转 YOLO 的注意点

COCO 转 YOLO 多一层映射:images数组给图宽高,annotations给image_id、category_id、bbox。坑在于 COCO 的category_id不一定是 0 起始连续,而 YOLO 要求从 0 开始连续。必须先建category_id -> 连续 id的映射,不能直接拿原 id 用。另外 COCO 的bbox是[x, y, w, h]绝对像素,转归一化时除以图宽高即可,不需要再算 xmax/ymax。

3.3 四个边界坑:越界、空标签、类别错位、文件名不匹配

  • 越界框:VOC 标注里偶尔出现xmax大于图宽,归一化后大于 1,YOLO 训练会报错或直接忽略。解决:转换时min(max(xc,0),1)夹紧,或直接丢弃该框。
  • 空标签:某张图没有目标,VOC 里没有object,转出来是空 txt。YOLO 允许空 txt 表示背景图,但如果你不想要背景图,要在划分前过滤掉。
  • 类别错位:classes顺序和data.yaml不一致,训练出来的类别名全错。解决:两边用同一个列表生成。
  • 文件名不匹配:图是001.jpg,标签是001.JPG.txt或001.xml没改名。解决:转换后统一os.path.splitext取主干再拼.txt。

提示:转换完先跑一遍校验脚本,统计每张图的框数、坐标范围、类别分布,比直接开训省时间。

4. 训练教程落地:data.yaml、超参与第一次跑通

4.1 data.yaml 怎么写才不报错

YOLO 训练第一步就是读data.yaml,写错路径或类别数,报错信息往往很模糊。标准写法:

path: /abs/path/to/dataset train: images/train val: images/val nc: 1 names: ["person"]

path用绝对路径最稳,train/val相对path写。nc必须等于names长度,行人检测通常就是 1 类。如果nc写成 0 或和 names 对不上,训练会直接崩在数据加载阶段。

4.2 第一次训练命令与关键参数

yolo detect train \ data=dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/drone_person

参数说明:model用预训练权重比从零训收敛快得多;imgsz=640是常见起点,无人机图如果目标很小可以试 960 或 1280;batch=16看显存,不够就降到 8;lr0=0.01是默认起点,小数据集可以降到 0.005;patience=20表示 20 轮没提升就早停。第一次跑建议先epochs=10验证链路通不通,再拉长。

4.3 训练中该盯哪些指标

训练日志里重点看三样:box_loss是否稳定下降、mAP50是否上升、cls_loss有没有突然飙高。box_loss不降通常是学习率太大或标签有问题;mAP50卡住可能是数据太少或目标太小;cls_loss飙高常见于类别 id 错位。混淆矩阵如果出现某类全错,回去查data.yaml的names顺序。

5. 避坑与排查:训练不收敛、标签错位、显存爆掉的真实记录

5.1 现象:训练 loss 一直不降,mAP 接近 0

原因:标签坐标没归一化,或者归一化除了错误的宽高。VOC 转 YOLO 时如果误用了size以外的尺寸,坐标会整体偏移。解决:随机抽 5 张图,用脚本把 YOLO 框画回图上,肉眼确认框位置对不对。这一步比看 loss 曲线快得多。

5.2 现象:训练报「no labels found」

原因:labels/train目录不存在,或 txt 文件名和图名不一致,或data.yaml里train路径写成了图片目录但框架按标签目录找。解决:确认images/train和labels/train同级且文件名主干一致,data.yaml的train指向images/train,框架会自动替换成labels/train。

5.3 现象:显存爆掉,batch 降到 1 还报 OOM

原因:imgsz太大,或workers太多导致内存泄漏,或用了大模型。解决:先把imgsz从 1280 降到 640,workers设 2~4,batch设 8;还不行换yolov8n这种小模型。无人机图目标小想保分辨率,可以试imgsz=960配batch=4。

5.4 现象:验证集 mAP 很高,实际推理全错

原因:训练集和验证集划分时图与标签没同步,验证集标签对不上图;或者验证集里全是简单样本。解决:重新用固定 seed 划分,确认每张 val 图都有对应 txt,且 val 里包含不同场景。常见做法是划分后统计 val 的框数分布,和 train 对比。

5.5 现象:类别名显示成 0、1 而不是 person

原因:data.yaml的names没写或写成了数字。解决:names: ["person"]必须是列表,顺序和转换时的classes一致。推理时框架按names索引显示,索引对不上就显示 id。

6. 进阶验证:用混淆矩阵和单图推理确认数据集真的能用

训练跑完不等于数据没问题。我一般会做两步验证。第一步看混淆矩阵,runs/drone_person/confusion_matrix.png里如果 person 行大部分落在 person 列,说明类别没串;如果大量落到 background,说明漏标或框太小。第二步抽 10 张验证图做单图推理,把预测框和真实框叠一起看:

yolo detect predict \ model=runs/drone_person/weights/best.pt \ source=dataset/images/val \ conf=0.25 \ save_txt=True \ project=runs/val_check

conf=0.25是常用阈值,save_txt=True会把预测结果存成 YOLO 格式,方便和真实标签逐行对比。重点看小目标:无人机航拍行人往往只占几十像素,如果imgsz设小了,小目标召回会明显掉。可以做一个简单统计,把真实框面积小于 32×32 的挑出来,看预测里漏了多少。如果漏检集中在小框,优先提imgsz而不是加数据。

还有一个容易被忽略的点:1000 张图对行人检测来说不算多,如果场景单一,模型很容易过拟合。验证时除了看 mAP,还要看训练集和验证集的 loss 差距,差距过大就是过拟合信号,可以加增强或减 epoch。从那以后我每次拿到新数据集,都强制先跑一遍「画框验证 + 混淆矩阵 + 小目标统计」这三步,再决定要不要开长训练。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询