简介:本资源为基于卷积神经网络的人脸识别驾驶员疲劳检测与预警系统毕业设计完整项目包,面向计算机相关专业正在做毕设的学生及需要项目实战练习的学习者,也可作为课程设计或期末大作业参考。项目经导师指导并认可通过,包含全部源码、数据集与项目介绍,可直接作为毕设使用。压缩包共19个文件,以11个Python脚本为核心,辅以2个XML级联分类器文件、2个TXT说明、1个HDF5模型权重、1个EXE可执行程序及MD文档等,整体约78.33MB。内容涵盖人脸检测、眼部特征提取、CNN模型训练与评估、Tkinter界面交互等模块,并附有训练好的mini_XCEPTION模型文件,便于快速复现与二次开发。目前已有244人学习下载,适合希望掌握深度学习疲劳检测完整流程、积累项目经验的学习者参考。
1. 从一张打哈欠的截图说起:这套疲劳检测源码到底能跑出什么
实验室里最常被问的一句话是:“有没有那种能直接跑、还能当毕设交的疲劳检测项目?”我手上这套Python_FatigueDriving就是被问得最多的一份。它用 OpenCV 的 Haar 级联先框出人脸和眼睛,再把眼睛区域送进一个叫_mini_XCEPTION的轻量卷积神经网络做睁眼/闭眼二分类,连续多帧判定为闭眼就触发预警。整套东西不依赖 GPU,普通笔记本 CPU 就能推理,模型文件_mini_XCEPTION.102-0.66.hdf5只有几 MB,权重已经训练好,省掉了自己标注数据、跑几十轮训练的时间。
它适合三类人:正在做计算机相关毕业设计、需要一份能演示能答辩的完整工程的学生;想练手 CNN 图像分类但不想从零搭数据管线的学习者;以及要交课程设计、期末大作业的人。项目里带了tkinter_UI.py做的图形界面,还有打包好的tkinter_UI.exe,双击就能看效果,源码、数据集处理脚本、训练脚本、评估脚本一应俱全。下面我按“先搞懂它怎么判疲劳 → 再动手把环境跑通 → 最后说清楚哪些地方容易翻车”的顺序拆一遍,你照着做基本能复现。
2. 拆开_mini_XCEPTION:疲劳判定到底靠哪几个模块串起来
这套工程的核心不是某一个脚本,而是一条从摄像头帧到预警信号的流水线。理解这条线,后面调参、改逻辑、写论文里的“系统设计”章节才有东西可写。我把它拆成四个环节:人脸检测、眼睛定位、CNN 分类、时序判定。
2.1 Haar 级联做人脸和眼睛定位
haarcascade_files目录下有两个 XML:haarcascade_frontalface_default.xml和haarcascade_eye.xml。前者负责在整帧里找人脸,后者在人脸框内找眼睛。Haar 级联是 OpenCV 里最经典的检测器,优点是快、CPU 友好、不需要额外模型文件;缺点是侧脸、遮挡、暗光下容易漏检。工程里extract_face.py和detect_class.py都调了这两个文件。
常见做法是先用detectMultiScale拿人脸框,再把框的上半部分裁出来送进眼睛检测,因为下半张脸是嘴和下巴,搜眼睛纯属浪费算力。参数上scaleFactor=1.3、minNeighbors=5是比较稳的组合,minSize建议设成(30,30)以上,太小会框出一堆噪点。
import cv2 face_cascade = cv2.CascadeClassifier('haarcascade_files/haarcascade_frontalface_default.xml') eye_cascade = cv2.CascadeClassifier('haarcascade_files/haarcascade_eye.xml') gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, minSize=(30, 30)) for (x, y, w, h) in faces: roi_gray = gray[y:y + h // 2, x:x + w] # 只取上半脸找眼睛 eyes = eye_cascade.detectMultiScale(roi_gray, scaleFactor=1.1, minNeighbors=10)这段逻辑说明:scaleFactor控制每次缩放图像的步长,越小越慢但越不容易漏;minNeighbors是候选框被保留所需的最少邻居数,调大能压掉误检。眼睛检测的minNeighbors我一般设到 10,因为眼睛区域小,误检比人脸更烦。
2.2_mini_XCEPTION的输入输出与预处理
models目录下的_mini_XCEPTION.102-0.66.hdf5是一个 XCEPTION 的迷你版,输入尺寸是 64×64 灰度图,输出两个概率:睁眼、闭眼。文件名里的0.66是它在验证集上的准确率,102是训练轮次相关标记。load_and_process.py和data_provider.py负责把图片统一成这个尺寸和通道数。
关键预处理有三步:转灰度、缩放到 64×64、归一化到 0~1。顺序不能乱,先缩放再归一化,否则插值会引入偏差。cnn.py里定义了网络结构,evaluate.py用来在测试集上算准确率和混淆矩阵。
import cv2 import numpy as np def preprocess_eye(eye_img): eye_img = cv2.cvtColor(eye_img, cv2.COLOR_BGR2GRAY) # 转灰度 eye_img = cv2.resize(eye_img, (64, 64)) # 统一尺寸 eye_img = eye_img.astype('float32') / 255.0 # 归一化 eye_img = np.expand_dims(eye_img, axis=-1) # 加通道维 eye_img = np.expand_dims(eye_img, axis=0) # 加 batch 维 return eye_img参数说明:astype('float32')是 Keras/TensorFlow 的默认浮点类型,用float64会报类型不匹配;两次expand_dims分别补通道维和 batch 维,模型predict要求输入是(1,64,64,1)。这一步写错,报错信息通常是维度不匹配,别去改模型,先检查这里。
2.3 时序判定:为什么单帧闭眼不算疲劳
单帧闭眼可能只是眨眼,正常眨眼 100~400 毫秒。工程里用连续帧计数来区分:detect_class.py维护一个计数器,连续 N 帧判定为闭眼才触发预警。这个 N 就是灵敏度旋钮,设太小会频繁误报,设太大反应迟钝。我一般用 15~20 帧,按 30fps 算大约 0.5~0.7 秒。
tkinter_UI.py把摄像头画面、检测框、预警文字整合到一个窗口里,check.py像是调试用的单步检查脚本。整个数据流是:摄像头帧 → 人脸检测 → 眼睛检测 → 预处理 → CNN 推理 → 计数器累加 → 超阈值弹预警。
3. 把环境跑起来:从requirements.txt到摄像头出画面
这一章是动手部分。我按“装依赖 → 验证模型 → 跑主程序 → 跑界面”的顺序写,每步都给出可抄的命令和排查点。项目里运行说明.txt有基础说明,但有些细节它没写全,我补上。
3.1 依赖安装与版本对齐
requirements.txt里主要是opencv-python、tensorflow/keras、numpy、scikit-learn、matplotlib。这里最大的坑是 TensorFlow 版本和 hdf5 模型的兼容性。老工程常用 TF 1.x 或 TF 2.x 早期版本,新机器直接pip install tensorflow装到最新版,加载模型时可能报Unknown layer或bad marshal data。
python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt python -c "import tensorflow as tf; print(tf.__version__)"逻辑说明:先建虚拟环境隔离依赖,避免污染系统 Python。装完先打印 TF 版本,记下来。如果加载模型报错,常见做法是降到 TF 2.3~2.6 区间,或者用tf.keras.models.load_model时加compile=False。参数上opencv-python用 4.x 即可,Haar 级联文件在 4.x 里路径不变。
提示:如果
pip install tensorflow卡在下载,换国内镜像源,命令加-i https://pypi.tuna.tsinghua.edu.cn/simple。
3.2 验证模型能否正常加载
在跑摄像头之前,先单独验证模型文件没坏。这一步能省掉后面大量“到底是模型问题还是摄像头问题”的纠结。
from tensorflow.keras.models import load_model import numpy as np model = load_model('models/_mini_XCEPTION.102-0.66.hdf5', compile=False) print(model.input_shape) # 期望 (None, 64, 64, 1) print(model.output_shape) # 期望 (None, 2) dummy = np.zeros((1, 64, 64, 1), dtype='float32') print(model.predict(dummy))逻辑说明:compile=False跳过优化器和损失函数加载,只取网络结构和权重,能绕开不少版本兼容报错。input_shape和output_shape是判断模型是否匹配预处理的关键,如果输入不是 64×64×1,说明你拿错模型文件了。predict输出两个概率,和接近 1。
3.3 跑通主检测脚本与 UI
模型验证通过后,先跑detect_class.py看命令行输出,再跑tkinter_UI.py看界面。tkinter_UI.exe是打包好的,但建议先用源码跑,方便看报错。
python detect_class.py # 命令行检测,看是否弹预警 python tkinter_UI.py # 图形界面版如果摄像头打不开,检查cv2.VideoCapture(0)的索引,外接摄像头可能是 1。如果画面卡顿,把帧率降下来或跳帧处理,每两帧检测一次。tkinter_UI.py里预警逻辑和detect_class.py基本一致,只是多了界面刷新。
3.4 训练与评估脚本怎么用
split_train_test.py划分数据集,load_and_process.py加载并预处理,cnn.py定义模型,baojin.py应该是训练入口(名字可能是拼音“报警”或作者标记),evaluate.py出评估指标。想自己重训或改网络,按这个顺序走。
python split_train_test.py # 生成训练/测试划分 python baojin.py # 训练,产出新的 hdf5 python evaluate.py # 评估准确率、混淆矩阵参数说明:训练脚本里batch_size、epochs、学习率是三个主要旋钮。数据量小的时候batch_size设 32~64,epochs设 50~100,配合早停。evaluate.py输出的混淆矩阵能看出是睁眼误判多还是闭眼漏判多,据此调分类阈值。
4. 避坑与排查:这套源码最容易翻车的五个地方
这一章是我踩过的坑,按“现象 → 原因 → 解决”写。你跑不通的时候,大概率能在这里找到对应条目。
4.1 模型加载报Unknown layer或bad marshal data
现象:load_model直接抛异常,程序起不来。原因:hdf5 是旧版 Keras 保存的,新版 TensorFlow 的 Keras 反序列化不认。解决:先试compile=False;不行就降 TF 版本到 2.3~2.6;再不行用h5py手动读权重再灌进同结构网络。我一般优先降版本,最省事。
4.2 摄像头画面正常但永远不预警
现象:人脸框出来了,眼睛也框了,但闭眼不触发。原因:多半是时序计数器阈值设太大,或者 CNN 输出被当成睁眼。解决:先把计数器阈值临时调到 3 看是否触发,确认链路通;再打印每帧的闭眼概率,看是否普遍偏低。如果概率一直接近 0,检查预处理是否漏了归一化或通道维。
4.3 眼睛检测框乱跳、框到眉毛或眼镜
现象:眼睛框不稳定,CNN 输入的是眉毛区域。原因:haarcascade_eye.xml对眼镜和眉毛敏感,minNeighbors太小。解决:把眼睛检测的minNeighbors调到 10~15,minSize设(20,20),并限制只在上半脸搜索。戴眼镜的场景误检率高,这是 Haar 的固有局限,不是代码 bug。
4.4tkinter_UI.exe双击闪退
现象:exe 打开一瞬间就没了。原因:打包时没带 Haar XML 和模型文件,或者路径写的是绝对路径。解决:用源码跑tkinter_UI.py看报错;如果要用 exe,确保 XML 和 hdf5 和 exe 在同一目录,且代码里用相对路径。打包工具用 PyInstaller 时加--add-data把资源文件带进去。
4.5 训练时 loss 不降或准确率卡在 0.5
现象:自己重训,模型学不动。原因:数据没打乱、标签和图片不对应、学习率太大。解决:检查data_provider.py里图片和标签的对应关系,确认split_train_test.py划分后没有重叠;学习率从 1e-3 降到 1e-4 试;batch_size太小也会导致梯度震荡。先拿预训练模型跑通推理,再动训练。
5. 进阶玩法:把预警从“弹文字”改成“能落地的完整闭环”
跑通只是起点。答辩时老师常问“你这系统除了弹个框还能干嘛”,这时候需要把预警做成闭环。我一般会加三样东西:预警日志、声音提示、以及一个可调的灵敏度面板。
预警日志用logging模块,每次触发写一条带时间戳的记录,方便事后统计疲劳发生频率。声音提示用winsound(Windows)或playsound,比纯文字更直观。灵敏度面板在tkinter_UI.py里加一个Scale控件,绑定计数器阈值,实时可调,演示时很加分。
import logging import winsound logging.basicConfig(filename='fatigue_log.txt', level=logging.INFO, format='%(asctime)s - %(message)s') def trigger_alarm(frame_count): logging.info(f'疲劳预警触发,连续闭眼帧数: {frame_count}') winsound.Beep(1000, 500) # 1000Hz 响 500ms逻辑说明:logging的format里asctime自动带时间,filename指定日志文件。winsound.Beep两个参数是频率和时长,Windows 自带,不用额外装库。跨平台的话换成playsound播一个 wav。
验证方法上,我习惯用一段预先录好的打哈欠视频代替实时摄像头,这样每次测试条件一致,能对比不同阈值下的误报率和漏报率。把视频喂给detect_class.py,统计触发次数,画一条阈值-误报曲线,论文里的“实验分析”章节就有数据了。
注意:调灵敏度时别只看单次演示效果,要在不同光照、戴不戴眼镜、正脸侧脸几种条件下各跑一遍,取一个折中值。我吃过亏,演示当天换了间教室,光照一变误报翻倍。
从那以后我每次改完阈值,都强制用同一段测试视频跑三遍取平均,再上摄像头。这套源码的价值不在于模型多先进,而在于它把数据、训练、推理、界面、打包整条链路都摆出来了,你能顺着改、顺着加,把它变成自己的东西。希望帮到你。
本文还有配套的精品资源,点击获取