目录

一、项目简介

二、算法原理

1. 人脸 68 关键点

2. EAR 眼部纵横比公式

三、环境依赖

四、完整可运行代码

五、代码核心讲解

1. EAR 计算函数

2. 中文绘制函数

3. 疲劳判定逻辑

六、常见报错解决

1. 找不到 simsun.ttc 字体

2. 找不到 shape_predictor_68_face_landmarks.dat

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 关键点模型文件

四、完整可运行代码

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. 摄像头打不开

检查设备摄像头权限、设备是否被其他软件占用。

七、效果展示

  1. 正常睁眼:实时显示 EAR 数值,眼部绿色轮廓绘制
  2. 长时间闭眼:屏幕红色中文预警 !!!危!!!

八、项目拓展

  1. 增加眨眼计数统计
  2. 增加打哈欠嘴巴检测
  3. 接入视频文件检测,不止实时摄像头
  4. 增加报警音效、弹窗提醒
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐