拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于OpenCV的疲劳驾驶检测系统实现与优化

1. 项目概述疲劳驾驶检测系统是近年来计算机视觉技术在交通安全领域的重要应用。作为一名长期从事OpenCV开发的工程师我经常被问到如何实现一个可靠的驾驶员疲劳检测系统。这个项目通过摄像头实时捕捉驾驶员面部特征利用OpenCV进行图像处理和分析能够准确识别闭眼、打哈欠等疲劳特征及时发出预警信号。这个方案特别适合以下场景长途货运车辆的行车安全监控出租车/网约车公司的司机状态管理个人车主的安全驾驶辅助驾校学员的训练监控2. 核心算法设计2.1 人脸检测与关键点定位我们使用OpenCV的DNN模块加载预训练的ResNet-10人脸检测模型net cv2.dnn.readNetFromCaffe(prototxt, caffemodel) blob cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104.0, 177.0, 123.0)) net.setInput(blob) detections net.forward()对于检测到的人脸采用68点面部特征点检测模型predictor dlib.shape_predictor(shape_predictor_68_face_landmarks.dat) shape predictor(gray, face) points face_utils.shape_to_np(shape)2.2 眼部状态分析通过计算眼睛纵横比(EAR)来判断闭眼状态def eye_aspect_ratio(eye): # 计算垂直距离 A dist.euclidean(eye[1], eye[5]) B dist.euclidean(eye[2], eye[4]) # 计算水平距离 C dist.euclidean(eye[0], eye[3]) # 计算EAR值 ear (A B) / (2.0 * C) return ear当EAR值连续3帧低于0.2时判定为闭眼状态。2.3 哈欠检测算法通过嘴部关键点计算嘴部纵横比(MAR)def mouth_aspect_ratio(mouth): # 计算垂直距离 A dist.euclidean(mouth[2], mouth[10]) B dist.euclidean(mouth[4], mouth[8]) # 计算水平距离 C dist.euclidean(mouth[0], mouth[6]) # 计算MAR值 mar (A B) / (2.0 * C) return mar当MAR值超过0.5且持续时间超过1秒时判定为打哈欠行为。3. 系统实现细节3.1 视频流处理框架cap cv2.VideoCapture(0) # 使用默认摄像头 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: # 特征点检测 shape predictor(gray, face) points face_utils.shape_to_np(shape) # 眼部分析 left_eye points[lStart:lEnd] right_eye points[rStart:rEnd] ear (eye_aspect_ratio(left_eye) eye_aspect_ratio(right_eye)) / 2.0 # 嘴部分析 mouth points[mStart:mEnd] mar mouth_aspect_ratio(mouth) # 疲劳状态判断 if ear EYE_AR_THRESH: COUNTER 1 if COUNTER EYE_AR_CONSEC_FRAMES: cv2.putText(frame, DROWSINESS ALERT!, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)3.2 性能优化技巧多尺度检测优化# 设置检测参数提高性能 detector dlib.get_frontal_face_detector() # 使用较小的图像进行检测 small_frame cv2.resize(frame, (0,0), fx0.5, fy0.5)异步处理框架from threading import Thread class VideoStream: def __init__(self, src0): self.stream cv2.VideoCapture(src) self.grabbed, self.frame self.stream.read() self.stopped False def start(self): Thread(targetself.update, args()).start() return self def update(self): while True: if self.stopped: return self.grabbed, self.frame self.stream.read() def read(self): return self.frame def stop(self): self.stopped True4. 完整代码实现import cv2 import dlib import numpy as np from imutils import face_utils from scipy.spatial import distance as dist # 初始化参数 EYE_AR_THRESH 0.2 # 眼睛纵横比阈值 EYE_AR_CONSEC_FRAMES 3 # 连续帧数 MOUTH_AR_THRESH 0.5 # 嘴部纵横比阈值 MOUTH_AR_CONSEC_FRAMES 15 # 约1秒(假设15fps) # 初始化计数器 COUNTER 0 TOTAL 0 mCOUNTER 0 mTOTAL 0 # 加载人脸检测器和特征点预测器 detector dlib.get_frontal_face_detector() predictor dlib.shape_predictor(shape_predictor_68_face_landmarks.dat) # 获取眼睛和嘴部特征点索引 (lStart, lEnd) face_utils.FACIAL_LANDMARKS_IDXS[left_eye] (rStart, rEnd) face_utils.FACIAL_LANDMARKS_IDXS[right_eye] (mStart, mEnd) face_utils.FACIAL_LANDMARKS_IDXS[mouth] def eye_aspect_ratio(eye): # 计算垂直距离 A dist.euclidean(eye[1], eye[5]) B dist.euclidean(eye[2], eye[4]) # 计算水平距离 C dist.euclidean(eye[0], eye[3]) # 计算EAR值 ear (A B) / (2.0 * C) return ear def mouth_aspect_ratio(mouth): # 计算垂直距离 A dist.euclidean(mouth[2], mouth[10]) B dist.euclidean(mouth[4], mouth[8]) # 计算水平距离 C dist.euclidean(mouth[0], mouth[6]) # 计算MAR值 mar (A B) / (2.0 * C) return mar # 启动视频流 vs VideoStream(src0).start() while True: frame vs.read() frame cv2.resize(frame, (800, 600)) gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 检测人脸 rects detector(gray, 0) for rect in rects: shape predictor(gray, rect) shape face_utils.shape_to_np(shape) # 提取眼睛和嘴部区域 left_eye shape[lStart:lEnd] right_eye shape[rStart:rEnd] mouth shape[mStart:mEnd] # 计算EAR和MAR ear (eye_aspect_ratio(left_eye) eye_aspect_ratio(right_eye)) / 2.0 mar mouth_aspect_ratio(mouth) # 绘制眼睛和嘴部轮廓 left_eye_hull cv2.convexHull(left_eye) right_eye_hull cv2.convexHull(right_eye) mouth_hull cv2.convexHull(mouth) cv2.drawContours(frame, [left_eye_hull], -1, (0, 255, 0), 1) cv2.drawContours(frame, [right_eye_hull], -1, (0, 255, 0), 1) cv2.drawContours(frame, [mouth_hull], -1, (0, 255, 0), 1) # 检查EAR是否低于阈值 if ear EYE_AR_THRESH: COUNTER 1 if COUNTER EYE_AR_CONSEC_FRAMES: cv2.putText(frame, DROWSINESS ALERT!, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) else: COUNTER 0 # 检查MAR是否高于阈值 if mar MOUTH_AR_THRESH: mCOUNTER 1 if mCOUNTER MOUTH_AR_CONSEC_FRAMES: cv2.putText(frame, YAWN ALERT!, (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) else: mCOUNTER 0 # 显示EAR和MAR值 cv2.putText(frame, EAR: {:.2f}.format(ear), (500, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.putText(frame, MAR: {:.2f}.format(mar), (500, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) # 显示画面 cv2.imshow(Frame, frame) key cv2.waitKey(1) 0xFF if key ord(q): break cv2.destroyAllWindows() vs.stop()5. 常见问题与解决方案5.1 光线条件影响检测精度问题现象在光线较暗或逆光环境下人脸检测和特征点定位不准确。解决方案使用红外摄像头替代普通摄像头添加自动曝光补偿算法# 自动调整图像亮度 def adjust_gamma(image, gamma1.0): invGamma 1.0 / gamma table np.array([((i / 255.0) ** invGamma) * 255 for i in np.arange(0, 256)]).astype(uint8) return cv2.LUT(image, table)5.2 侧脸检测效果差问题现象当驾驶员头部偏转角度较大时检测效果下降。解决方案使用多角度人脸检测模型添加头部姿态估计# 头部姿态估计 model_points np.array([ (0.0, 0.0, 0.0), # 鼻尖 (0.0, -330.0, -65.0), # 下巴 (-225.0, 170.0, -135.0), # 左眼左角 (225.0, 170.0, -135.0), # 右眼右角 (-150.0, -150.0, -125.0), # 嘴左角 (150.0, -150.0, -125.0) # 嘴右角 ]) # 解决PnP问题获取旋转向量和平移向量 _, rotation_vector, translation_vector cv2.solvePnP( model_points, image_points, camera_matrix, dist_coeffs)5.3 系统延迟问题问题现象实时检测时出现明显延迟。优化方案使用多线程处理from concurrent.futures import ThreadPoolExecutor def process_frame(frame): # 处理帧的函数 pass with ThreadPoolExecutor(max_workers4) as executor: while True: ret, frame cap.read() if not ret: break future executor.submit(process_frame, frame) # 获取处理结果 processed_frame future.result()使用C扩展提高关键算法性能6. 系统部署建议6.1 硬件选型对于车载环境推荐以下硬件配置处理器Intel Core i5及以上或Jetson Xavier NX内存8GB及以上摄像头支持1080p30fps带红外功能更佳存储256GB SSD6.2 报警机制设计除了屏幕显示警告外还应包含声音报警不同级别的疲劳状态对应不同报警音物理震动通过座椅震动提醒驾驶员云端上报将疲劳事件记录上传至管理平台# 声音报警示例 import winsound def play_alert(level): if level 1: # 轻度疲劳 winsound.Beep(1000, 200) elif level 2: # 严重疲劳 winsound.Beep(2000, 500)6.3 模型优化方向使用轻量级网络如MobileNetV3替代传统人脸检测模型量化模型减小计算量# 模型量化示例 converter tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) converter.optimizations [tf.lite.Optimize.DEFAULT] tflite_quant_model converter.convert()在实际部署中我发现夜间行车时红外摄像头的效果明显优于普通摄像头特别是在驾驶员佩戴眼镜的情况下。另外将EAR阈值根据个人特征进行微调±0.05范围内可以显著提高检测准确率。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门