ARTICLE DETAIL

资讯详情

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

远距离抽烟行为识别系统:基于YOLOv5+Openpose+Resnet18的实践

远距离抽烟行为识别系统:基于YOLOv5+Openpose+Resnet18的实践 简介基于YOLOv5、OpenPose与ResNet18的远距离抽烟行为识别检测系统专为计算机视觉、人工智能等专业学生及毕业设计/课程设计场景打造涵盖行人检测、人体姿态估计与行为分类的完整技术链。项目针对单一YOLO在远距离吸烟检测上的局限设计了两种可运行方案先以YOLOv5检测人体再生成骨骼关键点图并交由ResNet18分类或直接使用OpenPoseResNet18完成判别配套说明文档与已训练模型代码均经测试通过。包内共638个文件包含412张样本图片、53个Python脚本、17个YAML配置、7个PT权重、6个JIT模型及XML/TXT标注文件总体积161.25MB数据与训练脚本齐全便于二次开发。目前已有348人学习下载。除现成的抽烟检测外资源还提供动作关键点数据集train/test与训练流程可按需生成其他姿态数据并扩展模型适合入门学习、项目立项演示到实际部署的多个阶段也能直接作为毕设或课程设计的完整参考。 远距离摄像头下的抽烟行为识别一直是安防场景里一个很尴尬的痛点。近景人脸识别抽烟已经比较成熟了可一旦摄像头挂在5米、10米以上的杆子上人脸区域常常只有几十个像素烟头、烟雾细节基本看不清再牛的近景模型也会失灵。我最近完成了一个基于YOLOv5OpenposeResnet18的远距离抽烟行为识别检测系统把目标检测、姿态估计和分类网络串联成一个三级流程实测在10-15米距离上能稳定跑出85%以上的识别准确率。这篇博客把整个选型思路、数据集构建、训练调参和工程落地的过程完整记录下来给正在做类似行为识别项目的朋友一个可以直接参考的路线。1. 远距离抽烟识别的核心难点为什么近景方案全部失灵1.1 远距离场景下图像信息退化到什么程度先看一组实际数据。市面常见的2.8mm焦距监控摄像头安装在12米高度时一个身高1.7米的成年人在地面行走其在画面中的像素高度大约只有60到80像素人脸部分通常不会超过30×30像素。在这个分辨率下烟头直径约7mm的成像可能只有1到2个像素烟雾几乎是完全不可见的连被检测者手里拿的是香烟还是棒棒糖都很难分辨。这个物理限制直接宣告了传统近景方案失效。近景场景下主流做法是人脸检测加嘴部区域分类——检测到人脸后裁剪出包含嘴部和手部的区域用分类网络判断嘴里是否含有烟支。但这套逻辑依赖一个关键前提嘴部区域要清晰到能看见烟支的外形特征。一旦距离拉远嘴部区域低于20×20像素时分类网络的输入信息量严重不足训练集再大也无济于事。我在项目初期的对比实验里把近景模型直接迁移到10米距离的测试集上准确率直接掉到47%和随机猜测没什么区别。1.2 换个思路从看细节转向看姿态既然看不清烟和烟头那就索性不看了转而分析抽烟这个动作在人体姿态层面留下的强特征。抽烟行为的本质是手持烟具移动到嘴部区域并在该区域停留数秒钟期间伴随手部遮挡嘴部和轻微的头部倾斜。这三个特征在远距离下恰恰是鲁棒的。因为骨骼关键点如手腕、手肘、肩膀、鼻子、眼睛即使在大幅降采样的人体图像上仍然可以被姿态估计模型稳定提取出来。只要关键点坐标可靠手部与嘴部的距离、手腕抬升的角度、手在嘴部区域的停留时间这些几何特征就不会受到分辨率限制。这就是为什么这个项目最终放弃端到端的单模型方案转而采用YOLOv5OpenposeResnet18三级级联架构的根本原因——远距离场景下几何结构信息比纹理细节信息可靠得多。2. 三个模型的分工逻辑不是堆砌而是各司其职的流水线2.1 YOLOv5负责任务无关的人体目标锁定整个流水线的第一环是YOLOv5。它的任务不是判断是否抽烟而是尽可能全地把画面中的人体目标检测出来输出每个人的边界框坐标。这一环的核心价值在于缩小后续姿态估计的搜索范围避免整张图送入Openpose带来的巨量计算开销。在模型体量选择上我最终选用了YOLOv5m而不是更轻的YOLOv5s。原因很直接远距离人体的像素面积小属于小目标s模型的特征提取能力相对有限漏检率会升高。对比测试中在15米距离的测试视频上s模型的人体召回率为89.6%而m模型达到了96.3%。作为流水线最前端如果人体框都漏掉了后面的环节完全无从谈起。输入分辨率方面我建议将测试阶段的推理分辨率设为1280×1280虽然推理时间会从大约9毫秒增加到18毫秒但小目标召回率能再提升2到3个百分点这笔账是划算的。2.2 Openpose精确提取手、嘴、肩的几何坐标第二环是Openpose姿态估计模型。在拿到YOLOv5给出的每个人体边界框后将裁剪出的人体图像送入Openpose提取头部、颈部、肩部、肘部、手腕、眼睛、鼻子共18个关键点的坐标。这些坐标是整个识别系统最核心的中间特征。需要特别说明的是Openpose在单人体上的推理速度并不算快。原版VGG结构在GPU上处理单人框大约需要60到80毫秒如果画面中同时有5个人整条流水线的帧率会掉到不足10 FPS。为了解决这个问题我在工程上做了一个重要取舍不使用Openpose的全图推理模式而是基于YOLOv5的输出框逐人裁剪推理。这样既能保证每人的关键点质量又能通过批处理batch processing在GPU上并行计算多个人体框。实测四路batch推理时单人平均耗时可以压低到40毫秒左右。在远距离姿态提取上有一个容易被忽视的技术细节原版Openpose的训练数据以中近距离的人体图像为主直接拿来处理30到80像素高的远距离人体关键点置信度会明显下降。我建议在COCO和MPII数据集之外额外混入一批远距离监控视角的标注数据对Openpose进行微调微调时冻结前几层卷积只训练后端的PAFPart Affinity Fields分支可以在不大幅改动预训练权重的条件下有效提升远距离关键点的检出稳定性。2.3 Resnet18把姿态特征变成抽烟/不抽烟的结论第三环是Resnet18分类网络。前两级模型输出的关键点坐标经过归一化处理后会生成一组固定长度的特征向量这组向量进入Resnet18进行分类最终输出抽烟或不抽烟的概率。为什么需要专门的分类网络而不是直接用几何规则阈值判断我做了一组对比实验设计了一组简单的判定规则比如手腕与鼻子距离小于某个阈值且手腕角度处于某个范围即判定为抽烟。规则法的准确率只有73.1%误报主要集中在打电话和摸脸这两个动作上因为它们在几何特征上和抽烟高度相似。而Resnet18分类网络可以通过大量标注数据自动学习到手部在嘴部区域停留时间更长、“手腕姿态更垂直”这类隐含的模式差异在同样的测试集上将准确率提升到88.4%。数据驱动的分类器在处理模糊边界时总是优于人工硬编码的规则这是我在这个项目里最深刻的一点体会。3. 远距离抽烟数据集构建整个项目最耗时、决定上限的环节3.1 数据采集策略公开数据集根本不够用必须自制我查遍主流公开数据集COCO、VOC、MPII里都没有抽烟行为这个类别。市面上的开源抽烟数据集基本全是近景人脸特写完全无法直接服务于远距离项目需求。因此数据集必须自己做这也是整个项目周期中耗时最长的部分大约占到总时间的60%。数据采集我总结出三个来源渠道公共场所合规采集的广角摄像头录像需脱敏处理去除可辨识特征覆盖10到20米距离范围无人机航拍视角下的街面场景重点补充俯视角度因为监控摄像头大多带安装倾角从开源视频网站收集的远距离街头拍摄素材注意优先选用允许二次创作授权的片段。三条渠道合计采集了约5600段有效视频片段每段时长5到10秒覆盖白天、黄昏、夜晚三种光照条件和晴天、阴天、小雨两种天气状况。3.2 标注链路三个模型需要三类不同的标注信息这套级联系统的训练数据是分阶段生成的。第一阶段构建YOLOv5训练集用labelimg工具对所有视频抽帧标注人体边界框共得到约18000张带标签图像。第二阶段构建Openpose微调数据集这一步有个省力技巧先用原版Openpose自动推理出关键点坐标作为预标注再人工修正明显错点。修正重点集中在手腕和手肘处因为远距离图像中手臂区域像素质量较差自动标注的抖动明显。第三阶段构建Resnet18的行为分类数据集为每个抽帧样本打上有抽烟行为或无抽烟行为的标签这一阶段不需要手工框选直接在时间轴上按事件标注即可。3.3 数据增强针对远距离场景的特殊处理手法常规的裁剪、翻转、色彩抖动这类增强手段当然要做但针对远距离场景我还加入了三个针对性增强策略模拟模糊增强对图像施加高斯模糊和运动模糊模拟远距离光学聚焦不佳导致的目标边缘混叠效果多尺度缩放增强将人体区域随机缩放到40到100像素高度让模型充分适应不同距离下的尺度差异逆光/低照度增强调节伽马值和对比度模拟背光和夜晚路灯照明下的弱纹理条件。这些增强操作在消融实验中的贡献非常显著。未加针对性增强时模型在夜间测试集上的准确率为72.6%加入之后直接提升到84.1%。远距离行为识别的主要矛盾不是正样本不够多而是负样本不够像针对性增强就是在制造这种像逼着模型学会真正的判别特征。在负样本设计上我踩过一个大坑。最初模型在测试时频繁把打电话识别成抽烟误报率一度高达15%。排查发现负样本里手部接触头部/耳部的动作类型太少。后来我把负样本扩充到包含打电话、摸头发、擦嘴巴、揉眼睛、用手遮挡阳光等全部手到头部的动作类型并且每种再细分多个方向角度最终把误报率压到了5%以内。行为识别项目里负样本的覆盖度直接决定了产品的可用性这句话希望做类似项目的同行刻在工位上。4. 训练过程中的关键细节与参数调优记录4.1 YOLOv5训练要点小目标模块和锚框尺寸要调YOLOv5m训练时为了增强对小目标人身的感知能力我做了两处关键修改。第一在backbone的SPP层后增加了一个额外的P2特征输出层用80×80的大尺寸特征图来专门预测小目标。第二使用k-means聚类算法重新计算了远距离人体数据集的锚框尺寸默认锚框是针对COCO数据集的COCO里人体通常较大而远距离人体的宽高比和尺寸分布差异很大重新聚类后的锚框能显著加速收敛。训练参数量和优化器上批大小设为32初始学习率0.01使用SGD优化器配合余弦退火调度策略总训练轮数200轮。因为加入了自制数据我在前50轮冻结了backbone权重只训练检测头第51轮开始解冻全部层以0.001的低学习率微调这种两阶段策略让模型定位精度更稳。4.2 Openpose微调注意力放在手腕和手肘关键点Openpose的微调不是全部重训而是有重点的。原版模型在COCO和MPII上对手腕、手肘这类末端关键点已经具备较好的初始化能力但在远距离低分辨率下失效明显。我在微调时只解冻最后一层PAF预测层和最后的Refinement Stage前面的VGG特征提取层全部冻结。学习率设到非常保守的0.0001批大小为8训练了60轮。损失函数上Openpose官方使用均方误差损失我改为针对手腕、手肘关键点加权的MSE损失——手腕权重设为5手肘为3其余关键点保持1。这么改的出发点是清醒的抽烟行为识别最依赖的正是手腕和手肘坐标的可靠性而这两个点在远距离下最容易漂移。加权后手腕关键点的PCK0.2归一化距离阈值下的准确率从71.8%提升到了83.5%效果立竿见影。4.3 Resnet18输入特征设计与序列平滑Resnet18的分类输入不是原始图像而是一个精心设计的特征向量。我从Openpose输出的18个关键点中筛选出8个核心坐标点鼻子、左右眼、左右耳、左右手腕、颈部。将这些点做归一化处理后构建成以下特征左手腕到鼻子的归一化距离右手腕到鼻子的归一化距离左手腕到左耳的归一化距离右手腕到右耳的归一化距离左右手腕相对于颈部的抬升角度头部相对于颈部的倾斜角这9个维度构成了一个11×1的特征向量。为了让分类网络拥有动作持续的信息我又连续采样5帧画面将时间维度上的特征拼接起来最终输入维度为55×1送入Resnet18的卷积层做分类。这种时序拼接的设计让模型能够感知手在嘴部区域停留了多久——这是区分抽烟和短暂摸脸的关键线索。每秒30帧的监控视频流按每10帧取一帧的抽样频率进入分类网络为了避免单帧误判引起输出抖动我引入了滑动窗口投票机制连续3个窗口每个窗口覆盖5帧中至少2个窗口判定为抽烟事件才输出正向报警。这套机制把误报率额外汇降低了约2.5个百分点。在Resnet18的训练配置上输入特征做了z-score标准化数据集按8:1:1划分为训练集、验证集和测试集使用Adam优化器初始学习率0.001设置学习率在每20轮衰减为0.5倍训练60轮。关键训练技巧是类别不平衡处理——正样本抽烟只有负样本的四分之一我在损失函数中给正样本施加了4倍的类别权重并将训练过程加载了早停机制验证集准确率连续8轮不提升就停止训练最终模型在测试集上的准确率稳定在88%附近。5. 源码使用与工程化部署从拿到项目到跑通全流程5.1 项目目录结构解读一个完整的项目包应该包含以下核心模块这是这套系统的标准目录结构smoking_detection_system/ ├── detect.py # 主推理入口连接摄像头或视频文件 ├── train_yolo.py # YOLOv5训练脚本 ├── train_openpose.py # Openpose微调脚本 ├── train_resnet.py # Resnet18分类器训练脚本 ├── models/ │ ├── yolo_weights/ # YOLOv5模型权重 │ ├── openpose_weights/ # Openpose模型权重 │ └── resnet_weights/ # Resnet18分类模型权重 ├── datasets/ │ ├── yolo_annotations/ # 人体检测标注 │ ├── pose_keypoints/ # 关键点标注 │ └── behavior_labels/ # 行为分类标签 ├── utils/ │ ├── pose_features.py # 关键点特征提取 │ └── frame_buffer.py # 滑窗与序列缓冲 ├── configs/ │ ├── yolo_config.yaml │ └── openpose_config.yaml └── README.md # 使用说明文档这套结构把三个子模型完全解耦各自有独立的训练入口、权重目录和配置文件。最大的优点是后续替换任何一级模型都不需要改动其他模块的代码。比如未来想用YOLOv8替换YOLOv5只需修改detect.py中模型加载部分和yolo_config.yaml中的配置项Openpose和Resnet18链路可以完全不动。5.2 环境配置与推理速度调优环境方面建议使用Python 3.8以上版本PyTorch 1.8CUDA 11.x。如果显卡显存不足8GB推荐使用FP16半精度推理有效显存占用可以降低约40%而准确率损失控制在0.5%以内。如果只有一个CPU环境整个流水线的推理速度会比较吃力——即便经过逐人框裁剪优化CPU上每帧处理仍需约1.2秒基本只能满足离线视频分析需求实时监测不建议。实际部署中推理速度主要受两大因素影响画面中的人数上限和分辨率。在1080P输入下画面中同时存在3人时NVIDIA T4显卡上的全链路推理耗时约为85毫秒/帧勉强达到每秒11帧若将输入分辨率压缩到720P耗时可以压缩到60毫秒/帧。我建议在实景部署时把输入分辨率设为720P因为远距离人体轮廓在720P和1080P下的关键点提取差异很小而推理速度提升接近30%。关于源码的二次开发utils/pose_features.py是最值得关注的文件它负责把Openpose的原始输出转换成Resnet18的输入特征。如果你想增加新的行为识别类别如打电话、喝水、吃东西只需要在这个文件中新增特征组合函数并在behavior_labels中增加对应的类别标注不用改动模型结构本身。5.3 实测效果与误报复盘在完成所有训练和部署后我搭建了一条模拟监控环境进行实测。摄像头安装在12米高度俯视角度约15度测试区域宽度约20米。测试结果显示10米距离的吸烟召回率为91.2%15米距离为86.7%20米距离急剧下降到61.3%这是因为20米处人体高度不足50像素手腕和手肘关键点开始大面积漂移误报场景中占比最高的是手拿手机贴近耳边和手捧零食在嘴前咀嚼两者合计占全部误报的70%以上夜间场景整体准确率比白天低6.2个百分点主要源于低照度环境下关键点置信度下降。针对误报复盘我从日志系统里提取了误报样本逐一分析后发现一个共性规律所有误报样本中手部在嘴部区域的停留时间都接近1秒以上与真实抽烟的持续动作时长几乎不可区分。这意味着单纯增加时序上下文已经很难进一步压降误报未来最可行的优化方向是在系统输出层引入烟雾检测模块作为联动验证——在手腕位于嘴部区域时额外检测该局部区域是否存在烟雾纹理特征两种信号同时满足才触发报警可以进一步降低误报。6. 后续扩展与实际部署中的个人体会6.1 模型轻量化与边缘端落地如果未来需要把系统部署到嵌入式设备如Jetson Nano或树莓派模型压缩是绕不开的功课。我的经验是从次级模型开始压缩优先把Resnet18替换为MobileNetV3或ShuffleNetV2因为分类网络是整个流水线中对精度最不敏感的一环压缩后准确率损失通常不超过1个百分点。第二优先级才是对Openpose做剪枝但要注意剪枝幅度不宜超过原始权重的50%否则远距离关键点漂移会迅速恶化。YOLOv5不建议深度压缩它是整个系统的入口也是最前端的保障。6.2 距离和角度的物理边界我想特别提醒一句任何技术方案都有物理边界。这套系统在10到15米距离的表现可用但超过20米后精度断崖式下降是客观规律不是调参就能解决的。如果业务场景需要在30到50米距离做行为识别建议直接换方案比如结合工业相机长焦镜头做多级联动而非试图在单摄像头上做过度优化。6.3 一套值得固化的工程经验整个项目走下来我的一个核心经验是多模型级联系统里的瓶颈分析一定要分层做线上监控。单独看每个模型各自准确率都很高不代表串联起来就能正常工作。我在部署后专门搭建了一个全链路日志的可视化面板把每一帧中YOLOv5的检测框数量、Openpose各关键点的置信度、Resnet18的分类概率全部记录下来。当系统出现异常误报或漏报时直接在面板上回放对应时间段的数据一眼就能定位到是哪一级模型出了问题。这套排查方法帮我节省了大量调试时间。另外如果只给你一个教训去记住那我会选择这一条在行为识别项目中数据采集的覆盖度——尤其是负样本场景的覆盖度——永远是决定产品落地上限的第一要素模型结构的强弱只能决定能在多大程度上逼近这个上限。这个项目整体跑下来前前后后花了接近三个多月的时间其中最深的体会是远距离行为识别的本质问题不是模型不够强而是信息退化条件下的可判别特征设计。把这个问题想透了YOLOv5加Openpose加Resnet18这个组合正好提供了一条足够简洁可靠的解题路径。希望这篇拆解能帮到正在和远距离识别死磕的同行们。本文还有配套的精品资源点击获取
返回列表