光羽隹衡头像
关注

计算机视觉——Opencv(疲劳检测)

一、核心原理:眼睛纵横比(EAR)

要实现眼部疲劳检测,首先要明确一个核心指标:眼睛纵横比(EAR),这是判断眼睛是否闭合的关键依据。

1. 人脸关键点与眼部区域定位

Dlib 提供的shape_predictor_68_face_landmarks.dat模型能够精准检测人脸 68 个关键点,其中眼部区域的关键点分布如下:

右眼:36~41 号关键点(共 6 个)

左眼:42~47 号关键点(共 6 个)

2. EAR 计算公式

眼睛纵横比的核心思想是:

眼睛睁开时,纵横比保持稳定;

眼睛闭合时,纵向距离会急剧缩小,横向距离基本不变,最终纵横比趋近于 0

具体计算逻辑(对应眼部 6 个关键点的分布):

#    1   2
# 0         3   <----眼睛的6个关键点
#    5   4
  1. 计算纵向两个距离:A(关键点 1 与 5 的欧氏距离)、B(关键点 2 与 4 的欧氏距离)

  2. 计算横向一个距离:C(关键点 0 与 3 的欧氏距离)

  3. 纵横比 EAR = (A + B) / (2 * C)(取纵向距离均值再除以横向距离,消除个体眼部尺寸差异)

当 EAR 值低于某个阈值(本文选用 0.3,可根据实际需要调整)时,判定为闭眼状态;若闭眼状态持续超过一定帧数(本文选用 50 帧,对应摄像头帧率约 1~2 秒),则判定为疲劳状态并触发警报。

二、代码实现

1. 导入所需库

import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances  # 计算欧氏距离
from PIL import Image, ImageDraw, ImageFont  # pip install pillow

2. 核心函数 1:计算眼睛纵横比(EAR)

def eye_aspect_ratio(eye):
    '''-------------计算眼睛纵横比(EAR)-------------
    #    1   2
    # 0         3   <----这是眼睛的6个关键点
    #    5   4
    '''
    # 计算纵向距离A(1与5)、B(2与4)
    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(0与3)
    C = euclidean_distances(eye[0].reshape(1, 2), eye[3].reshape(1, 2))
    # 计算纵横比
    ear = ((A + B) / 2.0) / C
    return ear

注意:

使用euclidean_distances计算欧氏距离,需将单个关键点坐标 reshape 为 (1,2) 格式,满足函数输入要求。

3.辅助函数 1:OpenCV 添加中文文本

def cv2AddChineseText(img, text, position, textColor=(255,0, 0), textSize=50):
    """向图片中添加中文(解决OpenCV不支持中文的问题)"""
    if (isinstance(img, np.ndarray)):  # 判断是否为OpenCV图片类型(np.ndarray)
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))  # BGR转RGB,转换为Pillow图像
    draw = ImageDraw.Draw(img)  # 创建Pillow绘图对象
    # 加载中文字体(simsun.ttc为宋体,需确保环境中有该字体文件)
    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)  # RGB转BGR,转换回OpenCV图像格式

4. 辅助函数 2:绘制眼部凸包轮廓

def drawEye(eye):  # 绘制眼眶凸包
    eyeHull = cv2.convexHull(eye)
    cv2.drawContours(frame, [eyeHull], -1, (0, 255, 0), 1)

凸包:能够包围所有眼部关键点的最小凸多边形,清晰勾勒出眼睛的轮廓。

绿色细线条((0,255,0) 为绿色,线宽 1)

5. 主程序:视频流捕获与疲劳检测

# 全局变量:闭眼持续次数统计
COUNTER = 0

# 1. 初始化Dlib检测器与关键点预测器
detector = dlib.get_frontal_face_detector()  # 人脸检测器
predictor = dlib.shape_predictor(r"shape_predictor_68_face_landmarks.dat")  # 关键点预测器(替换为你的模型路径)

# 2. 初始化摄像头(0为默认摄像头)
cap = cv2.VideoCapture(0)

# 3. 循环读取视频帧,进行实时检测
while True:
    ret, frame = cap.read()
    if not ret:  # 若无法读取帧,退出循环
        break
    
    # 4. 检测人脸
    faces = detector(frame, 0)
    
    # 5. 遍历每一张检测到的人脸
    for face in faces:
        # 6. 预测人脸关键点
        shape = predictor(frame, face)
        # 7. 将关键点转换为NumPy数组(坐标格式:(x,y))
        shape = np.array([[p.x, p.y] for p in shape.parts()])
        
        # 8. 提取左右眼关键点
        rightEye = shape[36:42]  # 右眼:36~41号关键点
        leftEye = shape[42:48]  # 左眼:42~47号关键点
        
        # 9. 计算左右眼EAR值
        rightEAR = eye_aspect_ratio(rightEye)
        leftEAR = eye_aspect_ratio(leftEye)
        # 10. 计算平均EAR值(消除单眼遮挡等影响)
        ear = (leftEAR + rightEAR) / 2.0
        
        # 11. 疲劳判断逻辑
        if ear < 0.3:  # 阈值0.3,判定为闭眼
            COUNTER += 1  # 累计闭眼帧数
            if COUNTER >= 50:  # 持续闭眼50帧,触发疲劳警报
                frame = cv2AddChineseText(frame, "!!!!!危险!!!!! ", (250, 250), textColor=(0,0,255))
        else:  # 眼睛睁开,重置闭眼计数器
            COUNTER = 0
        
        # 12. 绘制眼部凸包与EAR信息
        drawEye(leftEye)
        drawEye(rightEye)
        info = "EAR: {:.2f}".format(ear[0][0])
        frame = cv2AddChineseText(frame, info, (0, 30))
    
    # 13. 显示视频帧
    cv2.imshow("Frame", frame)
    
    # 14. 按键退出:Esc键(ASCII码27)
    key = cv2.waitKey(1)
    if key == 27:
        break

# 15. 释放资源
cv2.destroyAllWindows()
cap.release()

运行结果:

注意事项

  1. 模型路径:需正确配置shape_predictor_68_face_landmarks.dat的文件路径,否则无法加载关键点模型。

  2. 字体文件:运行环境需存在simsun.ttc宋体文件,否则无法显示中文。

  3. 环境光线:建议在光线充足的环境下运行,光线过暗会影响人脸检测与关键点提取的精度。

  4. 阈值调整:EAR 阈值(0.3)与闭眼帧数阈值(50)可根据个人眼部特征、摄像头帧率调整,优化检测效果。

  5. 遮挡问题:佩戴眼镜、头发遮挡眼部等情况,可能会导致关键点提取失败,影响检测精度。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2401_83998832/article/details/157652265

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--