基于YOLOv5的人物专注性检测:疲劳与分心行为识别实践
发布时间:2026/8/30 22:57:27来源:尧图网络
简介本资源是一个面向计算机视觉开发者与智能监考/驾驶辅助场景研究者的YOLOv5人物专注性检测系统聚焦疲劳与分心行为双重识别任务。系统采用模块化设计疲劳检测基于Dlib人脸关键点定位结合PERCLOS模型量化闭眼时长并通过嘴部开合度判断打哈欠分心行为检测则依托YOLOv5目标检测框架精准识别玩手机、抽烟、喝水三类典型动作。压缩包共63个文件含20个核心Python脚本如main.py、myfatigue.py、mydetect.py、18个YOLOv5配置yaml文件、17个编译缓存pyc及UI界面、模型权重best.pt、人脸特征点数据shape_predictor_68_face_landmarks.dat、演示视频MP4与README说明文档整体大小为109.54MB。已有1356人学习下载提供完整可运行工程、带GUI的交互式界面PySide2、多版本YOLOv5模型支持及实测效果演示开箱即用便于二次开发与算法对比实验。1. 项目整体设计与思路拆解1.1 为什么专注性检测要选YOLOV5这套方案人物专注性检测说白了就是判断一个人当前是在认真干正事还是已经走神了、犯困了、在玩手机了。这类需求在线下课堂、在线监考、远程办公、驾驶员监控这些场景里都很常见。而实现这件事最直接的切入点是先解决“人在哪”“人的状态是什么”这两个问题这就绕不开目标检测和姿态/状态识别。我当初选YOLOV5不是因为它最新恰恰是因为它处于“好用”和“够用”之间最舒服的位置。YOLOV5虽然没有YOLOV8、YOLOV9那些新版本的结构花活但它的生态成熟度极高预训练模型好找、部署资料多、踩坑记录遍布全网对一个需要快速落地“检测人的状态”的项目来说这比追求算法涨点重要得多。再说YOLOV5的推理速度在同等精度下依然能打在GPU上跑到几十FPS很轻松放在边缘设备上配合TensorRT也能做到实时生产环境完全顶得住。再说回专注性检测本身。这个项目核心拆成三块人本身的疲劳状态、分心行为识别、以及整体的专注度判断。疲劳状态看的是闭眼、打哈欠、点头这类生理信号分心行为看的是低头看手机、侧身转头、长时间离开工位这类动作信号。这些信号有一个共同特点——都依赖对人脸和人体的精确位置感知。所以整个项目的第一步就是先把“人”稳稳锚住YOLOV5负责这个地基。1.2 系统架构的三种主流路线对比我在动手之前把市面上常见的人物专注性检测方案都过了一遍最后总结成三条路线纯CNN方案直接用分类网络对人脸图像判断“闭眼/睁眼”“打哈欠/正常”或者对人体图像判断“看手机/未看手机”。优点是模型轻、训练快缺点是空间信息弱多目标场景容易乱而且对视频序列的时序信息完全不利用单帧误判率偏高。目标检测单目标跟踪方案先用YOLOV5检测出人和人脸再用DeepSORT之类的跟踪器给每个人分配ID然后对每个ID单独提取状态特征。好处是能扛多人场景方便统计每个人的专注时长缺点是跟踪器偶尔会丢ID接踵而至的就是专注时长统计出错。实时检测时序平滑方案检测器仍然是YOLOV5但在后端加了一个时间窗口的投票/加权机制比如连续N帧里闭眼帧数超过阈值才判定为疲劳而不是看到一帧闭眼就报警。这条路线兼顾了实时性和稳定性我最终选的就是它。这里特别想说明一下为什么没有直接上Transformer或者最新的YOLOV8来解决。原因很朴素这个项目需要的是“可控、可解释、可在普通机器上跑起来”的源码而不是刷榜模型。YOLOV8的Anchor-Free机制虽然好但对本项目而言收益不大反而增加了部署时转ONNX、转NCNN的适配成本。YOLOV5的Anchor-Based检测头成熟稳定权重文件也小在课堂、工位这类相对固定的场景里精度已经绰绰有余。2. 核心细节解析与实操要点2.1 疲劳检测的核心原理与计算方式疲劳检测是整个系统里最有“硬核感”的部分它不是简单地拿一个模型输出“疲劳/不疲劳”而是基于眼部特征和嘴部特征做几何计算再结合时序判据输出结论。先说眼部特征。YOLOV5检测到人脸后我会用关键点模型可以是OpenCV自带的68点检测器也可以是MediaPipe的468点模型定位出左眼6个关键点、右眼6个关键点。然后计算一个叫EAREye Aspect Ratio眼睛纵横比的指标公式是EAR (||P2 - P6|| ||P3 - P5||) / (2 * ||P1 - P4||)其中P1到P4是眼睛水平方向上内外眼角的两个点P2、P3是上眼睑的两个点P5、P6是下眼睑的两个点。人在睁眼时EAR大约在0.25到0.35之间闭眼时会骤降到0.1以下。这个阈值需要实测校准我在这套系统里取的是0.18作为闭眼判定线。注意EAR的阈值不是死的。戴眼镜、光线差、侧脸角度大会导致关键点抖动阈值反而容易误判。我实测下来的经验是先用正常睁眼状态下采集300帧计算EAR均值再用闭眼状态下采集100帧计算均值取两者中位线作为动态阈值鲁棒性会好很多。PERCLOS眼睛闭合时间比例是疲劳检测的另一个关键指标。统计过去60秒内闭眼帧数占总帧数的比例超过0.4就判定为疲劳。这个阈值的设定是有生理学依据的——研究表明人在清醒状态下PERCLOS很少超过0.2超过0.35到0.4基本就是明显疲劳了。设计时把这两个指标做成OR判断单次闭眼持续时间超过2.5秒或者PERCLOS超过0.4任一命中都触发疲劳预警。2.2 分心行为检测的类别划分与判定逻辑分心行为检测这块关键在于想清楚要检测哪些行为以及每类行为用什么视觉特征去定义。我最终选了四类覆盖率高、判定难度适中的行为低头看手机、频繁转头、长时间离开工位、单手托腮。低头看手机依赖人体关键点检测YOLOV5检测人体框再用关键点模型获取肩膀、脖子、头部坐标计算头部俯仰角。角度的精确计算不需要很复杂的姿态估计模型用二维关键点的几何关系就够了——当鼻尖点到双肩中点连线的距离与双肩距离的比值超过0.6且持续时间超过3秒判定为低头。这个比值在抬头坐直时通常小于0.3写代码时可以做成自适应的阈值。频繁转头用头部水平转角做判定。这里我用的是左右眼关键点可见性的不对称性来估算——当一只眼的检测置信度明显高于另一只眼时大概率在转头。统计一分钟内转头次数超过8次就触发分心预警。长时间离开工位直接用YOLOV5的人体检测结果如果人体框消失超过90秒判定为离岗。这个时长根据业务场景可配置课堂就可以改成120秒司机监控则改成10秒。单手托腮视觉特征很典型手部关键点与人脸关键点高度重合且手部在画面中的位置稳定不动。我用YOLOV5的手部检测框与人脸检测框的IOU来判断IOU超过0.7则触发“托腮”标签。注意这里只是触发一个状态标记是否需要联动疲劳预警看业务需求。2.3 数据集构建与标注的亲身经验整个项目对数据集的依赖度比想象中高。YOLOV5本身的预训练权重只认识COCO的80类物体里面有人体类别person、有手机类别cell phone但没有人脸状态和手部的细分。所以即使不重新训练模型也必须训练一个附加分类器或者微调YOLOV5让模型能识别“闭眼的人脸”“打哈欠的人脸”“玩手机的人”这类细粒度目标。我采用了两条腿走路的数据策略公开数据集打底人脸检测用WIDER Face数据集闭眼和打哈欠用CEWClosed Eyes in the Wild和YawDD数据集人体检测直接沿用COCO的person类权重。这部分不用自己标注省了大量时间。自采数据做场景适配公开数据集的问题在于场景太泛真正部署用的教室、办公室光线和角度跟数据集差异很大。所以我用普通USB摄像头采集了大约2小时的自制视频切帧后用LabelImg工具标注了3000帧左右。标注类别就三类closed_eye、yawn、phone_use。其他类别复用YOLOV5的person类。具体到标注规范我踩过的坑是一定不要框得太紧。YOLOV5的标注框建议比真实目标外扩2%到3%因为模型学习的是框内特征与上下文背景的关系框太贴边容易导致检测框抖动。另外同一个目标在不同帧里标注框的大小差异要控制住不然训练出来的框回归不稳定部署时检测框会跳来跳去。3. 实操过程与核心环节实现3.1 环境搭建与依赖版本选择这个项目涉及到的核心依赖有PyTorch、OpenCV、YOLOV5源码、dlib或者MediaPipe、NumPy。我建议直接用Anaconda建一个干净的环境避免跟其他项目互相污染。实测下来的稳定版本组合如下组件推荐版本说明Python3.8.10兼容性最稳库基本都有预编译包PyTorch1.12.1 CUDA 11.6训练与推理稳定转ONNX也顺畅YOLOV5v6.0或v7.0v6.0的代码结构更简单适合改源码OpenCV4.8.0视频解码和图像预处理dlib19.24.0人脸关键点68点检测MediaPipe0.10.7可替代dlib多平台支持更好提示dlib的下载安装有时候会因为CMake编译失败卡住Windows上建议直接pip install dlib如果失败就用conda install -c conda-forge dlib不要自己编译源码省心很多。3.2 训练自己数据集的完整过程我使用YOLOV5训练闭眼、打哈欠、看手机三个自定义类别。整个训练流程分四步走第一步准备数据目录在YOLOV5源码目录下建datasets/attention_detection文件夹里面按YOLO格式组织datasets/attention_detection/ ├── images/ │ ├── train/ # 训练图像 │ └── val/ # 验证图像 ├── labels/ │ ├── train/ # 训练标签txt文件 │ └── val/ # 验证标签txt文件 ├── data.yaml # 数据集配置文件 └── classes.txt # 类别列表data.yaml里写清楚路径和类别数格式如下train: datasets/attention_detection/images/train val: datasets/attention_detection/images/val nc: 3 names: [closed_eye, yawn, phone_use]第二步训练参数设置由于是微调任务而不是从零训练学习率不用太大。我用的参数组合是python train.py --img 640 --batch 16 --epochs 100 --data data.yaml --weights yolov5s.pt --hyp data/hyps/hyp.scratch-low.yaml这里有几个参数要解释一下。--img 640表示输入图片尺寸448会更快但精度差一些640是均衡点。--hyp选择hyp.scratch-low.yaml是因为它数据增强强度低适合小数据集微调不会把原本COCO学到的特征破坏掉。batch size根据显存来6GB显存跑16是极限了如果报CUDA out of memory就降到8。第三步训练过程监控训练时重点看两个指标一个是mAP0.5代表IoU阈值0.5下的平均精度另一个是train/obj_loss代表目标置信度损失。正常情况下obj_loss应该随epoch下降如果在某个epoch后突然反弹多半是学习率过大或者数据里有标注错误的样本。我这次训练到第60个epoch时mAP0.5就已经到0.89了到第100个epoch稳定在0.93说明自定义类别的检测效果是可以的。第四步导出最优权重训练结束后best.pt会在runs/train/exp*/weights/目录下。同时我建议顺手导出成ONNX格式方便后面用OpenCV DNN做纯CPU推理python export.py --weights runs/train/exp/weights/best.pt --include onnxONNX格式在部署阶段很占便宜后面调用接口就统一了。这个步骤我强烈建议别跳过因为PyTorch的权重格式在工业部署中不通用ONNX才是实际部署最常用的中间格式。3.3 疲劳与分心检测核心代码实现检测主循环的逻辑其实很清晰我拆成四个模块来讲视频帧获取、目标检测与过滤、疲劳状态计算、分心行为判定。视频帧获取用OpenCV的VideoCapture搞定支持USB摄像头和视频文件。需要额外做的是帧率控制由于YOLOV5推理本身有耗时摄像头采集到的原始帧率和实际处理帧率不一致我做法是设置一个间隔采样逻辑每处理3帧就跳过1帧防止视频流堆积延迟越来越大。目标检测与过滤把YOLOV5检测结果中置信度低于0.45的框过滤掉然后根据类别ID分发给不同处理逻辑。person类交给人体关键点分析模块closed_eye和yawn类直接送入疲劳计数器phone_use类则送入分心行为判定模块。import cv2 import torch import numpy as np # 加载模型 model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadTrue) model.conf 0.45 # 置信度阈值 model.iou 0.5 # NMS IoU阈值 def process_frame(frame): results model(frame) detections results.pandas().xyxy[0] faces [] persons [] phones [] for _, det in detections.iterrows(): x1, y1, x2, y2 int(det[xmin]), int(det[ymin]), int(det[xmax]), int(det[ymax]) if det[name] person: persons.append((x1, y1, x2, y2)) elif det[name] in [closed_eye, yawn]: faces.append((x1, y1, x2, y2, det[name])) elif det[name] phone_use: phones.append((x1, y1, x2, y2)) return faces, persons, phones疲劳状态计算拿到人脸框后裁剪人脸ROI区域送入dlib的关键点检测器提取眼部和嘴部关键点然后算EAR和MAR嘴部纵横比用于判断打哈欠def eye_aspect_ratio(eye_points): # 计算EAR a np.linalg.norm(eye_points[1] - eye_points[5]) b np.linalg.norm(eye_points[2] - eye_points[4]) c np.linalg.norm(eye_points[0] - eye_points[3]) return (a b) / (2.0 * c) def mouth_aspect_ratio(mouth_points): # 计算嘴部开启程度张开超过0.6判定为打哈欠 a np.linalg.norm(mouth_points[2] - mouth_points[6]) b np.linalg.norm(mouth_points[0] - mouth_points[4]) return a / b分心行为判定这部分用到状态机思想。我不建议直接对每一帧做独立的“分心/不分心”判断因为单帧的误判率太高。正确的做法是给每个行为定义一个状态累计器低头看手机连续30帧判定为低头才触发警报频繁转头一分钟窗口内累计超过8次转头触发离岗连续120帧检测不到person类触发这种“持续时长累计次数”双维度判定逻辑能非常好地过滤掉间歇性误检。3.4 专注度评分算法设计专注度评分是整体系统的最终输出也是用户最关心的那部分。我采用一个百分制的评估模型初始分100分在各个检测事件触发时扣分事件类型扣分规则恢复规则闭眼非眨眼每次扣2分连续超过2.5秒扣5分恢复正常行为后每10秒恢复1分打哈欠每次扣3分同上低头看手机每次扣5分持续超过10秒扣10分停止行为后每15秒恢复2分频繁转头每分钟超过8次扣4分下一分钟正常则恢复2分离岗离岗期间每分钟扣15分返回岗位后每30秒恢复1分打分逻辑上有两个细节值得注意。第一所有恢复都是缓慢的不能检测到正常就瞬间拉回100分否则系统会变得像开关一样跳变用户根本来不及反应。第二分值的总分区间要控制在20-100分之间低于60分系统判定为“当前专注状态较差”通过UI面板的红色指示灯提醒现场人员关注。这个评分算法不需要特别复杂的机器学习模型本质上是一个动态阈值加权计算器但它的业务价值很高——管理者只需要看一个数字就能知道当前整体专注情况而不用去分析一堆行为标签。把复杂的感知结果转成直观的业务指标这是很多AI项目落地的关键一步。4. 常见问题与排查技巧实录4.1 模型训练不收敛或Loss值异常训练YOLOV5时最常遇到的坑是Loss值不降反升或者mAP一直为0。我遇到过两次原因分别是标签文件出问题YOLO格式的标签是txt文件里面每行是“类别ID x_center y_center width height”这些坐标都是归一化到0-1之间的值。如果标注工具导出的坐标是像素值训练时Loss就会疯狂震荡因为一个框的宽度可能占了整张图片的几十倍。排查方法很简单写一段代码检查labels目录下的txt文件看里面数值有没有大于1的异常值。我的经验是超过0.3这样的异常就该回头改标注了。类别ID错位data.yaml里的类别顺序必须和标注时的类别ID完全一致。我试过在data.yaml里写成[yawn, closed_eye, phone_use]但标注时closed_eye是0、yawn是1结果模型怎么训练都学不好因为编号对应关系全乱了。这种错位没有明显报错唯一的排查路径是随机挑几张训练图像把YOLOV5预标注的框显示出来人工看一眼类别ID和框的位置对不对。学习率过大导致的发散如果用的预训练权重是yolov5s.pt默认学习率0.01是合理的但如果是自定义复杂数据集或者数据量很少比如低于500张建议把学习率调整到0.001或者0.005否则前期loss下降很快中期突然发散到NaN。4.2 检测框抖动导致的疲劳误判这是整个系统上线后最影响体验的问题。明明人没有闭眼但检测框一直在跳人脸区域的裁剪不统一导致EAR值忽高忽低最后被误判成疲劳。分析下来的根因有三个第一YOLOV5的检测框天然存在微小抖动。解决思路是加入检测框的时序平滑。我使用的是简单的一阶低通滤波把当前帧的检测框坐标和上一帧的检测框坐标做加权平均x_new 0.6 * x_current 0.4 * x_previous y_new 0.6 * y_current 0.4 * y_previous这个方法效果立竿见影因为默认情况下检测输出波动幅度不大平滑后框的稳定性能提升很多。但要注意权重不能太低比如0.4和0.6反过来的话框会变得很“肉”响应不够及时。第二光照突变导致检测置信度波动。这个问题在窗户旁边的工位特别常见太阳被云遮住的瞬间画面亮度变化剧烈检测框会频繁跳变。我在图像预处理阶段加了自适应直方图均衡化CLAHE只对frame的局部进行对比度增强成本极低但效果显著。第三眨眼被误判成闭眼。常规眨眼时眼睛闭合时间一般在100到400毫秒之间而疲劳闭眼通常超过1秒。所以我在疲劳计数器里加了一个最小持续时间过滤只有闭眼状态持续超过0.5秒才进入闭眼计数器把正常眨眼直接过滤掉。这也是为什么4.1里强调不要单帧判定时序上下文信息对这类问题太重要了。4.3 部署到CPU机器上速度太慢YOLOV5的模型在GPU上能跑几十FPS但一旦部署没有独立显卡的机器上速度直接崩到个位数FPS。有两种提效方案我实测下来有效模型蒸馏与轻量化把yolov5s换乘yolov5nnano版本检测精度会掉大概3-5个点但推理速度提升一倍不止。在我的场景里专注性检测本身不需要极高精度的包围框检测nano版本完全够用。OpenCV DNN ONNX推理训练好的onnx格式可以直接用OpenCV的dnn模块加载比PyTorch的CPU推理速度快。配合FP16量化把模型精度从FP32降到FP16视觉任务一般不掉点在Intel i5-10400上实测从4FPS提升到12FPS左右。降低处理分辨率YOLOV5输入分辨率从640降到416检测精度会有轻微下降但速度提升到接近两倍。我建议在UI设置里加一个“性能/精度”切换选项让用户根据自己的硬件条件选择。一个重要提醒不要指望所有检测都实时跑。对于专注性检测真正需要高频处理的是人脸区域的关键点分析人体检测和分心行为检测只需要每秒处理2-3帧就够了。把任务分频处理能大幅降低CPU占用率。4.4 标签与代码逻辑的常见匹配问题这类综合检测系统里有一个特别隐蔽的坑就是状态记录和标签不匹配。比如你在训练模型时定义了closed_eye、yawn、phone_use三个类别代码里判断的也是这三个名字但模型预测出来的结果可能是motorcycle、truck这类来的值——这些都是COCO预训练类别里继承来的。排查方法在模型加载完成后用一行代码打印模型的所有类别名跟data.yaml里的定义对比避免手滑写错。print(model.names)模型推理结果里的det[name]直接对应model.names里的字符串。如果发现类别名对不上优先检查模型加载路径是不是指向了错误的权重文件。另外多路视频流并发检测时状态计数器是共享变量还是每路单独维护也容易出问题。建议用字典结构按摄像头ID隔离所有状态比如attention_status { 1: {fatigue_count: 0, phone_count: 0, active: True}, 2: {fatigue_count: 0, phone_count: 0, active: True} }而不是把所有路的状态混在一个全局变量里否则两路信号互相干扰报警逻辑直接乱套。5. 项目源码结构解读与二次开发建议5.1 源码目录结构与模块划分最终整理出来的项目源码采用清晰的模块化结构方便二次开发attention_detection/ ├── models/ │ ├── yolov5s.pt # 基础检测模型权重 │ └── best.pt # 自定义类别闭眼/哈欠/手机权重 ├── core/ │ ├── detector.py # YOLOV5模型封装提供检测接口 │ ├── face_landmark.py # 人脸关键点提取dlib/MediaPipe │ ├── fatigue.py # 疲劳检测逻辑EAR/PERCLOS/MAR │ ├── distraction.py # 分心行为判定逻辑 │ └── attention_score.py # 专注度评分算法 ├── ui/ │ ├── main_window.py # PyQt5界面 │ └── camera_view.py # 视频流显示控件 ├── utils/ │ ├── video_reader.py # 多路视频流管理 │ └── config.py # 全局参数配置 ├── data/ │ └── data.yaml # 训练数据配置 ├── weights/ │ └── best.pt # 最佳权重 └── run.py # 主启动入口这个目录设计的核心是把感知层、逻辑层、展示层完全解耦。检测器只负责给出“这人是谁、在什么位置”的感知结果疲劳和分心模块只负责根据感知结果做状态判定评分算法只负责吃进状态、吐出分数UI只负责把分数可视化。任何一个模块替换或升级都不会牵连其他部分这对后续扩展非常重要。5.2 多路摄像头的接入与异构场景适配实际部署常常不只一路摄像头比如一间教室有三台摄像头一台对准讲台、一台对准左侧学生区、一台对准右侧。我在这套项目里实现了多路视频流的接入逻辑本质上是在video_reader.py里维护一个VideoCapture对象列表然后用多线程方式并行读取每路视频独立跑检测流程。这里要特别强调一个工程经验多路视频流处理时千万不要在主GUI线程里跑检测否则界面会卡死直到用户以为程序崩溃。正确做法是每路视频开启一个QThread后台线程检测完的结果通过信号槽机制发回UI线程更新画面。实测三路720P视频在RTX 3060上总延迟能控制在300毫秒以内。异构场景的适配我通过config.py集中管理参数比如不同场景可以配置不同的警报阈值CONFIG { classroom: { ear_threshold: 0.18, phone_continuous_frames: 30, leave_time_threshold: 90, }, office: { ear_threshold: 0.2, phone_continuous_frames: 45, leave_time_threshold: 120, }, driver: { ear_threshold: 0.22, phone_continuous_frames: 10, leave_time_threshold: 15, } }不同业务场景对“分心”的容忍度是不一样的。课堂可以容忍学生偶尔低头但驾驶员低头看手机一秒都危险。把阈值参数化部署时只要改config文件就行不需要动代码。5.3 二次开发的扩展方向这个项目的架构留了三个非常明确的扩展口子第一个是行为类别扩展。目前只做了疲劳和看手机这两大类如果要加入“抽烟”“打架”“睡觉”等新行为只需要标注新数据、训练新模型、在distraction.py里加一个判定函数这三个步骤不会动到检测主流程。第二个是数据上报能力。现在的结果只是显示在本地UI上如果要接入管理者后台只需要把attention_score.py算出的分数通过HTTP或者MQTT协议发送出去。我已经在源码里留了一个report.py的占位文件往里面加POST请求就行。第三个是跟考勤系统的联动。专注性检测收集的状态数据天然有时间戳和人员ID可以用来生成个人专注度日报、周报。这是做教育场景SaaS产品非常看重的增量价值接入方只需要解析输出的结构化JSON日志不需要改检测逻辑。6. 性能调优与部署落地心得6.1 模型推理加速的实测对比我把不同推理后端的速度做过一轮实测机器是i5-10400 CPU GTX 1660 GPU输入分辨率640x640结果如下推理后端设备单帧耗时FPS备注PyTorch GPUGTX 166028ms35默认FP32TensorRT FP16GTX 166012ms83需TensorRT环境ONNX CPUi5-1040095ms10FP32精度ONNX CPUi5-1040062ms16FP16量化OpenCV DNN CPUi5-1040080ms12无需ONNX Runtime如果你准备在GPU服务器上做多路视频流分析TensorRT是最优解但环境配置相对麻烦。如果你是部署在普通办公电脑上ONNX OpenCV DNN路线够用且零额外依赖实属性价比之选。6.2 长时间运行的稳定性保障专注性检测系统通常需要长期待机运行一跑就是整天甚至整周。这类系统的稳定性要求比普通Web服务要高因为视频流断流、内存泄漏、显存溢出这些坑都会在长时间运行中暴露出来。我在这套系统中做了三处稳定性加固视频流自动重连每路VideoCapture对象启动一个守护线程检测到读取失败连续超过30帧就自动重新初始化摄像头连接。这在USB摄像头偶尔接触不良、网络摄像头断线的情况下非常好用避免系统静默失效。内存控制OpenCV的imdecode和Mat对象在长时间循环里会产生内存碎片我用一个每1000帧清理一次的定时器手动调用gc.collect()做垃圾回收。实测下来内存占用从稳定增长变为稳定持平。日志轮转会把检测结果、异常事件和系统状态写入日志文件。日志采用按天分文件存储单文件超过10MB自动切换防止磁盘空间被日志占满导致服务崩溃。除此之外运行模型推理的时候CUDA的graph显存缓存会在某些机器学习框架下持续累积如果长期不释放会导致显存溢出。解决办法是每处理5000帧调用一次torch.cuda.empty_cache()牺牲一丢丢性能换全程稳定性血赚。6.3 UI界面设计与交互逻辑从用户角度看这个系统主要的界面元素是实时视频画面展示、当前专注度分数、历史状态曲线和警报信息列表。实时视频画面展示我直接用OpenCV把检测框画在图像上不同类别用不同颜色区分。闭眼框用黄色打哈欠框用橙色玩手机框用红色人体框用绿色。习惯上颜色越暖代表严重级别越高管理者扫一眼画面就能定位问题区域。状态曲线用PyQt5的QChart控件绘制最近10分钟专注度分数折线图X轴是时间Y轴是分数。加上一个阈值线默认60分分数低于这条线时曲线颜色会从蓝色变成红色视觉冲击力很强。这个设计在客户实际使用中反馈非常好因为管理者不需要盯着一堆数字看趋势看颜色就行。警报消息列表每一条警报都带时间、摄像头位置、行为类型、处理状态四个字段。我建议在源码里预留一个“误报”按钮管理者可以一键标记某条警报为误报这些标记数据后续可以用来优化模型和阈值形成反馈闭环。界面整体设计原则是“一屏看懂”。不用设置一堆专业参数给操作员看真正的参数都在config.py里界面上只留开始/停止、截图、模式切换这几个核心按钮。越简单的界面在长期运行中越不容易误操作这是我从多个现场项目里得出的经验。7. 写在最后的实践建议整套系统实际用下来我个人最深的体会是人物专注性检测的技术难点不在模型精度本身而在于如何把模型输出转成稳定可靠、贴合业务语义的结论。模型只是一双眼睛真正判断“这个人是不是专注”的是后端那一套状态机、阈值逻辑和评分策略。所以开发这类项目时建议把至少一半精力放在状态定义和阈值调优上而不是一味刷模型指标。一个小技巧收尾调试疲劳检测阈值时不要只盯着单一指标的数值而是同时观察闭眼持续帧数、PERCLOS、MAR、头部姿态四个信号它们往往会同趋势变化。如果你看到EAR已经低到0.1但MAR没有变化大概率是光线问题导致关键点检测不准而不是人真的在睡觉。学会交叉验证信号这套系统的误报率能下降一大截。本文还有配套的精品资源点击获取
网站建设高端定制企业官网