
简介这份毕业设计资源面向计算机相关专业学生与Python初学者提供一套基于卷积神经网络的人脸识别驾驶员疲劳检测与预警系统完整源码可用于课程设计、毕设答辩或深度学习入门实践。压缩包共15个文件约2.8MB包含3个py主程序与界面脚本、1个ui界面文件、4个xml工程配置、2个txt依赖与说明、1个whl离线安装包及md文档、png需求图等覆盖从环境搭建到界面运行的完整链路。资源中附带dlib离线安装包与requirements依赖清单便于在Windows环境下快速复现main.py与main_ui.py分工明确配合ui文件可直观查看检测界面逻辑README与需求图则帮助理解系统设计思路与功能边界。目前已有364人学习下载适合希望以人脸疲劳检测为切入点掌握CNN模型调用、界面交互与工程组织方式的读者参考借鉴。1. 从一份能跑起来的毕设包说起Python 卷积神经网络人脸识别疲劳检测到底交付了什么如果你正在为毕业设计选题发愁或者已经选了「基于深度学习的人脸识别疲劳检测」却卡在环境配置和模型跑不通上这份 Python 卷积神经网络人脸识别驾驶员疲劳检测与预警系统压缩包大概率能帮你省掉两周的摸索时间。它不是一篇论文也不是一个在线演示而是一个完整的、带 UI 界面的本地可运行工程main.py 是入口main_ui.py 和 main.ui 负责界面test.py 用来做单点验证requirements.txt 锁定了依赖版本甚至贴心地附带了 dlib-19.8.1-cp36-cp36m-win_amd64.whl 这个在 Windows 上出了名难装的轮子。核心逻辑是用摄像头或视频流抓取驾驶员面部通过卷积神经网络判断眼睛闭合程度和嘴巴开合状态当疲劳特征持续超过阈值时触发预警。适合谁适合需要快速搭出可演示系统的本科生也适合想拿一个完整 pipeline 做二次开发的初级算法工程师。但要注意它不是一个工业级产品而是一个教学级原型理解这一点后面的坑你才不会踩得莫名其妙。2. 拆开压缩包文件结构、依赖链与 CNN 疲劳判定的技术选型2.1 目录里每个文件到底干什么用拿到压缩包先别急着双击 main.py花三分钟把文件清单过一遍能避免后面 80% 的「ModuleNotFoundError」。我按实际运行时的调用关系给你捋一遍文件/目录作用是否必须main.py程序主入口初始化摄像头、加载模型、启动 UI 事件循环是main_ui.py由 main.ui 编译生成的 Python 界面代码负责控件布局和信号槽是main.uiQt Designer 源文件改界面时编辑它再重新编译否但建议保留test.py单张图片或短片段测试脚本用来验证模型是否正常加载建议保留requirements.txt依赖清单包含 opencv-python、dlib、keras、tensorflow 等是dlib-19.8.1-cp36-cp36m-win_amd64.whlWindows 下 Python 3.6 的 dlib 预编译轮子Windows 必用pycachePython 字节码缓存可删否.idea / *.iml / workspace.xmlPyCharm 工程配置换 IDE 可删否README.md简要说明通常写运行命令和注意事项建议读关于系统.txt / 需求.png设计说明和需求截图写论文时可直接引用写论文时有用这里最关键的认知是main.ui 和 main_ui.py 是「源文件」和「生成文件」的关系。如果你直接改 main_ui.py下次用 pyuic 重新编译 main.ui 时改动会被覆盖。常见做法是改 main.ui然后运行pyuic5 main.ui -o main_ui.py重新生成。很多同学改了半天界面没生效就是栽在这个关系上。2.2 为什么选 CNN 而不是传统特征点方法疲劳检测的经典路线有两条一条是用 dlib 的 68 个面部特征点算 EAR眼睛纵横比和 MAR嘴巴纵横比纯几何规则另一条是直接把眼部或嘴部区域裁出来送进卷积神经网络做二分类。这份毕设走的是第二条路但保留了 dlib 做面部对齐和区域裁剪。为什么这么选几何规则在正面、光照均匀时很准但驾驶员一歪头、戴眼镜、夜间红外补光不足EAR 就会剧烈抖动误报率飙升。CNN 的优势在于它学的是纹理和结构特征对姿态和光照的鲁棒性明显更好。但纯 CNN 又需要大量标注数据所以这份工程的做法是dlib 负责「找到脸和关键区域」CNN 负责「判断这个区域是不是疲劳状态」。这是一种典型的混合 pipeline也是目前教学项目里最稳妥的方案。代价是什么dlib 的安装极其痛苦尤其在 Windows Python 3.6 环境下源码编译需要 CMake 和 Visual Studio 构建工具新手基本卡死。所以作者直接附了 whl 轮子这是这份资源最实在的地方之一。2.3 依赖安装先装 whl 再装 requirements不要一上来就pip install -r requirements.txtdlib 会卡住甚至报错。正确顺序是先手动装 whl再装其余依赖。下面是我验证过的命令序列# 第一步确认 Python 版本是 3.6.x且是 64 位 python --version # 输出应为 Python 3.6.x # 第二步先装 dlib 的预编译轮子注意路径要指向你解压后的实际位置 pip install dlib-19.8.1-cp36-cp36m-win_amd64.whl # 第三步再装其余依赖 pip install -r requirements.txt # 第四步验证 dlib 和 cv2 能否正常导入 python -c import dlib; import cv2; print(dlib.__version__, cv2.__version__)逻辑说明dlib 的 whl 文件名里cp36表示 CPython 3.6win_amd64表示 64 位 Windows。如果你的 Python 是 3.7 或 3.8这个 whl 装不上会提示「is not a supported wheel on this platform」。解决办法要么换 Python 3.6要么自己找对应版本的 dlib 轮子。requirements.txt 里的 tensorflow 和 keras 版本也要和 Python 3.6 匹配常见组合是 tensorflow 1.14 或 2.x 的早期版本具体以文件内容为准。提示如果你用 Anaconda建议单独建一个 Python 3.6 的虚拟环境避免和 base 环境里的包冲突。命令是conda create -n fatigue python3.6然后激活再执行上面的步骤。3. 跑通主流程从摄像头帧到疲劳预警的完整代码链路3.1 main.py 的启动逻辑与参数入口main.py 是整个系统的调度中心。它通常做四件事初始化摄像头、加载 CNN 模型权重、启动 Qt 界面、把视频帧循环绑定到界面刷新。你不需要逐行读懂但要知道改哪里能控制行为。下面是一个典型的启动段结构我按常见写法还原并加了注释# main.py 典型结构还原 import sys import cv2 import dlib from PyQt5.QtWidgets import QApplication from main_ui import Ui_MainWindow # 由 main.ui 生成 # 初始化检测器和预测器 detector dlib.get_frontal_face_detector() predictor dlib.shape_predictor(shape_predictor_68_face_landmarks.dat) model load_model(fatigue_cnn.h5) # 模型权重文件压缩包内通常有 # 疲劳判定阈值这两个参数是调优的核心 EAR_THRESHOLD 0.25 # 眼睛纵横比低于此值视为闭眼 CONSEC_FRAMES 20 # 连续多少帧闭眼后触发预警 cap cv2.VideoCapture(0) # 0 表示默认摄像头换视频文件填路径 app QApplication(sys.argv) window Ui_MainWindow() window.show() # 主循环读帧 - 检测人脸 - 裁剪眼部 - CNN 推理 - 更新界面 while True: ret, frame cap.read() if not ret: break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces detector(gray, 0) for face in faces: landmarks predictor(gray, face) # 取左眼区域送入 CNN 判断 left_eye extract_eye_region(gray, landmarks) pred model.predict(preprocess(left_eye)) if pred EAR_THRESHOLD: counter 1 else: counter 0 if counter CONSEC_FRAMES: trigger_alarm() # 触发预警可能是蜂鸣或界面弹窗 window.update_frame(frame) # 刷新界面显示 if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明这段代码的核心是「检测-裁剪-推理-计数-报警」五步。detector 负责找到人脸框predictor 给出 68 个关键点extract_eye_region 根据关键点索引裁出眼部小图CNN 对这张小图输出一个疲劳概率或 EAR 回归值counter 做时间累积超过 CONSEC_FRAMES 才报警。参数说明EAR_THRESHOLD 越低越不敏感适合光线差但驾驶员确实睁眼的场景CONSEC_FRAMES 越大越不容易误报但响应会变慢。我一般会把 CONSEC_FRAMES 设在 15 到 25 之间低于 10 基本没法用眨眼都会触发。3.2 用 test.py 做单点验证别直接上摄像头摄像头一开变量太多光线、角度、分辨率、驱动。一旦报错你根本不知道是模型问题还是硬件问题。test.py 的价值就是把这些变量固定下来。常见做法是让它读一张本地图片走完整个 pipeline把中间结果打印或保存出来。# test.py 单图验证脚本示例 import cv2 import dlib import numpy as np from keras.models import load_model detector dlib.get_frontal_face_detector() predictor dlib.shape_predictor(shape_predictor_68_face_landmarks.dat) model load_model(fatigue_cnn.h5) img cv2.imread(test_face.jpg) # 准备一张清晰的正面人脸图 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces detector(gray, 0) print(检测到人脸数量:, len(faces)) for i, face in enumerate(faces): landmarks predictor(gray, face) print(f第{i}张人脸关键点数量:, landmarks.num_parts) # 裁剪眼部并推理 eye extract_eye_region(gray, landmarks) cv2.imwrite(feye_{i}.jpg, eye) # 保存裁剪结果肉眼确认裁对了没 pred model.predict(preprocess(eye)) print(f第{i}张人脸疲劳预测值:, pred)逻辑说明先确认 detector 能检测到人脸再确认 predictor 返回 68 个点再确认裁剪出的眼部图是眼睛而不是眉毛或鼻子最后看模型输出是否在合理范围。参数说明test_face.jpg 要选正面、光照均匀、不戴墨镜的图。如果这一步就检测不到人脸后面摄像头环节不用试了先解决 dlib 模型文件路径问题。shape_predictor_68_face_landmarks.dat 这个文件压缩包里通常有如果没有需要单独下载注意它大约 100MB别下到损坏的版本。3.3 预警触发与界面联动的实现要点预警不是简单 print 一句话。这份工程里预警通常要同时做三件事界面状态栏变红、播放提示音、记录疲劳时间戳。界面联动靠的是 Qt 的信号槽机制。main_ui.py 里会定义好控件对象你在主循环里通过window.label_status.setText(疲劳)这类调用更新界面。# 预警触发与界面更新片段 from PyQt5.QtCore import QTimer import winsound # Windows 下播放提示音 def trigger_alarm(window): window.label_status.setText(疲劳预警) window.label_status.setStyleSheet(color: red; font-weight: bold;) winsound.Beep(1000, 500) # 频率 1000Hz持续 500ms # 记录时间戳方便写论文时做统计分析 with open(fatigue_log.txt, a) as f: f.write(f{time.strftime(%Y-%m-%d %H:%M:%S)} 疲劳触发\n)逻辑说明winsound 是 Windows 专用跨平台要用 pygame 或 Qt 的 QSound。参数说明Beep 的第一个参数是频率太高刺耳1000 到 2000 比较合适第二个参数是毫秒数500 足够引起注意又不会烦人。注意预警触发后不要每帧都写日志否则文件会爆炸常见做法是加一个冷却时间比如 5 秒内只记录一次。注意如果你在非 Windows 环境跑winsound 会直接报 ImportError。把这段换成print(\a)或者用 Qt 的 QApplication.beep() 更稳妥。4. 避坑与排查dlib 安装、模型加载和误报的血泪经验4.1 dlib 装不上提示 CMake 或 Visual Studio 缺失现象执行pip install dlib后卡在「Building wheel for dlib」然后报错提示找不到 CMake 或 cl.exe。原因dlib 包含 C 扩展pip 默认从源码编译而你的机器没有构建工具链。解决直接用压缩包里的 whl 轮子命令是pip install dlib-19.8.1-cp36-cp36m-win_amd64.whl。如果 Python 版本不匹配去下载对应 cp37、cp38 的轮子别硬编译。这是最省时间的做法没有之一。4.2 模型加载报错提示 Unknown layer 或 h5py 版本冲突现象load_model(fatigue_cnn.h5)抛出「Unknown layer: Sequential」或 h5py 相关错误。原因Keras 和 TensorFlow 版本不匹配或者保存模型时的 Keras 版本和当前环境不一致。解决先看 requirements.txt 里锁定的版本严格按它装。如果文件没写清楚常见组合是 tensorflow 1.14 keras 2.2.4或者 tensorflow 2.3 keras 2.4。另一个办法是用model tf.keras.models.load_model(..., compileFalse)跳过编译状态加载能绕过一部分自定义层问题。4.3 摄像头能开但检测不到人脸或框乱跳现象界面显示视频流但没有人脸框或者框在背景上乱跳。原因光照不足、摄像头分辨率太低、或者 dlib 的 detector 对侧脸和小脸不敏感。解决先换一张清晰正面图用 test.py 验证确认模型本身没问题。然后调detector(gray, 1)把第二个参数从 0 改成 1表示上采样一次能检测更小的脸代价是速度变慢。再不行就加一个简单的直方图均衡化gray cv2.equalizeHist(gray)对夜间红外画面提升明显。4.4 误报频繁正常眨眼也触发预警现象驾驶员明明睁着眼系统却不停报警。原因CONSEC_FRAMES 设得太小或者 EAR_THRESHOLD 设得太高。解决先把 CONSEC_FRAMES 调到 20 以上再把 EAR_THRESHOLD 降到 0.2 左右。更稳的做法是同时判断眼睛和嘴巴只有两者都满足疲劳条件才报警这叫「与逻辑」能大幅降低误报。代价是漏报率会上升需要根据实际场景权衡。4.5 打包成 exe 后模型文件找不到现象PyCharm 里跑得好好的用 PyInstaller 打包后提示模型文件不存在。原因打包后的程序工作目录变了相对路径失效。解决用sys._MEIPASS获取临时资源目录把模型文件和 dat 文件通过--add-data参数打进去。常见写法是import sys, os def resource_path(relative): if hasattr(sys, _MEIPASS): return os.path.join(sys._MEIPASS, relative) return os.path.join(os.path.abspath(.), relative) model load_model(resource_path(fatigue_cnn.h5))逻辑说明sys._MEIPASS是 PyInstaller 解压临时文件的目录打包时必须把模型文件声明为数据文件。参数说明--add-data fatigue_cnn.h5;.在 Windows 下用分号分隔源和目标Linux 下用冒号。这个坑不提前处理答辩现场打不开就尴尬了。5. 进阶调优与验证让疲劳判定从「能跑」到「敢演示」5.1 用 ROC 曲线找最佳阈值而不是拍脑袋EAR_THRESHOLD 和 CONSEC_FRAMES 这两个参数拍脑袋设也能跑但答辩时老师问「为什么是 0.25 不是 0.3」你就答不上来。正确做法是录一段包含清醒和疲劳两种状态的视频人工标注每一帧的真实标签然后跑一遍模型输出画 ROC 曲线找约登指数最大的点。下面是一个简化的验证脚本import numpy as np from sklearn.metrics import roc_curve, auc import matplotlib.pyplot as plt # y_true: 人工标注1 表示疲劳0 表示清醒 # y_score: 模型输出的疲劳概率 y_true np.load(labels.npy) y_score np.load(preds.npy) fpr, tpr, thresholds roc_curve(y_true, y_score) roc_auc auc(fpr, tpr) print(AUC:, roc_auc) # 找约登指数最大的阈值 youden tpr - fpr best_threshold thresholds[np.argmax(youden)] print(最佳阈值:, best_threshold) plt.plot(fpr, tpr, labelfAUC {roc_auc:.2f}) plt.plot([0, 1], [0, 1], k--) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.legend() plt.savefig(roc_curve.png)逻辑说明AUC 越接近 1 说明模型区分能力越强低于 0.8 就要考虑换模型或补数据。约登指数最大的点就是「真正率减假正率」最大的阈值兼顾了灵敏度和特异度。参数说明labels.npy 和 preds.npy 需要你自己采集和生成这是写论文时最有说服力的实验数据。如果 AUC 只有 0.6 左右别急着调阈值先检查标注是否准确、裁剪区域是否对齐。5.2 把单帧判定改成时序平滑减少玄学抖动单帧 CNN 输出天然会抖这一帧判疲劳下一帧判清醒体验很差。常见做法是加一个滑动窗口比如取最近 10 帧的平均值再和阈值比较。更进阶一点可以用 LSTM 对时序特征建模但对毕设来说属于过度设计。滑动窗口的代码很简单from collections import deque window deque(maxlen10) # 保存最近 10 帧的预测值 def smooth_predict(pred): window.append(pred) return sum(window) / len(window) # 返回滑动平均 # 在主循环里用 smooth_predict 替代原始 pred smoothed smooth_predict(pred) if smoothed 0.6: counter 1逻辑说明deque 的 maxlen 参数自动丢弃旧数据不用手动维护索引。参数说明窗口长度 10 是经验值太小平滑效果不够太大响应延迟明显。如果摄像头帧率是 30fps10 帧大约 0.33 秒人感觉不到延迟。这个改动虽小但演示时的观感提升非常明显属于性价比最高的优化。5.3 验证方法用录屏回放代替真人测试答辩前反复找同学坐摄像头前测试效率低还不稳定。更靠谱的做法是提前录几段视频一段正常驾驶、一段模拟打哈欠闭眼、一段低头看手机。然后用cv2.VideoCapture(test_video.mp4)替代摄像头索引跑完整流程统计报警次数和漏报次数。这样每次改参数都能快速回归不用求人配合。我一般会准备三段各 30 秒的视频覆盖白天、夜间和侧脸场景跑一遍只要两分钟比真人测试快十倍。从那以后我每次拿到这类毕设包都强制先跑 test.py 单图验证再跑录屏回放最后才开摄像头。这个顺序能帮你把环境问题、模型问题和硬件问题彻底分开省下的时间够你把论文的实验章节多写两千字。希望帮到你。本文还有配套的精品资源点击获取