【Opencv+cvzone】实现眨眼计数

2022年1月10日,腊八,距离放假回家还有5天,距离下次周会还有2天

代码存在C:\Users\10133\PycharmProjects\Project_PictureProcessing

一、调研

  • cvzone

CVzone是一个计算机视觉包,可以让我们轻松运行像人脸检测、手部跟踪、姿势估计等,以及图像处理和其他 AI 功能。它的核心是使用 OpenCV 和 MediaPipe 库。

二、处理过程

  • 初始处理

import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector

cap = cv2.VideoCapture(0)
detector = FaceMeshDetector(maxFaces=1)

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()
    # 用cvzone中的detector对面部特定点进行定位
    img, faces = detector.findFaceMesh(img)

    # 视频太大的话 可以将视频resize成目标大小
    # img = cv2.resize(img, (640, 360))
    cv2.imshow('image', img)
    cv2.waitKey(1)

有一个小的知识点,有关于 cv2 中 waitkey 的使用:

waitkey 控制着 imshow 的持续时间,当 imshow 之后不跟 waitkey 时,相当于没有给 imshow 提供时间展示图像,所以只有一个空窗口一闪而过。添加了 waitkey 后,哪怕仅仅是 cv2.waitkey(1),我们也能截取到一帧的图像。所以 cv2.imshow 后边是必须要跟 cv2.waitkey 的。

detector.findFaceMesh(img) 可以实现对图像进行网格定位,可以达到的效果如下图(救命 着实很好笑)

我这次没有按照教程给的导入视频,而是打开电脑自带摄像头,这次明显比上次流畅很多,不知道为什么手势识别的时候,录像卡成照片

  •  对特定点进行检查

在前面先列出要检查的点

# 如果要检查这三个点 首先列一个list
idList = [22, 23, 24]

在后面加入绘制这些点的函数

if faces:# 这里可以理解为假设face里面有我们需要知道的内容
     face = faces[0]
     for id in idList:
         cv2.circle(img, face[id], 5, (255, 0, 255))

结果如下

同理,可以找到眼睛周围的所有点,将其标注出来,并继续计算上下眼睑的竖直距离,但是只使用这一方法的话,其实也不好,因为当人物相对于摄像头的距离改变时,计算的距离数值也会改变,当人物距离摄像头很远时,会自动被识别成眼睛闭合,所以要改善算法。

  •  计数结果

当ratiolength取10时,虽然结果曲线很平缓,但是可以看出依据峰值进行判断的效果很不好

 取3的时候就好很多

在plot中将技术图像反转之后,得到下图(峰值朝下)

 三、全部代码

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

cap = cv2.VideoCapture(0)
detector = FaceMeshDetector(maxFaces=1)
plotY = LivePlot(400, 300, [30, 50], invert=True)
# 如果要检查这三个点 首先列一个list
idList = [22, 23, 24, 26, 110, 157, 158, 160, 161, 130, 243]
# 建一个空的ratio列表
ratioList = []
# 为了实现计数 先预设参数
blinkCounter = 0
# 为了防止眨眼的帧数重复计算,对进行判别的帧数进行设置
counter = 0
# 设置颜色,可以当眨眼时,将颜色设置为绿色
color = (255, 0, 255)

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()
    # 用cvzone中的detector对面部特定点进行网格定位
    img, faces = detector.findFaceMesh(img, draw = False)

    if faces:# 这里可以理解为假设face里面有我们需要知道的内容
        face = faces[0]
        for id in idList:
            cv2.circle(img, face[id], 5, color, cv2.FILLED)

        # 第一个left表示左眼
        leftUp = face[159]
        leftDown = face[23]
        leftLeft = face[130]
        leftRight = face[243]


        # 计算距离
        lengthVer, _ = detector.findDistance(leftUp, leftDown)
        lengthHor, _ = detector.findDistance(leftLeft, leftRight)
        # 简单的连接两个点
        cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)
        cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)
        # 输出计算的值 比率*100 cancel int的话,会使后面的曲线更加平滑
        ratio = lengthVer/lengthHor * 100
        # 扩展ratio列表 以计算ratioAverage
        ratioList.append(ratio)
        if len(ratioList) > 3:
            ratioList.pop(0)
        ratioAvg = sum(ratioList)/len(ratioList)

        if ratioAvg < 38 and counter == 0:
            blinkCounter = blinkCounter+1
            color = (0, 200, 0)
            counter = 1
        if counter != 0:
            counter = counter+1
            if counter > 10:
                counter = 0
                color = (255, 0, 255)


        # 把文本和矩形放在一起
        cvzone.putTextRect(img, f'Blink Count: {blinkCounter}',(50, 100), colorR = color)



        # 画图计数
        imgPlot = plotY.update(ratioAvg, color)
        # cv2.imshow('imagePlot', imgPlot)
        img = cv2.resize(img, (400, 300))
        # 将视频和计数图像放在同一界面中
        imageStack = cvzone.stackImages([img, imgPlot], 2, 1)

    else:
        img = cv2.resize(img, (400, 300))
        imageStack = cvzone.stackImages([img, img], 2, 1)



    # 视频太大的话 可以将视频resize成目标大小
    # img = cv2.resize(img, (640, 360))
    cv2.imshow('imageStack', imageStack)
    cv2.waitKey(25)

其实最后实现的效果还可以,但是当人脸相对摄像头的距离发生改变时,判别眨眼与否的门限将会改变,以及我的眼睛也太小了吧,稍微离远一点居然能判别为一直眨眼的状态,哭了= =

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python的OpenCV库和MediaPipe工具包是可以一起使用的,以实现手势识别的功能。 首先,需要在Python中安装OpenCV库和MediaPipe工具包。可以使用pip命令来安装它们: ``` pip install opencv-python pip install mediapipe ``` 安装完成后,就可以开始使用了。 首先,导入必要的库: ```python import cv2 import mediapipe as mp ``` 接下来,创建一个MediaPipe的Hand对象和一个OpenCV的VideoCapture对象,用于读取摄像头输入: ```python mp_hands = mp.solutions.hands hands = mp_hands.Hands() cap = cv2.VideoCapture(0) ``` 然后,使用一个循环来读取摄像头输入并进行手势识别: ```python while True: ret, frame = cap.read() if not ret: break frame_RGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = hands.process(frame_RGB) if results.multi_handedness: for hand_landmarks in results.multi_hand_landmarks: # 在这里可以对hand_landmarks进行处理和识别手势的操作 cv2.imshow('Gesture Recognition', frame) if cv2.waitKey(1) == ord('q'): break ``` 在循环中,首先将读取到的帧转换为RGB格式,然后使用Hands对象的process方法对该帧进行手势识别。得到的结果存储在results变量中。 在对每个检测到的手部进行循环处理时,可以使用hand_landmarks来获取该手的关键点坐标。可以根据这些关键点的位置和运动轨迹来实现手势的识别和分析。 最后,通过cv2.imshow方法显示图像,并使用cv2.waitKey方法等待用户操作。当用户按下"q"键时,循环终止,程序退出。 通过以上步骤,就可以使用Python的OpenCV库和MediaPipe工具包实现手势识别的功能了。当然,实际的手势识别算法和操作需要根据具体需求进行进一步的开发和优化。 ### 回答2: Python OpenCV和MediaPipe结合使用可以实现手势识别。首先,我们需要安装必要的库和工具,包括Python、opencv-python、mediapipe和其他依赖项。 然后,我们可以使用MediaPipe提供的HandTracking模块来检测手部的关键点。它使用机器学习模型来识别手势,并返回手部关键点的坐标。我们可以通过OpenCV的视频捕捉模块读取摄像头的实时图像。 接下来,我们通过应用MediaPipe的HandTracking模块获取手部关键点的坐标,并使用OpenCV将这些坐标绘制到图像上,以便我们可以实时看到手部的位置和动作。 完成这些基本的设置后,我们可以定义特定的手势,例如拇指和食指的指尖接触,作为一个简单的示例。我们可以通过检查特定的关键点之间的距离和角度来识别这种手势。如果关键点之间的距离较小并且角度较小,则我们可以确定手势是拇指和食指的指尖接触。 我们可以使用类似的方法来识别其他手势,比如手掌的张开和闭合,拳头的形成等等。我们可以定义一系列规则和阈值来确定特定手势的识别。 最后,我们可以根据检测到的手势执行特定的操作。例如,当识别到拇指和食指的指尖接触时,我们可以触发相机的快门,实现手势拍照。 总之,Python的OpenCV和MediaPipe结合使用可以实现手势识别。我们可以利用MediaPipe的HandTracking模块检测手部关键点,并使用OpenCV实时绘制手势位置。通过定义特定手势的规则,我们可以识别各种手势并执行相应操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值