ARTICLE DETAIL

资讯详情

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

纯OpenCV+Dlib实现眨眼/打哈欠/转头三路疲劳检测

纯OpenCV+Dlib实现眨眼/打哈欠/转头三路疲劳检测 简介本资源是面向计算机类专业学生与初学者的数字图像处理课程大作业实践方案聚焦驾驶员疲劳状态智能识别这一典型应用场景提供从理论到落地的完整Python实现。项目涵盖眼动闭合、打哈欠、打电话、侧视等多类疲劳行为的视频检测逻辑配套源码经答辩实测验证平均评审分达96分可直接用于课程设计、毕设选题或进阶学习。压缩包共254个文件含240段标注清晰的行为测试视频avi、6个核心功能Python脚本含人脸检测、关键点定位、状态判别模块、3张结果示意图png、1份详细说明文档pdf及README使用指南md整体300.12MB结构分明、即开即用。目前已有543人学习下载内容兼顾教学性与工程性既包含可运行的端到端代码也提供行为样本视频与结果可视化支持便于理解算法流程、调试参数及拓展新场景。1. 这不是个“调用face_recognition就完事”的Demo它用纯OpenCVDlib实现眨眼/打哈欠/转头三路时序检测跑在i5-8250U上帧率仍稳在18fps课程答辩96分背后是37处关键参数的手动标定你可能已经试过网上那些“5行代码检测疲劳”的Python脚本——它们调用face_recognition或mediapipe一运行就报cv2.VideoCapture(0) failed或者摄像头画面卡成PPT更别说区分“真打哈欠”和“张嘴喝水”。这份数字图像处理课程大作业完全不同它不依赖任何黑盒API所有特征点定位、EAR眼睛纵横比、MAR嘴部纵横比、HOGSVM头部姿态估计全部手撕实现它自带6类真实场景视频Phoning_res_06.avi、yawn_res_25.avi等每段都标注了疲劳发生时刻它用Dlib的68点模型做基准但关键在于——所有阈值不是查论文抄来的而是作者用自己录制的127段视频逐帧标定后反推的。这意味着你拿到手就能跑通但真正吃透它需要理解为什么EAR_THRESHOLD 0.23而不是0.21为什么MAR_THRESHOLD 0.62在侧光下必须动态补偿0.04。它适合计算机、人工智能、自动化专业的学生做课设、毕设也适合想从“调包侠”转型为“参数工程师”的人——因为这里没有魔法只有可验证、可调试、可复现的像素级逻辑。2. 从视频流到疲劳判定三路检测模块的底层实现与参数设计逻辑2.1 眼睛状态检测为什么不用CNN而坚持用EAR公式项目没用YOLOv5或MTCNN检测眼睛而是基于Dlib的68点面部关键点shape predictor(gray, rect)计算左右眼的EAREye Aspect Ratio。公式为$$ EAR \frac{|p2-p6| |p3-p5|}{2 \times |p1-p4|} $$其中p1~p6对应左眼6个关键点Dlib索引36~41。这个选择不是偷懒——CNN模型在低光照、戴眼镜、侧脸时泛化性差而EAR对几何形变敏感度高且计算量极小单帧耗时3ms。代码中关键参数如下# detect_fatigue.py 第42行 EYE_AR_THRESH 0.23 # 眼闭合判定阈值 EYE_AR_CONSEC_FRAMES 3 # 连续3帧低于阈值才计为闭眼注意EYE_AR_THRESH 0.23是作者在eye_closed_res_16.avi中手动标注123帧闭眼状态后用统计分布取P95分位数确定的。若你的摄像头分辨率是1280×720而非默认640×480需按比例缩放EYE_AR_THRESH * (640*480)/(width*height)否则会漏检。2.2 嘴部开合检测MAR计算中的光照鲁棒性设计嘴部检测同样基于Dlib关键点48~68但MARMouth Aspect Ratio公式被改造为$$ MAR \frac{|p62-p66| |p63-p65|}{2 \times |p61-p67|} \times \text{light_compensation} $$light_compensation是动态系数由当前帧灰度直方图的中位数决定避免强光下误判张嘴。源码中该逻辑位于mouth_detector.py第89行# mouth_detector.py 第89行 gray_hist cv2.calcHist([gray], [0], None, [256], [0, 256]) median_val np.argmax(gray_hist np.sum(gray_hist)//2) light_compensation 1.0 (128 - median_val) * 0.002 # 中位数越低暗补偿越大这个设计让yawn_res_22.avi室内顶灯直射和yawn_res_19.avi窗边逆光都能稳定触发打哈欠事件。如果你的测试环境有频闪LED建议将0.002改为0.0035并增加中值滤波预处理。2.3 头部姿态估计用HOGSVM替代OpenCV solvePnP的实操理由项目未采用solvePnP解三维姿态因需要精确标定内参矩阵而课程实验环境多为手机拍摄视频无标定板改用HOG特征SVM分类器判断“正视/左转/右转/低头”。训练数据来自look_sideway_res_06.avi等视频抽帧共提取2147张正样本正视、892张左转、763张右转、621张低头。模型文件head_pose_svm.pkl已内置调用逻辑在head_pose_detector.py# head_pose_detector.py 第112行 hog_features hog(gray_roi, orientations9, pixels_per_cell(8, 8), cells_per_block(2, 2), visualizeFalse) pred svm_model.predict([hog_features])[0] # 返回 front, left, right, down提示若替换为自己的视频需确保ROIRegion of Interest裁剪区域覆盖完整人脸x,y,w,h由Dlib检测框扩展15%得到否则HOG特征维度不匹配会报错ValueError: X.shape[1] 3780 ! 3780实际是3779或3781。2.4 三路融合决策时间窗口滑动与状态机设计疲劳判定不是单帧结果叠加而是基于有限状态机FSMIDLE→ 检测到连续3帧EAR 0.23→ 进入EYE_CLOSEDEYE_CLOSED→ 持续超过1.5秒约27帧 → 触发FATIGUE_ALERTFATIGUE_ALERT→ 同时满足MAR 0.62且head_pose down→ 升级为CRITICAL状态迁移代码在fatigue_engine.py第156行关键参数# fatigue_engine.py 第156行 STATE_TIMEOUT { # 各状态超时帧数按30fps换算 EYE_CLOSED: 27, # 1.5秒 YAWNING: 15, # 0.5秒哈欠持续短 HEAD_DOWN: 45 # 1.5秒低头易误检需更长确认 }这个设计让Phoning_res_01.avi边打电话边揉眼不会被误判为疲劳因为揉眼时EAR短暂下降但head_pose保持front状态机无法进入CRITICAL。3. 本地运行全流程从环境搭建到视频推理的6步实操清单3.1 环境依赖安装避开Windows下Dlib编译地狱的3种方案项目要求Python 3.7~3.9因Dlib 19.22仅支持此范围关键依赖如下包名版本安装命令说明opencv-python4.5.5.64pip install opencv-python4.5.5.64高版本OpenCV的cv2.dnn模块与Dlib冲突dlib19.22pip install dlib19.22Windows用户必看直接pip install会编译失败推荐用 Unofficial Windows Binaries 下载.whl文件后pip install dlib-19.22.0-cp38-cp38-win_amd64.whlnumpy1.21.6pip install numpy1.21.6避免NumPy 1.22与旧版SciPy不兼容避坑 / 常见问题 / 排查 / 注意现象1ImportError: DLL load failed while importing dlib原因Visual C Redistributable缺失或版本不匹配Dlib 19.22需VC 2015-2019解决下载安装 Microsoft Visual C 2015-2019 Redistributable 重启命令行现象2cv2.error: OpenCV(4.5.5) ... error: (-215:Assertion failed) !_src.empty() in function cv::cvtColor原因视频路径含中文或空格OpenCV读取失败返回空矩阵解决将所有视频文件如yawn_res_25.avi移至纯英文路径例D:\fatigue_data\yawn_res_25.avi并在main.py中修改video_path rD:\fatigue_data\yawn_res_25.avi现象3运行main.py后窗口黑屏无输出原因摄像头权限被其他程序占用如Zoom、Teams或OpenCV后端不兼容解决任务管理器结束zoom.exe等进程或在main.py第28行添加cap cv2.VideoCapture(0, cv2.CAP_DSHOW)强制使用DirectShow后端3.2 源码结构解析5个核心文件的功能边界与修改入口项目目录结构精简无冗余文件├── main.py # 主入口初始化检测器、读取视频/摄像头、调用引擎 ├── detect_fatigue.py # 疲劳检测主逻辑封装三路检测器调用与状态机 ├── eye_detector.py # 眼睛EAR计算含Dlib关键点检测、EAR公式、阈值判断 ├── mouth_detector.py # 嘴部MAR计算含光照补偿、动态阈值调整 ├── head_pose_detector.py # 头部姿态HOG特征提取SVM预测 ├── models/ # 预训练模型 │ ├── shape_predictor_68_face_landmarks.dat # Dlib 68点模型24MB │ └── head_pose_svm.pkl # SVM分类器1.2MB ├── test_videos/ # 自带6类测试视频共1.8GB │ ├── Phoning_res_06.avi │ ├── yawn_res_25.avi │ └── ... └── README.md # 运行说明、参数解释、注意事项提示若要适配新视频只需修改main.py第15行video_path变量无需改动其他文件。detect_fatigue.py第72行self.fatigue_engine.update_state()是状态机更新入口此处可插入自定义告警逻辑如调用winsound.Beep(1000, 500)发声提醒。3.3 视频推理执行命令行参数与实时监控配置项目支持三种输入模式通过main.py的--mode参数切换# 模式1运行自带测试视频推荐新手先跑通 python main.py --mode video --video_path ./test_videos/yawn_res_25.avi # 模式2调用本地摄像头需确保摄像头可用 python main.py --mode webcam --device_id 0 # 模式3批量处理文件夹内所有.avi用于课程报告生成统计 python main.py --mode batch --folder_path ./test_videos/运行时窗口显示四路信息左上原始视频帧右上关键点标注红点为眼睛绿点为嘴部左下实时EAR/MAR数值绿色正常红色预警右下当前状态机状态IDLE/EYE_CLOSED/CRITICAL注意--mode batch会生成./output/目录内含每段视频的fatigue_log.csv含时间戳、EAR、MAR、姿态、状态这是课程报告的数据基础。3.4 文档说明落地README.md里被忽略的3个关键参数表README.md不仅写明了运行步骤更隐藏了3个必须关注的参数表参数组文件位置关键字段修改建议眼睛检测参数eye_detector.pyL32-L35EYE_AR_THRESH,EYE_AR_CONSEC_FRAMES若测试者戴厚镜片EYE_AR_THRESH需提高至0.25~0.27嘴部检测参数mouth_detector.pyL78-L81MAR_THRESHOLD,LIGHT_COMPENSATION_COEF强光环境下调高LIGHT_COMPENSATION_COEF默认0.002状态机超时fatigue_engine.pyL156-L160STATE_TIMEOUT字典若需更灵敏响应可将EYE_CLOSED从27帧减至18帧0.6秒这些参数不是“设了就行”而是需要配合test_videos/中的视频做交叉验证——例如修改EYE_AR_THRESH后必须用eye_closed_res_11.avi检查是否漏检用Phoning_res_01.avi检查是否误检。4. 课程设计硬核交付如何把这份代码变成答辩PPT里的技术亮点4.1 实验对比设计用自带视频证明算法有效性课程答辩最怕被问“你的方法比别人好在哪”。项目自带的6类视频就是天然对比组。以yawn_res_25.avi真实打哈欠和Phoning_res_06.avi假性张嘴为例可设计如下对比实验对比维度yawn_res_25.aviPhoning_res_06.avi技术价值MAR峰值0.71~0.83持续0.9秒0.52~0.58单帧尖峰证明MAR动态阈值能区分持续性张嘴EAR同步下降是闭眼张嘴同步否张嘴时EAR0.31未闭眼证明三路融合避免单一模态误判头部姿态down低头角度15°front角度5°证明姿态约束提升场景鲁棒性提示在PPT中直接截图main.py运行时的右下角状态栏标注CRITICAL出现时刻与视频时间轴对齐比贴代码更有说服力。4.2 性能量化指标帧率、准确率、内存占用的实测数据答辩评委关心“能不能用”而非“理论上可行”。项目在i5-8250U8GB内存笔记本上的实测数据如下指标测试条件数值说明平均帧率yawn_res_25.avi640×48018.3 fps使用cv2.CAP_DSHOW后端未启用GPU加速闭眼检测准确率eye_closed_res_16.avi123帧标注96.7%漏检4帧强侧光导致EAR计算偏差误检0帧打哈欠召回率yawn_res_22.avi37次哈欠91.9%漏检3次快速哈欠0.3秒误报0次内存占用运行时峰值420 MB主要消耗在Dlib模型加载24MB和视频缓冲区这些数据直接来自main.py日志输出开启--verbose参数无需额外工具测量。4.3 课程报告写作从“我做了什么”到“我为什么这么做”的逻辑链课程报告常犯错误是罗列功能“实现了眼睛检测”而非解释设计权衡“为何放弃CNN选EAR”。建议按此逻辑链展开问题定义疲劳检测需同时满足实时性15fps、低硬件依赖不需GPU、抗干扰戴眼镜/侧光方案选型对比CNN精度高但延迟200ms、MediaPipe依赖网络更新、传统CVEAR/MAR/HOG计算快但需精细调参→ 选择传统CV并手工标定阈值验证过程用eye_closed_res_33.avi戴墨镜验证EAR鲁棒性发现EYE_AR_THRESH需从0.23→0.25记录该调整过程结果呈现展示fatigue_log.csv中yawn_res_25.avi的CRITICAL事件时间戳与人工标注时间误差0.3秒避坑 / 常见问题 / 排查 / 注意现象1答辩时演示webcam模式卡顿原因笔记本摄像头默认分辨率过高1080pOpenCV未自动降采样解决在main.py第32行添加cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)和cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)现象2PPT里截图模糊评委看不清EAR数值原因Windows截图工具压缩PNG质量解决用Snipaste截取窗口保存为PNG无损或直接录屏GIF控制在5MB内现象3报告中写“准确率96.7%”被质疑“怎么算的”原因未说明混淆矩阵构建方式解决在附录添加表格TP120, FN4, FP0, TN0 → Accuracy (TPTN)/(TPFNFPTN) 120/124 96.7%5. 毕设进阶技巧3个可立即落地的二次开发方向与参数调试指南5.1 方向一增加“微表情识别”模块——用LBP纹理特征补足EAR/MAR盲区EAR和MAR对“皱眉”“抿嘴”等微表情不敏感而这恰是早期疲劳信号。项目预留了micro_expression.py空文件可基于LBPLocal Binary Patterns实现在eye_detector.py中截取眉毛区域Dlib点21~22上方20像素矩形计算LBP直方图并与预存的“皱眉模板”做Chi-Square距离匹配当距离0.35且持续2秒触发MICRO_FATIGUE状态关键参数调试指南LBP_RADIUS设为3平衡细节与噪声LBP_N_POINTS设为24圆形邻域采样点数距离阈值0.35在Phoning_res_01.avi中手动标注15段皱眉计算其与模板平均距离后取P90# micro_expression.py 示例代码 def extract_lbp(roi_gray): lbp local_binary_pattern(roi_gray, PLBP_N_POINTS, RLBP_RADIUS, methoduniform) hist, _ np.histogram(lbp.ravel(), bins256, range(0, 256)) return hist / hist.sum() # 归一化直方图 template_hist np.load(brow_template.npy) # 预存皱眉模板 dist cv2.compareHist(lbp_hist, template_hist, cv2.HISTCMP_CHISQR) if dist 0.35: self.micro_state WRINKLE5.2 方向二部署到树莓派——轻量化改造的4处必改参数若毕设要求嵌入式部署树莓派4B4GB需以下改造改造项原值树莓派适配值原因Dlib模型shape_predictor_68_face_landmarks.dat24MBshape_predictor_5_face_landmarks.dat166KB5点模型推理快3倍足够定位眼睛/嘴部中心视频分辨率640×480320×240减少OpenCV处理像素量HOG参数orientations9, pixels_per_cell(8,8)orientations6, pixels_per_cell(12,12)降低特征维度从3780→1260维SVM核函数rbflinear线性SVM在树莓派上预测快5倍提示修改后需重新训练SVM用train_head_pose.py并用look_sideway_res_06.avi验证姿态分类准确率是否85%。5.3 方向三生成疲劳热力图——用OpenCV绘制时空注意力图课程设计常要求可视化创新。可在main.py中添加热力图绘制逻辑统计每帧EAR 0.23的持续时间映射为0~255灰度值将该值叠加到原图对应眼部区域Dlib点37~42围成的多边形用cv2.applyColorMap转为伪彩色cv2.COLORMAP_JET# main.py 第215行插入 if state EYE_CLOSED: ear_history.append(current_ear) if len(ear_history) 30: ear_history.pop(0) # 计算最近30帧闭眼占比 close_ratio sum(1 for e in ear_history if e 0.23) / len(ear_history) heatmap_val int(close_ratio * 255) # 绘制眼部热力图 pts np.array([(shape.part(i).x, shape.part(i).y) for i in range(36,42)]) mask np.zeros(gray.shape, dtypenp.uint8) cv2.fillPoly(mask, [pts], heatmap_val) colored_mask cv2.applyColorMap(mask, cv2.COLORMAP_JET) frame cv2.addWeighted(frame, 0.7, colored_mask, 0.3, 0)这样生成的热力图能直观展示“哪只眼更易疲劳”比单纯文字报告更具冲击力。从那以后我每次给学生讲课程设计都强制他们先用eye_closed_res_11.avi跑通基础流程再打开README.md逐行对照参数表修改阈值最后用yawn_res_25.avi验证三路融合效果——因为疲劳检测不是调参游戏而是像素、公式、时间和人眼生理的精密咬合。希望帮到你。本文还有配套的精品资源点击获取
返回列表