目录
[1. 人脸 68 关键点](#1. 人脸 68 关键点)
[2. EAR 眼部纵横比公式](#2. EAR 眼部纵横比公式)
[1. EAR 计算函数](#1. EAR 计算函数)
[2. 中文绘制函数](#2. 中文绘制函数)
[3. 疲劳判定逻辑](#3. 疲劳判定逻辑)
[1. 找不到 simsun.ttc 字体](#1. 找不到 simsun.ttc 字体)
[2. 找不到 shape_predictor_68_face_landmarks.dat](#2. 找不到 shape_predictor_68_face_landmarks.dat)
[3. 摄像头打不开](#3. 摄像头打不开)
一、项目简介
本次使用 Dlib + OpenCV + 68 点人脸关键点 实现实时眼部疲劳检测 。 通过 EAR(Eye Aspect Ratio,眼睛纵横比) 判断眼睛开合状态,连续多帧闭眼则触发疲劳预警,可用于疲劳驾驶检测、工位离岗瞌睡检测、课堂状态监测等场景。
本方案无需训练深度学习模型,传统视觉算法实时性高、代码轻量化、电脑可直接跑。
二、算法原理
1. 人脸 68 关键点
Dlib 经典 68 个人脸关键点中:
- 右眼:36--41
- 左眼:42--47
2. EAR 眼部纵横比公式
通过眼睛上下眼睑关键点欧式距离计算眼睛开合程度:
- A、B:眼睛垂直方向距离
- C:眼睛水平宽度
- EAR = (A+B)/2C
核心规律
- 睁眼:EAR 数值较大
- 闭眼 / 眯眼:EAR 急剧下降 常规阈值:EAR < 0.3 判定为闭眼
三、环境依赖
pip install numpy opencv-python dlib pillow scikit-learn
额外准备: shape_predictor_68_face_landmarks.dat 关键点模型文件
四、完整可运行代码
python
import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image,ImageFont,ImageDraw
# 计算EAR眼睛纵横比
def eye_aspect_ratio(eye):
A=euclidean_distances(eye[1].reshape(1,2),eye[5].reshape(1,2))
B=euclidean_distances(eye[2].reshape(1,2),eye[4].reshape(1,2))
C = euclidean_distances(eye[0].reshape(1, 2), eye[3].reshape(1, 2))
ear=((A+B)/2.0)/C
return ear
# OpenCV绘制中文(解决乱码)
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=50):
if isinstance(img, np.ndarray):
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")
draw.text(position, text, textColor, font=fontStyle)
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
# 绘制眼部轮廓
def drawEye(frame, eye):
eyeHull=cv2.convexHull(eye)
cv2.drawContours(frame,[eyeHull],-1,(0,255,0),1)
# 初始化
COUNTER=0
detector=dlib.get_frontal_face_detector()
predictor=dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
cap=cv2.VideoCapture(0)
while True:
ret,frame=cap.read()
if not ret:
break
faces=detector(frame,0)
for face in faces:
shape=predictor(frame,face)
shape=np.array([[p.x,p.y]for p in shape.parts()])
# 截取左右眼关键点
rightEye=shape[36:42]
leftEye=shape[42:48]
# 计算EAR
rightEAR=eye_aspect_ratio(rightEye)
leftEAR=eye_aspect_ratio(leftEye)
ear=(leftEAR+rightEAR)/2.0
# 连续闭眼判定疲劳
if ear<0.3:
COUNTER+=1
if COUNTER>=50:
frame=cv2AddChineseText(frame,"!!!危!!!",(250,250),textColor=(255,0,0))
else:
COUNTER=0
# 绘制眼部轮廓
drawEye(frame, leftEye)
drawEye(frame, rightEye)
# 显示实时EAR数值
info="EAR:{:.2f}".format(ear[0][0])
frame=cv2AddChineseText(frame,info,(0,30))
cv2.imshow("Eye Fatigue Detect",frame)
if cv2.waitKey(1)==27:
break
cv2.destroyAllWindows()
cap.release()
五、代码核心讲解
1. EAR 计算函数
利用双眼 6 个特征点计算纵横比,精准反映眼睛开合状态,是整个疲劳检测的核心指标。
2. 中文绘制函数
原生 OpenCV 不支持中文,利用 PIL 进行图片转绘,完美解决中文乱码问题。
3. 疲劳判定逻辑
- EAR 阈值 0.3:低于阈值判定闭眼
- 连续 50 帧闭眼:触发疲劳警告 可根据帧率自行修改帧数阈值。
六、常见报错解决
1. 找不到 simsun.ttc 字体
报错:IOError: cannot open resource 解决:
- Windows 自带宋体,直接运行即可
- Linux/Mac 替换字体路径为系统已有字体
2. 找不到 shape_predictor_68_face_landmarks.dat
将模型文件放在代码同级目录即可。
3. 摄像头打不开
检查设备摄像头权限、设备是否被其他软件占用。
七、效果展示
- 正常睁眼:实时显示 EAR 数值,眼部绿色轮廓绘制
- 长时间闭眼:屏幕红色中文预警 !!!危!!!
八、项目拓展
- 增加眨眼计数统计
- 增加打哈欠嘴巴检测
- 接入视频文件检测,不止实时摄像头
- 增加报警音效、弹窗提醒