ARTICLE DETAIL

资讯详情

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

航拍校园操场人体检测实战:从数据采集到YOLOv8部署

航拍校园操场人体检测实战:从数据采集到YOLOv8部署 1. 场景分析与数据需求梳理做航拍校园操场人体检测这个项目最先要搞明白的不是模型怎么选而是你到底在解决一个什么样的问题。我一开始接到这个需求时差点直接拿公开的COCO数据集去微调后来看了航拍样本才意识到地面视角和人头朝下的俯拍视角完全是两个世界。1.1 航拍视角下的人体检测难点无人机在高空往下拍画面里出现的人体特征和普通监控或手机拍摄的侧视角差很远。我做了几次飞行测试后发现最明显的差异集中在三个方面。第一是目标的尺度问题。操场上一整片学生集合在画面里每个人可能只有几十个像素大小远小于COCO数据集中常见的数百甚至上千像素的检测框。小目标不仅特征少而且在下采样过程中很容易被特征图忽略这也是为什么直接拿普通YOLO权重在航拍上跑漏检率会高到离谱。第二是视角带来的外观简化。俯拍视角下人的头肩特征明显但四肢轮廓往往被压缩成一片颜色团块加上衣服颜色接近地面跑道、草地、塑胶场地的颜色单纯靠色块区分的难度非常大。这个和我们平时在平视视角看到的“人”的语义信息差别很大模型需要重新学习特征关联。第三是密集遮挡问题。操场上的活动往往是成群结队人体之间相互遮挡的案例非常多。好几个目标挤在一起检测框重叠度很高常规的NMS阈值如果不调整很容易把两个紧挨着的人合并成一个框或者漏掉其中一个。1.2 校园操场场景的独特性普通航拍人体检测数据集大多来自城市街道、广场或者自然场景校园操场又有自己不一样的地方。操场地面通常有非常明显的标志线比如白色跑道线、足球场中线、禁区线等这些线在俯拍图像里是强几何特征很容易被模型误认为边界或者小型目标。操场周围一般还有看台、围栏、树木、教学楼的一角这些背景元素在一天不同时段会产生变化很大的阴影。早晨和傍晚人身的影子会拉得很长影子有时会连接多个目标光照方向影响阴影的形状让模型的特征提取产生混乱。还有一个不太容易被注意到的点操场上的人群分布不是均匀的。做课间操或者体育课集合时人群呈矩阵状分布自由活动时人群呈散点状分布比赛时人群会集中到某个区域。这种空间分布的非均匀性要求在采集数据时不能只盯着一类场景否则训练集里人群分布模式单一模型在另一种模式上就很容易表现不佳。基于这些特点我放弃了直接拿网上的航拍数据集来顶替的方案。网上的航拍人体数据集多来自无人机航拍的城市街道或野外场景背景纹理、目标密度和校园操场差异太大迁移效果很难保证。就算能用预训练权重做迁移学习数据分布差异太大也容易导致模型训练发散。所以稳妥的做法还是自建一套“航拍校园操场”专属数据集虽然前期工作量大了不少但后期踏踏实实。1.3 数据集规模与标注策略确定我一开始按照目标检测的一般经验准备收集5000张左右的图片。实际采集后经过清洗留下来的有效图像大约在3000张左右。这个数量对YOLO系列模型来说不算多如果训练场景单一、拍摄高度固定也许够用但如果我们希望模型能覆盖不同高度、不同时段、不同活动类型则需要更多样本或者依靠更强数据增强来补。我最终把项目的训练集定在2400张验证集400张测试集200张。因为场景局限在校园操场类别只有“人”这一个类别所以不需要做多类别平衡。但要注意单类别检测的硬性要求是负样本要足够也就是没有人的操场背景图也要有。不然模型很容易把操场标志线、阴影这种东西当成目标。标注策略上我确定了一个原则只标注可见的人体完整轮廓范围如果只露出一半身体只要可以明确判断是人就标注可见部分如果被遮挡超过70%并且无法判断完整姿态的可以标也可以不标。一开始我和标注的同学说只要看到人就标结果出现一批模棱两可的标注框训练出来模型反而糊涂。后来规范改成“看得清头肩就标看不清就不标”整个数据质量提升了一截。2. 数据采集与预处理实操数据集的质量七分靠采集三分靠清洗。这个项目里我建议把时间和精力重点花在采集阶段因为后期再怎么做数据增强也很难凭空造出航拍俯视的独特视角信息。2.1 无人机采集路线与拍摄参数采集时使用的无人机是大疆系列的Mavic机型选择它可以方便地在操场上方悬停和规划航线。我采用的飞行高度分为两个档位低空30米左右用于采集人群密集场景目标像素相对较大高空60米左右用于采集全场景分布对应小目标检测需求。航线上我以操场中心为基准做了十字形和螺旋形两种路径。十字形路线适合拍摄纵向排列的人群比如跑操队伍螺旋形路线适合采集不同角度的场景让目标出现在图像的不同位置。这里有个小技巧拍摄时不要一直保持镜头垂直向下建议以30度到60度之间的俯角混合采集。完全垂直的视角有助于检测人群密度但带有一定俯角的图像更接近实际监控场景也更容易让模型学到人物的立体形态。拍摄参数的设置也很关键。分辨率统一采用4K快门速度尽量高于1/1000秒避免运动模糊。光圈不要开到最大因为正午阳光充足时光圈太大容易导致中央过曝。我用的参数是f/4.0ISO控制在100到400之间尽量保持画面的清晰度和低噪点。一个容易忽略的问题是云台角度和相机畸变。无人机广角镜头边缘畸变比较明显如果只在图像中心区域采集模型对边缘目标的泛化能力就会很差。所以拍摄时我会有意识地让目标出现在画面的四角和边缘但后期也会通过裁剪模拟边缘样本。2.2 图像筛选与清洗的细节采集回来之后不要急着标注。先把原始视频里面连续帧之间的相似图片剔除掉。我使用的方式是每隔一段时间抽帧然后对相邻两帧做帧差法计算像素差异比例差异太小的帧直接丢掉。这样可以把数据集里的冗余信息大幅降低模型不会因为大量重复样本而过拟合到固定画面。清洗的时候还需要剔除几类“坏图”第一类是对焦失败导致整体模糊的这个简单肉眼一扫就能筛掉第二类是曝光异常的尤其是正午逆光条件下操场一半是白斑一半是黑影这种图像的动态范围超过了检测模型能有效处理的范畴直接弃用更安全第三类是画面被无人机自己的影子或者云层阴影覆盖的这类图像会干扰模型对真实亮度分布的认知。另外一个很多人不注意的清洗细节是检查图像的EXIF信息把高度和角度数据记录下来。我最后把数据集按高度标签做了分组低空图片归入近景文件夹高空图片归入远景文件夹方便后续做分模块训练或者评估模型在不同高度下的表现。如果没有这一步后面分析漏检原因时会非常痛苦。2.3 数据增强手段与针对性选择YOLO训练中数据增强是提升泛化能力的核心。常规的翻转、旋转、缩放、亮度变化、对比度调整我们当然都加了但针对航拍场景我额外做了几种增强。第一种是随机仿射变换。俯拍图像中地面的矩形跑道的透视形变会随着无人机的水平位移而改变通过模拟这种透视变化可以让模型对斜视角度的鲁棒性更好。第二种是随机裁剪拼接类似于Cutout或Mixup的变种。我随机把图片切掉几个小块填充灰色块这样模型不会过度依赖局部纹理来判断是不是人。对于密集场景这种遮挡模拟非常有用因为人群互相遮挡的情况在真实场景里很常见。第三种是马赛克增强这个YOLOv5以后的版本自带。我调高了mosaic的启用概率因为四张图拼接在一起后图片尺寸变小相当于强行造出了更多小目标样本对航拍场景特别有效。实际训练时我还开启了一个自定义的“天空干扰”增强随机在图像顶部添加一段模拟天空的渐变区域。这个操作听着有点怪但它确实能减少模型把看台顶棚、天空颜色误判为背景的情况。增强不是越多越好。我一开始开了很多种增强结果训练时间变长loss虽然下降得很快但验证集mAP反而停滞。后来减少了一些增强项尤其是把饱和度调整幅度调低因为操场塑胶跑道的颜色饱和度本来就很高过度调整会让模型对颜色特征产生错误依赖。3. 标注流程与质量控制标注是目标检测项目里最枯燥但也是最重要的环节。这个项目类别少只有“人”框但因为航拍图像的尺度变化大、遮挡多标注难度其实比许多多类别项目还要高。3.1 标注工具选型与配置我用的标注工具是LabelImg和X-AnyLabeling的组合。LabelImg适合快速做矩形框标注操作简单、稳定原生支持YOLO格式的txt导出。X-AnyLabeling则集成了SAM模型可以交互式分割目标在目标边界复杂时能帮上大忙。不过在航拍俯视图中人的轮廓大多比较规整直接用矩形框的效率反而更高。安装过程没什么可说的关键是团队协同。我把图片分成三个批次分给三个同学标注使用同一份标注规范的文档说明。这里强烈建议使用样本图片示例来标明“标”和“不标”的情况文字描述再多都不如几张典型样例直观。比如一个站在树荫下只露出一只手的人算不算目标我的答案是“不算”。因为训练目标是检测可行动的人体而不是分离身体部件。标注前还需要统一坐标系。YOLO格式要求的是归一化坐标标注工具里需要提前设置好类别文件我建了一个classes.txt里面只有一行person。宽度高度和归一化坐标由工具自动计算。这里有一个易错点不同版本的标注工具导出的文本框格式略有差异有的用的是左上角坐标加宽高有的用中心点坐标加宽高。我在数据校验时写了一个脚本统一检查txt文件里的值是否都在0到1之间发现不少第一次导出的文件坐标值直接超过了1就是因为工具设置不对。3.2 标注规范的制定我制定的规范大概有这几条首先身体大部分可见且姿态清晰必须标注完整框框要贴合人体的外接矩形。其次如果人被遮挡导致某一个方向上的边界完全看不出来那么只标注可见部分的紧框而不是凭想象补齐整个身体。再次只露出头部或者只有一条腿的人体碎片不标注但如果看到头部和肩膀就算下肢被栏杆挡住也标注完整可见区域的框。还有一个细节是框的贴合度。YOLO训练时如果框画得过大把背景大量包进来模型会学到错误的特征关联如果框画得过小目标特征被切掉一部分模型又不容易收敛。我要求标注框紧贴人的外轮廓误差尽量控制在两三个像素以内。实际操作中靠人工来回调整很费力但这一步不能省因为数据集质量直接决定模型上限。标注完成后我做了两轮交叉审核。第一轮由标A的同学检查标B同学的框重点看有没有漏掉密集区域的人和框的贴合度第二轮由我本人抽查每个批次随机抽20%的图片检查标注框数量与画面中视觉可辨认的人影数量是否大致匹配。第一轮交叉审核后漏检率明显下降但框的贴合度问题还是很多尤其是高空图中小尺寸目标不少人会把框画得非常大一检查就现形。3.3 质量复核与边界案例处理复核阶段我发现几个比较容易混淆的边界场景。第一种是远处跑道上的人因为距离远像素很小分辨率低很多时候只有几个像素组成的一团模糊亮点这类目标到底标不标需要明确规则。我的规则是只要人眼在标准屏幕上能辨认出具体的人形轮廓就标如果只是一个点或一团噪点不标。这个规则直接影响训练集对极小目标的覆盖度不能太激进也不能太保守。第二种是多人重叠时标注框之间应该允许重叠但重叠面积过大的情况需要特别注意。如果两个人在画面里已经融合成一个色块完全无法区分边界那就不标第二个只标一个框。这是为了避免给模型提供“两个重合框对应一个目标”的错误监督信息。第三种是镜面反射和阴影中的目标。操场边的玻璃幕墙反射里的人影、水洼里的倒影这些我统一不标注。目标检测是检测实体不是检测倒影。如果模型因为倒影而误检反而增加部署时的误报率。阴影中的目标则要看真实可见程度能看清轮廓就标看不清就放弃。我把复核发现的问题整理成一份修订记录再让标注同学一起复盘之后的标注错误率降低了很多。这里想强调一点标注不是一个一次性工作它是一个需要持续迭代的过程。如果训练出的模型在某个场景下漏检严重就要回头检查是不是这个场景的标注本身质量不高而不是盲目换模型结构。4. YOLO训练配置与调参实践数据准备妥当后就进入训练阶段。YOLO的版本我选择的是YOLOv8原因是它在小目标检测方面比前代有所改进同时部署生态比较完善。有人可能会问为什么不用YOLOv9或者YOLOv10我的考虑是稳定性和参考资料的丰富度。对于单类检测任务YOLOv8足够成熟踩坑的解决方案也容易找到。4.1 数据集格式转换与环境搭建YOLOv8接收的数据集目录结构为images里面放train和val子目录labels里面对应有train和val子目录。图片和标签的文件名要完全一致标签文件中每行代表一个目标格式是类别编号 中心点x 中心点y 宽度w 高度h全部是归一化后的0到1浮点数。我写了一个简单的脚本确保训练集和验证集的划分不产生文件泄漏同时随机种子固定下来方便复现。具体代码如下import os import random import shutil random.seed(42) source_imgs all_images source_labs all_labels train_ratio 0.8 imgs os.listdir(source_imgs) random.shuffle(imgs) split int(len(imgs) * train_ratio) train_imgs imgs[:split] val_imgs imgs[split:] for img in train_imgs: shutil.copy(os.path.join(source_imgs, img), dataset/images/train/) lab img.replace(.jpg, .txt) shutil.copy(os.path.join(source_labs, lab), dataset/labels/train/) # 验证集同理环境搭建上我建议直接用官方提供的ultralytics包命令是pip install ultralytics。训练用的GPU是单张V100显存16Gbatch size设置为16图像输入分辨率设置成640。这里我要多说一句更高分辨率比如1280对小目标检测的效果通常会更好但对显存和训练时间的要求更高。我做了对比实验后发现在V100上使用640到800之间的分辨率性价比最好。到了1280后mAP确实提升了两到三个点但训练时间翻倍还多。再补充一点航拍小目标多开启YOLOv8的augment参数并设置合适的mosaic概率很有帮助。我在配置文件中把mosaic设为1.0因为小目标占比高mosaic能在训练时生成大量尺寸压缩样本让模型适应不同目标尺度。4.2 训练关键参数与损失函数要点YOLOv8的损失函数包含三部分分类损失、回归损失、DFL损失。训练时最需要关注的实际上是回归损失中的IoU项。航拍场景下人挨着人很多检测框之间的IoU天然比较高这时如果正负样本分配参数设置不合理很容易导致模型把多个相邻目标当成同一个目标。我一开始用的是默认的tal_topk10训练到后期发现密集人群中的检测框经常出现合并现象。后来把tal_topk调低到5因为每个锚点分配的候选正样本数量减少模型能更准确地学到单个人的边界而不是把旁边人的肩膀也拉进来。这个参数对密集场景的影响比你想象中大得多。再说说置信度阈值。训练时不用太关注这个但推理时如果设置太低比如0.1俯拍画面里的操场标志线、树荫边缘都会被错检成人。我尝试过0.25、0.35、0.45几档最终测试集上0.35的表现最好既保证了召回又抑制了大部分误检。如果部署环境中的误报代价较高可以进一步调高到0.45。还有一个经常被忽略的参数是close_mosaic。YOLOv8在训练最后10个epoch会关闭mosaic增强让模型在接近真实分布的图像上做最后的拟合收敛。我保留了默认设置。如果你用的是YOLOv5也建议开启最后一个epoch关闭mosaic的操作效果类似。4.3 训练过程监控与常见问题训练时一定要盯住两个曲线训练loss和验证集mAP。我见过不少人只看loss下降就以为模型在变好结果训练到后期loss下降的同时mAP也在下降这就是过拟合或者数据泄漏的信号。在训练过程中我遇到了几个典型问题。第一个是BN层崩溃。这个通常发生在batch size较小且学习率设置不当的时候特征图统计量出现剧烈波动loss突然变成NaN。我当时的处理方法是把初始学习率从0.01降到0.005并开启warmup。YOLOv8默认自带warmup但航拍图像中批量归一化对数据分布更敏感稍微调低学习率就稳定了。第二个是类别单一导致分类分支过拟合。因为只有一个类别分类分支持续训练会让模型倾向把所有目标都预测为person但这种“盲目自信”会导致误检率上升。我在训练后期使用早停耐心值设为20个epoch当验证集mAP连续20轮不再上升就停止训练避免过拟合。第三个是图片尺寸不统一导致标签错位。我清洗后的图片有些是4K原始尺寸有些经过裁剪成了1080P但标注坐标是基于各自原始尺寸计算的。YOLO训练时如果图像被resize到固定输入尺寸问题不大但如果数据集内部有混合尺寸且我的预处理脚本没有统一处理就可能导致标签不对齐。我在预处理代码里把所有图片都归一化到长边1280再统一resize到训练尺寸。训练结束后我的最佳模型在验证集上的mAP50达到了93.5%mAP50-95大概在68.4%左右。这个成绩对于单类航拍检测来说比较理想。但我还是要提醒一句mAP50-95更能反映小目标的检测定位精度如果你发现mAP50不错但mAP50-95很低说明模型虽然能大致框住目标但边界精度不足这在航拍场景中很常见原因是小目标本身的边界信息就不充分。5. 模型评估与落地部署训练完成不代表任务结束真正的考验是把模型放到实际场景中跑起来。我在模型评估和部署阶段又踩了不少坑这里分享一些值得注意的细节。5.1 评估指标与混淆矩阵解读目标检测最常用的指标是mAP50和mAP50-95。对于航拍小目标检测建议额外关注mAP small这一类指标因为YOLOv8的结果文件里会按目标尺度细分指标。我打印出详细报告后发现大中目标的mAP都不错但小目标的mAP50只有81%左右明显低于总体的93.5%。这个结果说明模型在极小目标上有明显短板也指导了后续的数据补充方向多拍一些60米以上高度、人群密集的场景。混淆矩阵方面YOLO训练结果目录下会生成混淆矩阵图。因为是单类检测看起来比较简略但我建议把confusion_matrix_normalized打印出来看能直观展现误检比例。我的结果显示误检主要集中在背景被当作人的情况。分析后确认是操场白色标志线、树荫和塑料凳子的边缘特征被模型误认为人形。所以我又在训练集中加入了一批纯背景负样本重新训练后误检率下降了30%左右。这里有一个很多人没注意到的点负样本图片也需要有对应的空标签文件也就是txt文件是空的里面一行都没有。如果训练时负样本图片没有标签文件数据加载器可能会报错或者跳过图片导致负样本根本没有参与训练。我一开始就漏掉了这个细节。5.2 模型导出与推理部署训练完成后需要把模型导出为部署格式。我用的是yolo export modelbest.pt formatengine device0导出到TensorRT引擎。在V100机器上导出时选择fp16半精度可以显著提升推理速度实测从约20ms一帧降到约8ms一帧。导出前注意TensorRT引擎是绑定GPU型号和CUDA版本的换机器后需要重新导出。如果部署在Jetson系列设备上导出过程还需要配置TensorRT版本和JetPack版本的一致性这个不匹配会直接导致加载失败。推理脚本我用的是ultralytics自带的predict方法输出结果包含检测框坐标、置信度和类别ID。在航拍视频流场景中还需要做一个跟踪模块我使用了ByteTrack搭配YOLOv8。这里为何要考虑跟踪因为航拍画面中单帧检测只能给出位置很多实际应用比如统计人数、追踪运动轨迹需要多帧关联同一个目标。如果不做跟踪人群跑动时目标ID频繁切换统计数据就完全不可用。部署时的输入尺寸也要注意。训练时我用的是640但部署时如果推理分辨率和训练分辨率不一致性能会打折扣。可以在部署时再选择768或832但要保证模型已经见过对应尺度或配合自适应缩放。我最终选择768作为部署分辨率因为它在小目标检测和速度之间取得了平衡。5.3 部署后的优化空间模型部署上线后我做了几轮实际试飞测试。发现两个问题一是正午强光下白色运动服与天空高光区域接近导致误检二是黄昏时段人群阴影拉长模型偶尔把两个相邻目标的阴影合并检测成一个框。针对第一个问题我调整了部署端的预处理加入了一个轻量的白平衡校正模块把整个画面的色温拉回到接近训练集的分布。针对第二个问题我改进了后处理NMS策略在检测框合并阶段增加了一个基于框中心距离的约束如果两个框的IoU很高但中心距离较远就不合并。这其实就是传统NMS和SoftNMS之外的另一种启发式策略虽然简单但对影子造成的粘连框很有效。再往后如果想把模型进一步压小并提升速度可以考虑蒸馏方案用当前的大模型作为teacher蒸馏到一个更小的YOLOv8n或者YOLO11n模型。我做过一次对比小模型在mAP50上只掉了2到3个点但速度从8ms降到3ms左右对于需要实时处理4K视频流的边缘设备来说非常香。蒸馏要用真实推理时的soft label而不是训练集里的one-hot标签这一点需要注意。最后分享一个扩展思路。这个数据集虽然只标注了“人”一类但校园操场场景完全可以延伸到更多应用。例如同时标注出场地标志线、足球球门、篮球架配合人体位置可以做越界告警、运动轨迹分析、设备安全距离监测。数据积累到这个程度以后再往上加类别和任务比从零开始要高效得多。我个人的体会是航拍人体检测这种任务真正决定模型上限的往往不是算法结构而是数据集对场景的覆盖程度。同一个操场不同高度、不同时段、不同活动类型之间的差异比很多研究者想象中要大得多。只有把这些差异都体现在数据里YOLO这类通用检测器才能真正在航拍场景中落地。接下来有朋友想复现这个项目的话建议优先在数据采集阶段多下功夫哪怕少训几个版本的模型也要保证源数据足够多样。
返回列表