简介:面向无人机视觉与计算机视觉研究者、开发者的行人检测数据集,旨在为无人机航拍场景下的行人识别与避障提供高质量训练材料。整个压缩包共1895个文件,包含630张jpg原图、630个xml边界框标注、634个txt标签说明,并附1个py预处理/转换脚本,包体约206.8MB。数据已划分训练集、测试集和验证集,图像与标注一一对应,覆盖从数据准备、格式转换到模型训练、评估的完整链路,可直接用于YOLO、Faster R-CNN、SSD等主流检测框架,免去自行采集和标注的繁琐工作。读者既能据此验证航拍视角下的检测效果,也能通过对比实验分析不同模型性能,同时学习PASCAL VOC风格标注与txt标签的组织方式。目前已有3956人学习下载,适合无人机巡检、安防监控、智慧交通等场景下的算法研究与工程实践。
1. 无人机行人检测数据集:标注好了不等于直接能用,关键看这四件事
一个“已标注”的无人机行人检测数据集,听起来像是拿到了现成的答案:解压、训练、出模型,三步走完。但我在本地跑过几个公开渠道能找到的无人机视角行人检测数据集之后,最大的感受是:标注好只是起点,能不能让模型真的在无人机画面上把人检出来,取决于标注质量、视角分布、目标尺寸和场景覆盖这四件事。这也是为什么同样用“已标注”的数据集,有人三天跑出能用的模型,有人折腾两周还在跟漏检和误检搏斗。
这篇文章要解决的,就是把你从“拿到数据集”带到“模型能落地”这段路。适合正在做无人机巡检、安防监控、智慧城市相关项目的开发者,也适合刚入门目标检测、想用现成数据集快速验证算法思路的同学。我会从数据集的构成和标注规范讲起,然后给出一套从数据校验到模型训练的可复现流程,最后把高手才会注意的边界条件和踩坑点拆开讲。
2. 数据集构成与标注规范:先弄清楚“已标注”到底标注了什么
拿到任何一个“已标注”的无人机行人检测数据集,第一件事不是解压跑脚本,而是先看清楚它的目录结构和标注格式。很多翻车现场都是从这里开始的:看起来是同一套标注格式,实际用的时候才发现坐标系统、类别编号、图片尺寸记录方式对不上,白白浪费一下午。
2.1 数据来源与场景分布:先判断它适不适合你的任务
无人机视角的行人检测和普通监控摄像头视角有本质区别。监控摄像头大多是俯仰角固定、目标尺度相对稳定;无人机是俯视视角,行人在画面里通常是小目标,占比不到整张图的百分之几,而且会随飞行高度和速度发生剧烈的尺度变化。数据里如果大多数图片的拍摄高度在30米以下、行人占比大,那你拿去做50米高度的巡检任务就会出现明显漏检。
我一般拿到数据集先做三件事:统计图片分辨率分布、统计标注框面积分布、统计每张图的平均目标数。这三个数字直接决定这个数据集适不适合当前任务。标注框面积分布特别值得看——如果绝大多数框的长边小于64像素,训练时需要重点考虑小目标检测策略;如果数据和实际作业高度落差太大,优先找同场景的数据集或者自己补采。
2.2 标注格式与目录结构:VOC、YOLO还是COCO
常见的无人机行人检测数据集有三种标注形态:Pascal VOC格式的XML文件、YOLO格式的TXT文件、COCO格式的JSON文件。三种格式的坐标表达方式不同:VOC和COCO都是绝对像素坐标且用xmin、ymin、xmax、ymax这类方式记录;YOLO格式用的是归一化的中心点坐标和宽高。图片尺寸记录这件事也容易踩坑,VOC的XML里带有图片宽高,可以直接校验;YOLO的TXT不带尺寸信息,如果原始图片被缩放,标注坐标会全军覆没。
我习惯用下面这条命令先摸清目录结构,再决定怎么下手:
# 查看数据集目录树,限制层级为3 cd dataset_root tree -L 3 -d # 统计图片数量、XML/TXT/JSON标注文件数量 find . -name "*.jpg" | wc -l find . -name "*.xml" | wc -l输出结果能告诉你数据集是原始结构还是已经做了划分。如果是划分好的,通常有train、val、test三个目录,但不少数据集只分了两部分,需要自己再切一次验证集。
# 统计标注框尺寸分布的Python脚本片段 # 这里按照YOLO格式的txt标注为例 import os from collections import Counter img_width, img_height = 1920, 1080 size_bins = Counter() label_dir = "labels/train" for f in os.listdir(label_dir): if not f.endswith(".txt"): continue with open(os.path.join(label_dir, f)) as fp: for line in fp: _, cx, cy, w, h = line.strip().split() pixel_w = float(w) * img_width pixel_h = float(h) * img_height if pixel_w < 32 or pixel_h < 32: size_bins["tiny"] += 1 elif pixel_w < 96 or pixel_h < 96: size_bins["small"] += 1 else: size_bins["large"] += 1 print(size_bins)这段脚本的关键作用是:提前暴露目标尺度分布。如果tiny类占比超过一半,后面训练必须启用多尺度训练和更高分辨率的输入图。代码里img_width和img_height需要改成你手里数据的真实值,不确定的话用Python的PIL库批量读取一张图确认。标注文件的格式如果是VOC或者COCO,解析逻辑要相应改成XML或JSON取值,但判断思路是一样的。
3. 把数据集跑起来:从解压到可视化校验的一条龙操作
数据集的目录结构摸清了,标注格式也确认了,接下来不能直接进训练。先做可视化校验,这是整个流程里最便宜的一道后悔药:把标注框画到原图上,人眼看一遍,就能发现坐标偏移、类别错标、框没贴住目标这些问题。省下的是后面训练半天发现loss不下降的排查时间。
3.1 先做数据划分与文件完整性检查
训练前一定要划分数据。不要直接拿所有图片训练,否则你连模型过拟合还是欠拟合都判断不了。常见做法是训练集、验证集、测试集按7:2:1划分。如果数据集本身划分好了,检查一遍文件是否齐整——图片和标注文件一一对应是这步的重点。
# 检查图片与标注文件是否一一对应 import os from pathlib import Path def check_pairs(img_dir, label_dir): imgs = {Path(f).stem for f in os.listdir(img_dir) if f.endswith((".jpg", ".jpeg", ".png"))} labels = {Path(f).stem for f in os.listdir(label_dir) if f.endswith(".txt")} img_only = imgs - labels label_only = labels - imgs print(f"缺标注的图片数: {len(img_only)}") print(f"缺图片的标注数: {len(label_only)}") # 打印前5个缺标注的图片名方便定位 for name in list(img_only)[:5]: print("missing label:", name) check_pairs("images/train", "labels/train")这段代码用意是暴露配对问题。很多数据集从网盘下载后会出现文件缺失或文件名被截断,直接用完整的数据集训练会让模型在加载时报错或者默认跳过某些图片。缺标注的图片一定要从训练集里剔除,否则训练过程中会随机报错,而且报错信息往往不直观,只显示一个DataLoader worker崩溃。
剔除缺标注图片的方法不复杂,把上面脚本里img_only里的文件移到另一个目录,或者生成一个保留清单。我一般直接把训练清单写成文本,训练脚本读取这个清单来加载图片,这样比物理移动文件更灵活,后面增删样本也方便。
3.2 用可视化脚本给标注框画出来:坐标对不对一眼便知
校验标注正确性最快的方式就是画框。下面这段脚本读取YOLO格式标注并画在图上,输出到preview目录。代码里做了坐标越界判断,这是从踩坑里学来的:不少数据集的标注框有极小概率越界,如果不加保护,后续变成COCO或VOC格式时数值会异常。
# 可视化YOLO标注,输出效果预览图 import cv2 import os import numpy as np def draw_yolo_boxes(img_path, label_path, out_dir): img = cv2.imread(img_path) h, w = img.shape[:2] colors = [(0, 255, 0), (0, 0, 255), (255, 0, 0)] with open(label_path) as fp: for line in fp: parts = line.strip().split() if len(parts) != 5: continue cls = int(parts[0]) cx, cy, bw, bh = map(float, parts[1:]) # 反归一化还原像素坐标 x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) # 越界裁剪 x1, y1 = max(0, x1), max(0, y1) x2, y2 = min(w, x2), min(h, y2) cv2.rectangle(img, (x1, y1), (x2, y2), colors[cls % len(colors)], 2) cv2.putText(img, f"cls-{cls}", (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[cls % len(colors)], 1) os.makedirs(out_dir, exist_ok=True) cv2.imwrite(os.path.join(out_dir, os.path.basename(img_path)), img) # 遍历前50张训练图做预览 img_dir = "images/train" label_dir = "labels/train" for i, fname in enumerate(os.listdir(img_dir)): if i >= 50: break stem = os.path.splitext(fname)[0] lbl = os.path.join(label_dir, stem + ".txt") if os.path.exists(lbl): draw_yolo_boxes(os.path.join(img_dir, fname), lbl, "preview")从预览图里最容易发现的几个问题:框整体偏移说明坐标归一化基准不对,某些框宽高为0说明标注文件损坏,类别编号大量超出预期说明数据集里可能混入了其他类别的样本。这批预览图务必肉眼过一遍,至少抽看训练集、验证集、测试集各一部分。我见过有人在这个环节发现整个数据集的标注都没有贴住行人,而是框住了背景,这种问题不提前发现,训练再久也不会有好结果。
4. 用数据集训练检测模型:完整流程与关键参数
校验没问题,就到了正式训练环节。多数人拿到“已标注”的无人机行人检测数据集,目标是把模型训练到一个能用的水平。这个部分我以YOLO系列为例展开,这也是目前无人机目标检测里最主流的方案,兼顾速度和精度。训练流程上,覆盖从选模型到判读训练曲线的完整路径。
4.1 模型选型与数据格式适配
模型选型的核心逻辑是:算力有限就优先考虑YOLO系列的轻量版本;需要极致精度且推理设备允许大模型,再往上加。无人机场景通常是在嵌入式设备或者边缘计算盒子上跑推理,参数规模太大会带来帧率压力。经验值是:在30万像素级别的输入分辨率下,轻量版能做到实时,标准版有明显精度优势但速度下降明显。
数据格式适配这一步,是把第3章校验通过的YOLO格式TXT和图片组织成训练框架要求的目录结构。不同框架对数据组织方式要求不同,但训练集和验证集的图、标分别放两个目录是最通用的做法:
# YOLO系训练框架通用的数据目录布局 datasets/ drone_person/ images/ train/ # 训练集图片 val/ # 验证集图片 labels/ train/ # 训练集标注txt val/ # 验证集标注txt data.yaml # 数据配置文件data.yaml是训练入口,里面记录类别数、类别名和路径。写这个文件时有个高频坑:路径最好写绝对路径,或者使用相对当前工作目录的路径,不要写一个看起来对但实际不存在的路径。
# data.yaml 内容示例 path: /home/user/datasets/drone_person train: images/train val: images/val nc: 1 names: ["person"]这个文件的难点不在格式,在于理解path字段的基准意义。很多框架会基于path拼接train和val的路径,如果你把train写成/home/user/datasets/...这种绝对路径,框架会拼出一串错误的地址。建议先写相对路径images/train,然后在命令行验证路径拼接结果。框架启动时会打印实际加载的图片路径,扫一眼就能确认。
4.2 训练启动与参数调整
训练启动命令看着简单,但参数怎么设直接决定结果上限。我常用的训练命令如下:
# 以YOLO系框架为例启动训练 yolo train \ model=yolov8s.pt \ data=data.yaml \ epochs=100 \ imgsz=1280 \ batch=16 \ lr0=0.01 \ mosaic=0.5逐个说参数考虑:imgsz=1280是应对无人机小目标的关键设置。很多现成教程默认给640,但无人机画面里的行人只有几十个像素,分辨率太低会直接抹掉细节。显存够就上1280,不够就降到960。mosaic=0.5是马赛克增强的概率,无人机行人数据集如果场景比较单一,把增强概率降下来能避免训练分布和真实分布偏离太多。lr0初始学习率,0.01是一个稳妥起点,如果训练曲线震荡明显就降到0.005。
# 训练后验证模型效果 yolo val \ model=runs/detect/train/weights/best.pt \ data=data.yaml这里的best.pt是训练过程中在验证集上精度最高的模型权重,不是最后一轮的last.pt。用best做验证能反映真实可用精度。验证输出里主要看mAP50、mAP50-95这两个指标。对无人机行人检测来说,mAP50的意义更大,因为行人检测的判断标准通常框得差不多就行,不需要像素级精确;mAP50-95考察的是更严格的框质量,如果这个数值过低而mAP50不低,说明模型的框定位偏粗糙,可以考虑在后续迭代里调整回归损失的权重。
4.3 训练曲线的判读方法
训练过程输出两张关键曲线:loss曲线和验证指标曲线。loss曲线里,训练loss下降而验证loss不降反升,是过拟合的典型信号;两个loss都在下降但速度很慢,大概率是学习率太小或者数据增强过重。验证指标曲线里,mAP50在前20个epoch快速上升、后面缓慢爬升是正常节奏,如果前10个epoch完全没有上升迹象,回查数据yaml和标签格式可能更高效。
我一般会盯着前20个epoch的loss曲线做判断,而不是等100个epoch全跑完。前20轮如果训练loss和验证loss同步下降,这组参数就是健康的,让它继续跑就行;如果验证loss在20轮内出现了持续上升,就可以直接停掉调参,不浪费后面的几十轮时间。这也是遇到过太多次训练数小时、结果发现标签坐标是反的过程之后养成的习惯。
5. 无人机行人检测避坑指南:五个高频问题与排查路径
这个数据集方向上,几乎每个坑都会让训练时间翻倍。以下五条是从实际操作里反复踩出来的,每条都按现象、原因、解决三个层次来写。
5.1 小目标漏检严重,模型几乎对远处的行人无感
现象:训练后的模型对近距离行人检测效果尚可,但画面里的远距离行人大量漏检,甚至完全不报。验证集上mAP50不低,但实际飞高之后效果立刻劣化。
原因:训练数据里小目标样本占比高,但模型输入分辨率不足,网络下采样后小目标特征被卷积层抹掉了。多数模型的下采样倍率是32倍,输入640时,一个32像素的行人在最终特征图上只有1个像素点,几乎不可能被检出。
解决:三步走。第一步把imgsz提升到1280,让同样一个行人占据更多像素;第二步开启多尺度训练,让模型见过不同尺寸的行人;第三步如果仍然漏检,用基于锚点的检测头并单独调高小目标层的权重。
5.2 标注框和图片分辨率对不上,坐标明显偏移
现象:可视化预览时,所有框集体向左上偏移,而且远处小目标的框偏得格外明显。
原因:数据集里图片原始分辨率是4000x3000,但标注坐标是基于缩略图1500x1000做的,训练时直接读取原始图片导致坐标换算错误。这类问题在从网盘下载的多个来源混合数据集里特别常见。
解决:检查图片的真实尺寸并用它作为反归一化的基准。不要信文件命名里的尺寸信息,用Python的PIL或OpenCV读一遍。如果发现混用,批量将图片统一缩放到标注坐标对应的尺寸,或者把标注坐标重新换算到图片实际尺寸。
5.3 负样本太少,误检成群出现
现象:模型把屋顶、车辆、树冠频繁识别成行人,而且误检位置集中在某些特定纹理区域。
原因:数据集中绝大多数图片都包含行人,纯背景帧几乎没有。模型学到的是“有纹理的局部区域像行人”,而不是真正区分行人的结构特征。
解决:从无人的巡检视频里抽帧,加入20%到30%作为负样本,标注文件留空即可。这是成本最低又最有效的防误检手段。加入负样本后,模型会学会“在没有行人时输出空检测”,而不是硬找出一个框。
5.4 类别不平衡导致训练不收敛
现象:损失函数持续震荡,验证mAP在一两个点之间来回跳,模型输出的类别概率倾向于某一类(比如背景类)。
原因:数据集中某些类别样本极少,检测头对这类目标的梯度贡献被大类别淹没。在行人数据集里这往往表现为“行人和骑行的人混在一起但其中一类数量很少”。
解决:最简单的做法是给不同类别设置不同的loss权重,或者在采样器里做类别重采样。另一个可行方案是把稀有类别合并到大类别里——如果你的任务不要求区分这两个子类,合并是更务实的做法。
5.5 训练集和验证集分布不一致
现象:训练loss下降漂亮,验证集mAP也很高,但模型在真实场景里表现稀烂。换了一批图片测试后精度掉了一半以上。
原因:数据划分时没有做随机化,或者是按时间顺序切分,导致验证集和训练集场景高度相似,验证结果虚高。更隐蔽的情况是:如果数据集里包含同一个场景的连续帧,随机划分会让相似的画面同时出现在训练集和验证集,严重的“数据泄露”会让指标失真。
解决:按视频序列划分数据,同一个视频来源的帧只能出现在一个集合里。只需要在划分前按文件名前缀分组,再对组进行划分,就能避免这个问题。这样评估结果才真正反映模型面对新场景时的表现。
6. 把数据集的价值最大化:三个让模型更进一步的技巧
当你已经在“已标注”的数据集上跑通了基线模型,接下来这三个技巧能让模型的实用性和精度再上一个台阶。这三个技巧用到最多的场景,是模型已经能用、但距离实际作业要求还差一口气的时候。
第一个技巧是多尺度训练与推理联动。训练时开启多尺度,每轮迭代随机从某个尺度范围内采样输入尺寸,让模型适应行人尺度的变化。推理时用TTA(测试时增强),把原图和缩放后的图分别送进模型推理再融合结果。这个组合能让小目标检测的mAP提升大约3到5个点,代价是推理耗时增加。实测中,TTA对无人机场景的收益特别明显,因为行人的绝对尺寸在飞行高度变化时会剧烈波动。
第二个技巧是利用伪标注迭代优化。把已训练模型拿到目标场景的新视频上跑一遍推理,得到一批带置信度的检测结果,人工筛选高置信度框作为伪标注加入训练集。这个过程能显著提升模型在新场景的适应能力。筛选标准要高,置信度至少0.8以上,并且经过人工抽检确认。一轮伪标注迭代大约能让新场景的recall提升10%以上。我在项目中试过用这个方法让模型的场景迁移成本降低了七成,但要注意每轮迭代后都要重新划分数据集,避免数据泄露。
第三个技巧是可视化特征图来定位失败原因。训练结束后,选取一张漏检图片,把网络中间层的特征图可视化出来,观察小目标区域在网络深层是否还有响应。如果响应微弱,说明网络在这个尺度上已经丢失了目标信息;如果响应强烈但最终输出没有框,则问题多半出在检测头或者后处理阶段。这类排查比盲调参数高效得多,能直接把优化方向从“玄学调参”变成“针对修复”。
我自己的教训是:每次拿到新数据集,先花一个小时做第2、3章的校验,再开始训练,这样后面省下的时间通常是三倍以上。哪怕数据是官方发布的“精品数据集”,也值得走一遍这个流程。希望帮到你。
本文还有配套的精品资源,点击获取