欢迎访问我的网站,希望内容对您有用,感兴趣的可以加入免费知识星球。

OpenCV检测眨眼

OpenCV 迷途小书童 3年前 (2020-12-02) 4678次浏览 2个评论

软硬件环境

  • windows 10 64bit
  • nvidia gtx 1066
  • opencv 4.4.0
  • dlib 19.21.0
  • imutils 0.5.3

视频看这里

此处是 youtube 的播放链接,需要科学上网。喜欢我的视频,请记得订阅我的频道,打开旁边的小铃铛,点赞并分享,感谢您的支持。

基本原理

首先使用开源库 dlib 的人脸检测器识别出图片中的人脸并得到68个脸部关键点,进而获取到左右眼的关键点信息,通过计算 EAR(Eye Aspect Ratio),从而判定是否眨眼。

人脸68关键点信息可以参考下图

opencv_blink

而眼部的关键点信息示意如下,对应的点是左眼37~42,右眼43~48

opencv_blink

EAR 的计算公式如下

opencv_blink

当眼睛是睁开的时候,它是一个常量,当眼睛闭上的时候,逼近于0

opencv_blink

因此,当 EAR 是一常量,然后快速逼近0,接着回升,就可以认为这是一次眨眼。

准备环境

由于安装 dlib 需要用到 cmake,所以第一步要先安装 cmake。下载 windows 版的 cmake,地址是:https://cmake.org/download/,傻瓜式安装后,将安装路径(默认是 C:\Program Files\CMake\bin)加入系统环境变量 PATH

opencv_blink

pip install dlib imutils scipy opencv-python

模型下载,百度盘链接:https://pan.baidu.com/s/17VKTiwe5VzVEkGTj2FdZUQ ,提取码:xit6

实例代码

import dlib
import cv2
from scipy.spatial import distance as dist
from imutils.video import VideoStream
from imutils import face_utils
import imutils
import time

def eye_aspect_ratio(eye):
    # 计算眼部垂直方向上的2组关键点的欧氏距离
    A = dist.euclidean(eye[1], eye[5])
    B = dist.euclidean(eye[2], eye[4])

    # 计算眼部水平方向上的1组关键点的欧氏距离
    C = dist.euclidean(eye[0], eye[3])

    # 计算EAR
    ear = (A + B) / (2.0 * C)

    return ear

# EAR置信度
EYE_AR_THRESH = 0.3

# 低于置信度的连续帧数
EYE_AR_CONSEC_FRAMES = 3

# 数据帧计数器
COUNTER = 0

# 眨眼的次数
TOTAL = 0

# 初始化dlib的人脸检测器,它基于HOG
detector = dlib.get_frontal_face_detector()

# 创建脸部关键点检测器
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# 得到左右眼的关键点索引,左眼是37~42,右眼是43~48
(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
(rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]

# 获取摄像头数据
vs = VideoStream(src=0).start()
fileStream = False
time.sleep(1.0)

while True:
    # 获取数据帧,调整大小并进行灰度化
    frame = vs.read()
    frame = imutils.resize(frame, width=450)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 得到脸的位置
    rects = detector(gray, 0)

    # 针对每一张脸进行处理
    for rect in rects:
        # 将脸部关键点信息转化成numpy的数组
        shape = predictor(gray, rect)
        shape = face_utils.shape_to_np(shape)

        # 分别计算左右眼的EAR
        leftEye = shape[lStart:lEnd]
        rightEye = shape[rStart:rEnd]
        leftEAR = eye_aspect_ratio(leftEye)
        rightEAR = eye_aspect_ratio(rightEye)

        # 取平均值
        ear = (leftEAR + rightEAR) / 2.0

        # 分别计算左右眼的凸包
        leftEyeHull = cv2.convexHull(leftEye)
        rightEyeHull = cv2.convexHull(rightEye)

        # 画眼部轮廓
        cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
        cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)

        if ear < EYE_AR_THRESH:
            COUNTER += 1
        else:
            if COUNTER >= EYE_AR_CONSEC_FRAMES:
                TOTAL += 1

            # 重置计数器
            COUNTER = 0

        # 显示眨眼的次数和EAR
        cv2.putText(frame, "Blinks: {}".format(TOTAL), (10, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
        cv2.putText(frame, "EAR: {:.2f}".format(ear), (300, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

    # 显示图像
    cv2.imshow("Frame", frame)

    key = cv2.waitKey(1) & 0xFF

    # 按q键,退出循环
    if key == ord("q"):
        break

# 资源清理
cv2.destroyAllWindows()
vs.stop()

最后执行这段代码

python demo.py

opencv_blink

OpenCV教程

https://xugaoxiang.com/category/ai/opencv/

喜欢 (1)

您必须 登录 才能发表评论!

(2)个小伙伴在吐槽
  1. 谢谢讲解很详细
    匿名2021-05-03 01:41