基于人脸表面特征的疲劳检测系统
项目背景
随着交通事业的发展,疲劳驾驶成为交通安全事故的重要原因之一。疲劳驾驶通常表现为注意力分散、反应迟钝等症状,其中最直观的表现包括频繁眨眼、打哈欠以及头部不自主的点头。本项目旨在通过检测驾驶员的面部特征来实时评估其疲劳程度,并在必要时发出警告信号,从而提高行车安全性。
系统原理
本系统主要通过分析驾驶员的脸部特征,尤其是眼睛的状态来评估其疲劳程度。具体来说,系统会监测驾驶员的眨眼频率、眼睛开合度以及打哈欠的动作。通过这些数据,系统能够实时计算出驾驶员的注意力集中程度,并据此判断是否存在疲劳驾驶的情况。
关键技术
- Dlib库:一个强大的图像处理库,用于人脸检测和关键点定位。
- Eye Aspect Ratio (EAR):一种用于量化眼睛开合状态的指标,用于评估眨眼频率。
- OpenCV:用于视频捕获和图像处理的核心库。
检测方法
疲劳检测主要依据以下几个方面的数据:
- 眼睛开合度:通过计算眼睛长宽比(EAR)来衡量。
- 眨眼频率:根据单位时间内眨眼次数来判断。
- 嘴巴张合程度:通过检测嘴部开合来判断是否打哈欠。
系统流程
- 初始化检测器:使用
dlib.get_frontal_face_detector()
获取人脸检测器,使用dlib.shape_predictor
加载预先训练好的68个面部特征点检测模型。 - 定义眼部区域:确定左右眼在面部标志中的索引。
- 视频流读取:打开摄像头,读取视频流。
- 图像预处理:对每一帧图像进行尺寸调整,并将其转换为灰度图。
- 人脸检测:在灰度图上使用人脸检测器来检测人脸位置。
- 特征点定位:在检测到的人脸区域内使用特征点检测器来定位面部特征点。
- 特征点转换:将检测到的特征点坐标转换为数组格式。
- 眼睛坐标提取:从面部特征点中提取左右眼的坐标。
- 计算EAR值:编写函数计算左右眼的EAR值,并取平均值作为最终的EAR。
- 眼睛轮廓绘制:使用OpenCV的
cv2.convexHull
和cv2.drawContours
绘制眼睛的轮廓。 - 人脸标记:使用矩形框标记检测到的人脸。
- 眨眼计数:根据EAR值的变化情况,累计眨眼次数。
- 特征点显示:在图像中标记出68个面部特征点。
- 显示眨眼次数:使用
cv2.putText
在屏幕上显示当前累计的眨眼次数。 - 疲劳判定:如果在短时间内累计眨眼次数超过一定阈值,则判定驾驶员可能处于疲劳状态。
- 疲劳提示:当系统判定驾驶员处于疲劳状态时,会在屏幕上显示警告信息。
实现细节
- EAR计算:
EAR = (|eye_left| + |eye_right|) / 2
,其中|eye_left|
和|eye_right|
分别为左右眼的EAR值。 - 阈值设定:根据实际情况调整EAR的阈值和连续帧数阈值。
- 疲劳判定:若连续3次检测到EAR值低于设定阈值,则计为一次眨眼;若总眨眼次数超过50次,则认为驾驶员处于睡眠状态。
应用场景
该系统可应用于各种需要长时间集中注意力的场合,如长途驾驶、监控室值班等。通过实时监控驾驶员的状态,有助于预防由疲劳引起的交通事故。
运行说明:
### 配置环境
python 3.6.8
opencv-python == 4.4.0.46
numpy == 1.19.4
pillow == 8.0.1
scikit-image==0.15.0
pandas==1.1.4
dlib == 19.7.0 (dlib无法使用pip安装,见dlib安装说明)
### 代码运行
tkinter_UI.py tkinter界面,直接运行即可
关键代码:
import os
import cv2
from functools import partial
from scipy.misc import imresize
from PIL import Image
data_set = "genki4k/files/"
output_dir = "genki4k/files_crip/"
harr_model_path = 'face_det/data/haarcascades'
frontal_model= os.path.join(harr_model_path, 'haarcascade_frontalface_default.xml')
profile_model = os.path.join(harr_model_path, 'haarcascade_profileface.xml')
# 正脸检测的模型
frontal_dector = partial(cv2.CascadeClassifier(frontal_model).detectMultiScale,
scaleFactor=1.1,
minNeighbors=5,
minSize=(100, 100))
# 侧脸检测的模型
profile_dector = partial(cv2.CascadeClassifier(profile_model).detectMultiScale,
scaleFactor=1.1,
minNeighbors=5,
minSize=(100, 100))
if not os.path.exists(output_dir):
os.makedirs(output_dir)
def extract_face(image, save_path):
image = cv2.imread(image)
faces = frontal_dector(image)
for (x, y, z, w) in faces:
cv2.rectangle(image, (x,y), (x+z, y+w), (0, 255, 0), 1)
save_img = image[y:y+w,x:x+z]
cv2.imwrite(save_path, save_img)
save_img = Image.open(save_path)
save_img = save_img.resize((64,64))
save_img = save_img.convert('L')
save_img.save(save_path)
imgs = os.listdir(data_set)
for img in imgs:
extract_face(data_set+img, output_dir+img)
依赖项:
decorator==4.4.2
dlib==19.7.0
imageio==2.16.0
imutils==0.5.4
networkx==2.5.1
numpy==1.19.4
opencv-python==4.4.0.46
pandas==1.1.4
Pillow==8.0.1
pygame==2.1.2
python-dateutil==2.8.2
pytz==2023.3
PyWavelets==1.1.1
scikit-image==0.15.0
scipy==1.5.4
six==1.16.0