OpenCV实战:人眼检测+眨眼计数

该文介绍了一个使用OpenCV库结合FaceMeshDetector模块来实时检测人眼并计算眨眼次数的项目。首先,通过468个人脸特征点检测人眼位置,然后连线计算眼睛开合比例,以此判断眨眼动作,最终实现眨眼计数功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

项目简介:使用OpenCV,实时检测人眼,并实现眨眼计数。

在之前的《OpenCV人脸特征点检测》中,我们了解到人脸由468个特征点构成,如下图所示:

由此可得人眼的坐标信息,然后根据坐标可以实时检测人眼。

二、实战

(1)安装环境

pip install opencv-python
pip install cvzone==1.5.6
pip install mediapipe==0.8.3.1

 (2)OpenCV加载视频

import cv2

cap = cv2.VideoCapture('Videos/2.mp4') #加载视频

while True:
    success, img = cap.read() #读取视频

    img = cv2.resize(img, (640, 360))  # 设置视频高、宽
    cv2.imshow('Image', img)
    cv2.waitKey(1)

 (3)捕捉人眼

  使用cvzone的FaceMeshDetector方法,可快速检测到人眼,代码如下:

import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector

cap = cv2.VideoCapture('Videos/2.mp4')  # 加载视频
detector = FaceMeshDetector(maxFaces=1)  # 创建检测器
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]  # 左眼坐标
color = (255, 0, 255)

while True:
    success, img = cap.read()  # 读取视频
    img, faces = detector.findFaceMesh(img, draw=False)
    if faces:
        face = faces[0]
        for id in idList:
            cv2.circle(img, face[id], 20, color, cv2.FILLED) #标定左眼

    img = cv2.resize(img, (640, 360))  # 设置视频高、宽
    cv2.imshow('Image', img)
    cv2.waitKey(1)

效果:

 (4)连线

 连接眼睛上下、左右四点,输出两点间的距离

import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector

cap = cv2.VideoCapture('Videos/2.mp4')  # 加载视频
detector = FaceMeshDetector(maxFaces=1)  # 创建检测器
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]  # 左眼坐标
color = (255, 0, 255)

while True:
    success, img = cap.read()  # 读取视频
    img, faces = detector.findFaceMesh(img, draw=False)
    if faces:
        face = faces[0]
        for id in idList:
            cv2.circle(img, face[id], 20, color, cv2.FILLED)

        # 眼睛四个点
        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]
        # 连接四个点
        cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)
        cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)

        # 两点距离
        lengthVer = int(detector.findDistance(leftUp, leftDown)[0])
        lengthHor = int(detector.findDistance(leftLeft, leftRight)[0])
        print("垂直方向:", lengthVer)
        print("水平方向:", lengthHor)

    img = cv2.resize(img, (640, 360))  # 设置视频高、宽
    cv2.imshow('Image', img)
    cv2.waitKey(1)

效果:

 (5)绘制图像

人在眨眼的时候,眼皮上下两点的距离是动态变化的,而水平方向两点长度不变,因此可以取垂直/水平的比例作为检测值,来判断是否眨眼了。

代码:

import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector
from cvzone.PlotModule import LivePlot

cap = cv2.VideoCapture('Videos/2.mp4')  # 加载视频
detector = FaceMeshDetector(maxFaces=1)  # 创建检测器
plotY = LivePlot(640, 360, [20, 50], invert=True)  # 绘图器
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]  # 左眼坐标
color = (255, 0, 255)
BlinkCounter = 0
ratioList = []
counter = 0

while True:
    success, img = cap.read()  # 读取视频
    img, faces = detector.findFaceMesh(img, draw=False)
    if faces:
        face = faces[0]
        for id in idList:
            cv2.circle(img, face[id], 20, color, cv2.FILLED)

        # 眼睛四个点
        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]
        # 连接四个点
        cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)
        cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)

        # 两点距离
        lengthVer = int(detector.findDistance(leftUp, leftDown)[0])
        lengthHor = int(detector.findDistance(leftLeft, leftRight)[0])
        # print("垂直方向:", lengthVer)
        # print("水平方向:", lengthHor)

        ratio = int((lengthVer / lengthHor) * 100)  # 垂直水平/水平方向的长度比
        print('比例:', ratio)
        ratioList.append(ratio)
        if len(ratioList) > 3:
            ratioList.pop(0)
        ratioAvg = sum(ratioList) / len(ratioList)  # 长度比均值
        print(ratioAvg)

        imgPlot = plotY.update(ratioAvg)  # 绘图更新
        img = cv2.resize(img, (640, 360))  # 设置视频高、宽
        imgStack = cvzone.stackImages([img, imgPlot], 2, 1)
    else:
        img = cv2.resize(img, (640, 360))  # 设置视频高、宽
        imgStack = cvzone.stackImages([img, img], 2, 1)

    cv2.imshow('Image', imgStack)
    cv2.waitKey(1)

效果:

 (6)眨眼计数

由(5)可知,可以通过比例变化来判断是否眨眼,代码如下:

import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector
from cvzone.PlotModule import LivePlot

cap = cv2.VideoCapture('Videos/2.mp4')  # 加载视频
detector = FaceMeshDetector(maxFaces=1)  # 创建检测器
plotY = LivePlot(640, 360, [20, 50], invert=True)  # 绘图器
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]  # 左眼坐标
color = (255, 0, 255)
BlinkCounter = 0
ratioList = []
counter = 0

while True:
    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # 重复播放视频
    success, img = cap.read()  # 读取视频
    img, faces = detector.findFaceMesh(img, draw=False)
    if faces:
        face = faces[0]
        for id in idList:
            cv2.circle(img, face[id], 20, color, cv2.FILLED)

        # 眼睛四个点
        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]
        # 连接四个点
        cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)
        cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)

        # 两点距离
        lengthVer = int(detector.findDistance(leftUp, leftDown)[0])
        lengthHor = int(detector.findDistance(leftLeft, leftRight)[0])
        # print("垂直方向:", lengthVer)
        # print("水平方向:", lengthHor)

        ratio = int((lengthVer / lengthHor) * 100)  # 垂直水平/水平方向的长度比
        print('比例:', ratio)
        ratioList.append(ratio)
        if len(ratioList) > 3:
            ratioList.pop(0)
        ratioAvg = sum(ratioList) / len(ratioList)  # 长度比均值
        print(ratioAvg)
        # 眨眼计数
        if ratioAvg < 35 and counter == 0:
            BlinkCounter += 1
            color = (0, 200, 0)
            counter = 1
        if counter != 0:
            counter += 1
            if counter > 10:
                counter = 0

        cvzone.putTextRect(img, f'Blink Count:{BlinkCounter}', (50, 200), 6, 5, colorR=color)  # 显示眨眼个数

        imgPlot = plotY.update(ratioAvg)  # 绘图更新
        img = cv2.resize(img, (640, 360))  # 设置视频高、宽
        imgStack = cvzone.stackImages([img, imgPlot], 2, 1)
    else:
        img = cv2.resize(img, (640, 360))  # 设置视频高、宽
        imgStack = cvzone.stackImages([img, img], 2, 1)

    cv2.imshow('Image', imgStack)
    cv2.waitKey(1)

效果:

OpenCV检测人眼、眨眼计数

三、最后

愿我们坚持学习下去,为了更美好的明天和更美好的自己。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值