用Python和Keras从零搭建疲劳驾驶检测器:MTCNN人脸对齐与CNN分类实战
用Python和Keras从零搭建疲劳驾驶检测器MTCNN人脸对齐与CNN分类实战在智能交通领域驾驶员状态监测正成为保障道路安全的关键技术。本文将带您从零构建一个基于视觉分析的疲劳检测系统通过MTCNN实现毫秒级人脸对齐结合自定义CNN模型完成眼部状态分类最终运用PERCLOS算法实现疲劳程度量化。整个过程仅需普通USB摄像头和Python环境特别适合想掌握完整AI项目落地流程的开发者。1. 开发环境配置与依赖安装在开始编码前需要搭建支持深度学习的Python环境。推荐使用Anaconda创建独立环境以避免依赖冲突conda create -n fatigue_detection python3.8 conda activate fatigue_detection核心依赖包包括pip install tensorflow2.6.0 pip install keras2.6.0 pip install opencv-python pip install mtcnn # MTCNN的Python实现注意若使用GPU加速需单独安装CUDA 11.2和cuDNN 8.1并安装tensorflow-gpu版本验证MTCNN是否安装成功from mtcnn import MTCNN detector MTCNN() print(MTCNN initialized successfully!)常见安装问题解决方案错误类型可能原因解决方法CUDA out of memory显存不足降低MTCNN检测阈值或缩小输入图像尺寸ImportError: libcudart.soCUDA路径未正确配置在.bashrc中添加export LD_LIBRARY_PATH/usr/local/cuda/lib64No module named keras虚拟环境未激活使用conda activate fatigue_detection激活环境2. MTCNN人脸检测与关键点定位实战MTCNN的三级级联网络结构使其在复杂环境下仍能保持高精度P-Net快速生成候选窗口R-Net过滤非人脸区域O-Net精确定位5个关键点实现实时视频流处理import cv2 from mtcnn import MTCNN cap cv2.VideoCapture(0) detector MTCNN(min_face_size50) while True: ret, frame cap.read() if not ret: break # 转换为RGB格式 rgb_frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 检测人脸 results detector.detect_faces(rgb_frame) for result in results: # 绘制人脸框 x, y, w, h result[box] cv2.rectangle(frame, (x,y), (xw,yh), (0,255,0), 2) # 标记关键点 for key, value in result[keypoints].items(): cv2.circle(frame, value, 2, (0,0,255), -1) cv2.imshow(Face Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()关键参数调优建议min_face_size控制最小检测人脸尺寸像素值越小检测越慢thresholds调整三个网络的置信度阈值默认[0.6, 0.7, 0.7]factor图像金字塔缩放因子默认0.7093. 眼部区域精确裁剪与对齐基于MTCNN输出的5个关键点我们可以实现精准的眼部区域提取import math import numpy as np def get_eye_region(keypoints, frame, expand_ratio0.2): 根据关键点提取眼部区域 :param keypoints: MTCNN返回的关键点字典 :param frame: 原始图像帧 :param expand_ratio: 区域扩展比例 :return: 左眼和右眼ROI left_eye keypoints[left_eye] right_eye keypoints[right_eye] # 计算两眼间距 eye_distance math.sqrt((right_eye[0]-left_eye[0])**2 (right_eye[1]-left_eye[1])**2) # 计算眼部区域尺寸 eye_width int(eye_distance * 0.7) eye_height int(eye_width * 0.5) # 左眼ROI left_eye_x1 int(left_eye[0] - eye_width * expand_ratio) left_eye_y1 int(left_eye[1] - eye_height * expand_ratio) left_eye_x2 int(left_eye[0] eye_width * (1 expand_ratio)) left_eye_y2 int(left_eye[1] eye_height * (1 expand_ratio)) left_eye_roi frame[left_eye_y1:left_eye_y2, left_eye_x1:left_eye_x2] # 右眼ROI right_eye_x1 int(right_eye[0] - eye_width * expand_ratio) right_eye_y1 int(right_eye[1] - eye_height * expand_ratio) right_eye_x2 int(right_eye[0] eye_width * (1 expand_ratio)) right_eye_y2 int(right_eye[1] eye_height * (1 expand_ratio)) right_eye_roi frame[right_eye_y1:right_eye_y2, right_eye_x1:right_eye_x2] return left_eye_roi, right_eye_roi眼部对齐处理流程计算两眼连线角度进行仿射变换使双眼水平统一裁剪为64×64像素的输入尺寸def align_eye(eye_roi): 眼部图像标准化处理 # 转为灰度图 gray cv2.cvtColor(eye_roi, cv2.COLOR_BGR2GRAY) # 直方图均衡化 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8)) equalized clahe.apply(gray) # 尺寸归一化 resized cv2.resize(equalized, (64, 64)) # 归一化到[0,1]范围 normalized resized.astype(float32) / 255.0 # 增加通道维度 return np.expand_dims(normalized, axis-1)4. CNN分类模型构建与训练我们设计一个轻量级CNN网络结构在保证精度的同时实现实时推理from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, BatchNormalization def build_eye_state_model(input_shape(64,64,1), classes2): model Sequential([ # 第一卷积块 Conv2D(32, (3,3), activationrelu, input_shapeinput_shape), BatchNormalization(), MaxPooling2D((2,2)), Dropout(0.25), # 第二卷积块 Conv2D(64, (3,3), activationrelu), BatchNormalization(), MaxPooling2D((2,2)), Dropout(0.25), # 第三卷积块 Conv2D(128, (3,3), activationrelu), BatchNormalization(), MaxPooling2D((2,2)), Dropout(0.25), # 全连接层 Flatten(), Dense(256, activationrelu), BatchNormalization(), Dropout(0.5), # 输出层 Dense(classes, activationsoftmax) ]) model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy]) return model数据增强策略对提升模型鲁棒性至关重要from keras.preprocessing.image import ImageDataGenerator train_datagen ImageDataGenerator( rotation_range15, width_shift_range0.1, height_shift_range0.1, shear_range0.1, zoom_range0.1, horizontal_flipTrue, fill_modenearest) # 示例数据集结构 dataset/ train/ open_eye/ image1.jpg image2.jpg ... closed_eye/ image1.jpg ... val/ open_eye/ closed_eye/模型训练最佳实践使用EarlyStopping防止过拟合采用ReduceLROnPlateau动态调整学习率保存验证集上表现最好的模型from keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint callbacks [ EarlyStopping(patience10, verbose1), ReduceLROnPlateau(factor0.1, patience5, verbose1), ModelCheckpoint(best_model.h5, save_best_onlyTrue) ] history model.fit( train_generator, steps_per_epochlen(train_generator), epochs50, validation_dataval_generator, validation_stepslen(val_generator), callbackscallbacks )5. PERCLOS疲劳度计算与系统集成PERCLOSPercentage of Eyelid Closure Over the Pupil是业界公认的疲劳评估标准其核心计算公式为PERCLOS (眼睛闭合帧数 / 总检测帧数) × 100%实现实时疲劳度监测class FatigueDetector: def __init__(self, window_size30, threshold0.7): self.eye_state_history [] self.window_size window_size # 统计窗口大小帧数 self.threshold threshold # 疲劳判定阈值 def update(self, eye_state): 更新眼部状态记录 self.eye_state_history.append(eye_state) if len(self.eye_state_history) self.window_size: self.eye_state_history.pop(0) def get_perclos(self): 计算当前PERCLOS值 if not self.eye_state_history: return 0.0 closed_frames sum(1 for state in self.eye_state_history if state closed) return (closed_frames / len(self.eye_state_history)) * 100 def is_fatigued(self): 判断是否达到疲劳状态 return self.get_perclos() self.threshold完整系统集成示例def main(): # 初始化组件 cap cv2.VideoCapture(0) detector MTCNN() model load_model(best_model.h5) fatigue_detector FatigueDetector() while True: ret, frame cap.read() if not ret: break # 人脸检测 rgb_frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) faces detector.detect_faces(rgb_frame) for face in faces: # 眼部区域提取 left_eye, right_eye get_eye_region(face[keypoints], frame) # 预处理 left_eye_processed align_eye(left_eye) right_eye_processed align_eye(right_eye) # 状态预测 left_pred model.predict(np.array([left_eye_processed])) right_pred model.predict(np.array([right_eye_processed])) # 更新疲劳检测 avg_state closed if (left_pred[0][1] right_pred[0][1])/2 0.5 else open fatigue_detector.update(avg_state) # 可视化 perclos fatigue_detector.get_perclos() color (0, 0, 255) if fatigue_detector.is_fatigued() else (0, 255, 0) cv2.putText(frame, fPERCLOS: {perclos:.1f}%, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2) cv2.imshow(Fatigue Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()性能优化技巧多线程处理将视频采集与模型推理分离到不同线程模型量化使用TensorFlow Lite减小模型体积异步检测每3帧进行一次完整检测中间帧使用跟踪算法# 使用TensorFlow Lite进行模型量化 converter tf.lite.TFLiteConverter.from_keras_model(model) tflite_model converter.convert() with open(model.tflite, wb) as f: f.write(tflite_model)在实际部署中发现将输入图像尺寸从64×64降低到48×48可使推理速度提升40%而精度仅下降2%左右。对于嵌入式设备部署建议使用MobileNetV3等轻量级架构替代标准CNN。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2492423.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!