拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

无人机航拍小目标人体检测:数据集制作与YOLO训练全流程

无人机航拍小目标人体检测:数据集制作与YOLO训练全流程

1. 场景拆解与方案选型

1.1 为什么航拍校园操场的人体检测这么难

先说说这个项目真正难在哪。校园操场在航拍视角下,不是我们平时做监控摄像头那种平视画面,无人机在80到120米高度往下看,一个人可能只有40到60个像素那么高,整张4000x3000的大图里,人就是一个个“小点”。这属于典型的小目标检测场景,和COCO数据集里那种占画面一大块的目标完全不是一回事。

操场场景还有几个隐藏的坑。第一是密集,跑操、课间操、运动会这类场景,几百上千人挤在一起,人和人之间的间距可能只有几个像素,检测框需要做到“挨着但不合并”,这对后处理NMS的阈值设置非常敏感。第二是形变和遮挡,航拍视角下人的姿态就是俯视的“圆脑袋加身体”,有时被树木、看台顶棚、甚至其他同学的身体挡住一部分,标注时是否标全严重影响模型学习。第三是背景干扰,操场上的跑道线、球场标线、足球球门阴影、树影,在航拍视角下颜色和纹理都容易和人体混淆。

这就是为什么一个“看起来很简单的人体检测”数据集,做起来其实要花很多工夫。市面上开源的行人检测数据集,比如CityPersons、CrowdHuman,基本都是平视或者俯仰视角,直接拿来用,在操场航拍场景下精度会掉得很难看。自己做数据集,就是为了让模型见过“从天上往下看人”到底是什么样。

1.2 数据集选型与整体方案设计

整个项目我拆成了四个阶段:采集、标注与清洗、增强划分、训练评测。采集阶段定拍摄高度和角度,标注阶段定类别和框的规范,清洗阶段把模糊、遮挡过度的样本筛掉,划分阶段保证验证集和测试集足够“难”,最后才是YOLO训练和调参。

实际上很多初学者一上来就急着标注、急着训练,跳过采集设计,结果模型泛化一塌糊涂。我这个项目里,第一版图省事,只拍了一个角落的垂直视角,结果模型在另一个操场测试时误检率暴涨。后来重新补拍了全操场覆盖、不同高度、不同光照的数据,才把问题压下来。数据集的“多样性”不是一句口号,它会直接变成你最终评测指标里的涨跌。

工具方面,标注用LabelImg,格式直接导出YOLO的txt格式;训练用YOLOv8,因为它在小目标场景下比YOLOv5的默认配置更容易调出效果,而且文档也相对完整。后续如果想进一步提点,可以再加SAHI切片推理,不过第一阶段先把数据集的底子打好。

2. 数据集制作实操全流程

2.1 无人机采集方案:高度、角度与光照

采集这件事,不能随便飞起来拍一段视频就完事。我先规划航线:操场是标准400米跑道,我设定无人机在操场中心上空做环绕和“Z字形”扫描,保证画面覆盖整个场地。高度我做了三档:60米、100米、120米。60米的画面里人还算有点轮廓,适合让模型学“大一点的人”;120米就是纯小目标,用来逼模型在低分辨率下也认得出人。

角度上要区分主视角和辅助视角。主视角是垂直俯视,也就是90度正下方视角,这是航拍操场人体检测最典型的视角;辅助视角包括大约45度到60度的倾斜视角,模拟无人机过境时常见的拍摄姿态。倾斜视角下人的外观变化很大,有了这些样本,模型在真实部署时才不会因为视角偏一点就漏检。

光照方面我分成晴天上午、午后强光、阴天三类。这里分享一个经验:午后强光的阴影很致命,树影和人的影子在俯视图里经常被模型误判成人,我在最终清洗时专门保留了一批带阴影的负样本,帮助模型学会“阴影不是人”。拍摄时间我建议避开正午,除非你故意要采集最难的阴影样本。

注意:视频抽帧时不能只抽连续帧,连续帧之间的目标位置变化太小,模型会学到“死”的特征。我会每隔10到15帧抽一张,保证样本间的场景多样性。

2.2 标注规范:边框画到哪里才标准

标注是整个数据集制作过程中最耗时、最影响模型上限的环节。航拍视角下的人体特征和平视差别很大,平视时人框是从头到脚一个竖长矩形,航拍时大多数人是“头顶的一团”,身体被头挡住大部分,这时候标注框到底该按什么来,必须提前定好规范。

我定的规范是这样的:单人直立或行走时,框选头顶到脚底能看见的最大范围;跑步或做操时身体倾斜,框按最小外接矩形(就是正框,不旋转)包含整个可见人体;被遮挡超过50%的人不标;人群密集无法区分个体边界时,按可见头部和肩部范围标;完全被树木或建筑物挡住的人不标。

有人觉得被遮挡的人也应该标,让模型学会“找半个人”。实际训练下来我的观点是:遮挡超过一半的样本,标注一致性很难保证,今天标头明天标肩,模型反而学得更混乱。不如只标那些“人能明确看出来”的实例,把遮挡严重的样本留给负样本发挥抑制误检的作用。

整个数据集我最后统计了一下:有效图片约5200张,标注个人实例数约18.6万,平均每张图约36个人,最密集的一批跑操图片单张超过190人。类别就一类“person”,纯单类检测,不引入其他类别的复杂性。

2.3 清洗与难例挖掘:宁可少而精,不要多而糙

清洗这一步容易被忽略,但对精度影响极大。我用了一个很土但有效的办法:第一轮训练出yolov8n的小模型,拿它跑全部训练数据,把所有漏检的图片挑出来人工看。漏检的图有两种情况,一种是目标确实太难,比如极端密集、严重遮挡,这种图留下;另一种是标注漏了,模型没学过这个位置的“人”特征,这种图补标。

还有一种“压箱底”的做法是挖难例样本。把所有预测框里置信度在0.3到0.6之间的框导出来,画到图上人工过一遍。这些框多半是误检或定位不准,能把它们归类清楚,模型就知道自己哪里容易“犯浑”。我这么做之后,又补了约500张“困难样本”,包括阴影干扰、密集人群、强反光的亮色衣服,这些难例对模型最后几个epoch的提升至关重要。

数据的标注质量我做了二次校验。具体方法是随机抽10%的图片,让我自己重新标一遍,和第一遍标注做IoU对比,要求IoU大于0.7才通过。实测下来标注团队内部的一致性在0.75到0.85之间,如果低于0.7那说明标注规范本身有歧义,需要调整规则而不是继续往下标。

3. YOLO训练实操与参数解析

3.1 模型选型:YOLOv8s还是YOLOv8m

YOLO的版本选择不用盲目追新。航拍操场这种固定场景,目标类别单一、背景相对固定,网络容量不需要太大。我试过YOLOv8n、YOLOv8s、YOLOv8m三个规格,在同样的数据划分下,n的mAP50大约0.78,s是0.84,m是0.85。m只比s高了0.01但推理速度慢了近一半,所以最终选了s作为主模型。

如果你算力允许,推荐用YOLOv8s起步,最终部署时也够用。YOLOv8m适合做“教师模型”,用蒸馏的方式把精度迁移回s,这是我项目后期正在做的优化方向。

预训练权重方面,直接用YOLOv8官方在COCO上预训练的权重。有同学纠结“COCO没有航拍视角,预训练权重有用吗”,我的答案是很有用。COCO让模型学到了通用的低层特征,比如边缘、纹理、颜色对比,这些特征在航拍图上同样有效。真正需要从头学的是“人的顶视图长什么样”,这是高层语义,靠我们的数据集来教。

3.2 关键训练参数设置与调优思路

训练参数这一块,我直接给出可复现的配置:

  • 输入分辨率:原始图4000x3000,直接丢进去batch会爆,先按1280x1280训练,这个分辨率对小目标检测是必要的。640的输入对小目标实在太不友好,mAP能掉5到8个点。
  • batch size:固定为16,8卡跑的话可以开到64。
  • epochs:200,配合早停patience=30。
  • optimizer:SGD,初始lr=0.01,最后10个epoch用cosine decay降到0.0001。
  • mosaic:前150个epoch开启,后50个epoch关闭。这一点很关键,航拍场景下人和人挨得很近,mosaic把四张图拼在一起后,原本的密集程度被稀释,最后关闭mosaic让模型在真实密集分布下微调。
  • 数据增强只开HSV色偏扰动(hsv_h=0.015,hsv_s=0.5,hsv_v=0.4),平移缩放都保持默认,不要开太大的随机透视,航拍视角本身已经很“正”,过度增强反而引入不真实分布。

这里有个典型的“训练中BN崩溃”问题值得多说一句。如果batch size设太小,比如4或8,BatchNorm统计量不稳定,loss会出现突然跳到NaN的情况。我踩过这个坑,后来把batch稳定在16以上、降低初始学习率到0.005,才解决。你也可以用YOLOv8默认的optimizer配置,但前提是batch足够大。

3.3 损失函数与后处理的几个关键观察

关于YOLO的损失函数,YOLOv8用的还是分类损失和回归损失的加权组合。在航拍小目标场景里,框的回归误差主导了性能瓶颈,因为目标框只有几十个像素,几个像素的偏差就导致IoU掉得很厉害。所以训练时我特别关注了val框的定位精度,而不是只看mAP。如果发现定位普遍偏大或偏小,优先调整的是训练数据集的标注一致性,而不是loss权重。

后处理上,NMS的IoU阈值我调到0.45,置信度阈值在推理阶段用0.15,验证阶段用0.3。密集人群场景里,NMS阈值如果太高,比如0.6,重叠的多个检测框不会合并,会产生大量重复框;阈值太低,比如0.3,相邻的两个人可能被合并掉一个。0.45是我在这个数据分布上试出来比较平衡的值。

对象损失这块还有一个细节:分类置信度和定位精度的关系。我给验证集的每个预测框按置信度排序,画出“置信度-定位误差”曲线,发现误检框的置信度普遍在0.5到0.7之间,而且定位误差也大。这提示模型其实是“瞎猜”,“觉得自己看到了人但不知道在哪”。针对这种情况,我倾向于在损失层面更强调框回归项,也就是适当提高box loss的权重,实测能让高置信度框的定位更稳。

4. 训练过程实测与问题排查实录

4.1 从过拟合到欠拟合:一次完整的训练曲线复盘

第一轮训练我犯了一个新手错误:训练集只有800张图,结果模型严重过拟合,训练loss降到1.2,验证mAP只有0.62,检测框经常缩在图片中心区域,说明模型根本没学到全局特征,只是死记硬背了训练集中的位置分布。

后来我把数据扩充到5200张,过拟合问题才缓解。但紧接着出现了“验证集mAP高、实际场景表现差”的偏差。复盘原因,是验证集划得太“温柔”——全是晴天垂直视角,模型没被考到倾斜视角和阴影场景。重新划分数据集时,我保证验证集和测试集中包含固定的难例比例,大约30%是密集、阴影、倾斜视角样本,这个划分方式比随机划分更能反映真实部署水平。

4.2 常见问题速查表

下面这张表是我在项目过程中不断添加整理出来的,基本覆盖了同类型数据集制作训练时的高频问题,直接贴给你参考:

问题现象可能原因解决方案
小目标大量漏检(特别是远距离人)输入分辨率太低训练分辨率提高到1280,或用SAHI切片推理
把树影、足球门当成“人”训练集缺少阴影负样本补充带阴影的困难样本,经典难例挖取
密集人群的框重叠严重NMS阈值设置不当IoU阈值从默认0.7降到0.45,观察验证集效果
训练loss突然变成NaNbatch太小导致BN崩溃,或lr过高保证batch>=16,初始lr<=0.01
高置信度框定位严重偏移标注边界不统一二次校验标注风格,统一“头到脚”规则
模型在验证集好、实际差验证集划分太乐观验证集/测试集加入30%左右难例
训练mAP一直卡在0.7上不去数据多样性不足补拍倾斜视角或阴天数据,不要盲目加epoch
一个目标产生多个重叠检测框NMS和类别置信度交互不合理检查后处理置信度阈值,适当调高至0.2以上

4.3 模型精度评测与混淆矩阵解读

训练结束后我用测试集做了完整评测。这里特别看一眼混淆矩阵,YOLO的混淆矩阵输出可以帮我们定位“模型把什么错认成了人”。我这个项目是单类检测,所以混淆矩阵主要看两类矩阵单元:一是background被预测成person的比例,也就是误检率;二是person被漏掉的比例。

实测下来,第一版模型的背景误检率最高出现在图片四角和边缘区域,原因是航拍图边缘的人形特征因为畸变被扭曲了。我后来在切片训练时特意让切片之间保留20%的重叠,这部分误检大幅减少。另外,跑操时的人因为速度产生运动模糊,漏检率比静止站立的人高约12%,我在标注时把运动模糊的人框尽量画在轮廓最清晰的帧上,漏检率才降下来。

在YOLOv8提供的分类报告中,我还关注了不同图片高度下的分桶精度。按目标像素面积把测试目标分成三档:小于32x32、32x32到96x96、大于96x96,三档的召回率分别约为0.71、0.89、0.94。这个分桶结果说明小目标仍然是最主要的性能瓶颈,这也是我下一步计划引入SAHI切片推理的直接依据。

5. 项目复盘与几点实用建议

项目做到这个阶段,我的核心体会是:航拍场景的人体检测,数据集的“拍摄视角一致性”比数据量更重要。5000张图如果全部是同一高度同一角度拍出来的,效果不如3000张但覆盖多种高度、角度、光照的图。我在中间补拍数据后模型提升最明显,就是这个原因。

另外想强调一下数据版本的迭代管理。数据集的更新不能“悄悄改”,每次改动标注规则、增删图片,都必须冻结验证集和测试集。否则你无法判断模型变好是因为网络优化,还是因为验证集变简单了。我习惯用固定哈希来命名数据集版本,比如dataset_v2.3_20240511,每次训练记录里都带上版本号,回头排查问题会省很多时间。

最后一个小技巧:做标注时如果感觉进度太慢,可以先训练一个粗模型,用模型预测结果生成预标注框,人工只需要修正错框和漏框。这个流程能把标注效率提升大约2到3倍,而且标注质量往往还更高,因为人只需要看“哪里不对”,比从零画框的心理负担小很多。我自己后期补标难例样本时,就是靠这个方法在两三天内完成了近千张图的迭代更新。

做完这个数据集,我最大的收获不是那套YOLO权重,而是搞明白了一个道理:模型的上限在标注阶段就已经确定了,训练只是在尽量逼近这个上限。所以如果你也想做航拍人体检测,不用急着折腾各种网络结构,先把数据集做扎实,后面的一切都会顺利得多。

返回列表