树莓派4B Python3.7 模拟捂眼检测

#继之前安装树莓派3.7python+mediapipe之后,实现了一种通过cvzone(封装了mediapipe)

1使用cvzone里的cvzone.FaceDetectionModule.FaceDetector找到人脸位置获取人脸边框坐标

2通过cvzone里的cvzone.HandTrackingModule.HandDetector找到人手关键点坐标位置

3通过人脸位置的x,y,w,h和手指关键坐标的一点,我使用了小拇指第二关节,一旦检测到小拇指进入了人脸检测区域就可以得到捂眼睛的状态,实测cvzone的人脸检测可以做到半张脸检测到人脸信息,同时两种检测同时进行在i7 笔记本电脑cpu上不会卡顿,移植在树莓派4B上可以通过480p流畅运行,720p略有卡顿,1080p严重卡顿延迟拖影,可能是树莓派本身的视频流处理的原因,我使用过树莓派的两种视频解码模式都效果不是很好,正在持续寻找解决方法。

4在输入参量中cover_mode = 1只检测捂左眼反之 = 2只检测捂右眼。代码可以直接运行

检测过程如下图一,手的关键点坐标如图二:

完整实例代码如下: 

# -*- coding: utf-8 -*-
import cv2
import time
import numpy as np
import cvzone.HandTrackingModule
import cvzone.FaceDetectionModule
face_detector = cvzone.FaceDetectionModule.FaceDetector(minDetectionCon=0.5)
hand_direction_detector = cvzone.HandTrackingModule.HandDetector(mode=False,  # 视频流图像
                                                                 maxHands=4,  # 最多检测两只手
                                                                 detectionCon=0.5,  # 最小检测置信度
                                                                 minTrackCon=0.7)  # 最小跟踪置信度


def is_coverings_eye(cap_hand_direction, cover_mode=1, test_time=5):
    print("捂眼检测")
    atime = time.time()
    while True:
        success, frame = cap_hand_direction.read()
        if success is not True:
            break
        # frame = cv2.flip(frame, flipCode=1)  # 这里是否反转 下面是否反转还得测试
        _, face_boxs = face_detector.findFaces(frame, draw=False)
        hands = hand_direction_detector.findHands(frame, draw=False, flipType=False)
        # 获取人脸边框范围 与人手比较
        if face_boxs:  # 如果检测到了人脸 在此判断条件下再去检测人手 三种情况 没手 一只手 两只手
            max_area = 0  # 初始化最大面积为0
            max_index = -1  # 初始化最大面积对应的遍历序号为-1
            for index, facebox in enumerate(face_boxs):  # 先全部遍历求出面积最大的人脸序号
                _, _, w, h = facebox["bbox"]
                area = w * h  # 计算人脸面积
                if area > max_area:
                    max_area = area
                    max_index = index
            face_x, face_y, face_w, face_h = face_boxs[max_index]['bbox']  # 求出人脸范围
            if hands:  # 如果有手存在 找到面积最大的左手和右手的序号
                left_hand_max_area = 0  # 初始化最大面积为0
                right_hand_max_area = 0  # 初始化最大面积为0
                left_hand_max_index = -1  # 初始化最大面积对应的遍历序号为-1
                right_hand_max_index = -1  # 初始化最大面积对应的遍历序号为-1
                left_region_status = 0  # 初始化左手是否在范围内
                right_region_status = 0  # 初始化右手是否在范围内
                for index, hand in enumerate(hands):
                    if hand["type"] == "Left" and cover_mode == 1:  # 左手
                        _, _, w_left, h_left = hand["bbox"]
                        left_hand_area = w_left * h_left  # 计算面积
                        if left_hand_area > left_hand_max_area:
                            left_hand_max_area = left_hand_area
                            left_hand_max_index = index
                    if hand["type"] == "Right" and cover_mode == 2:  # 右手
                        _, _, w_right, h_right = hand["bbox"]
                        right_hand_area = w_right * h_right  # 计算面积
                        if right_hand_area > right_hand_max_index:
                            right_hand_max_index = right_hand_area
                            right_hand_max_index = index
                # 这里已经知道人脸范围 同时若index不等于-1 的时候就是有这只手
                if left_hand_max_index != -1:  # 如果检测到了左手
                    left_hand_x, left_hand_y = hands[left_hand_max_index]["lmList"][20][:2]  # 用小拇指头代表左手
                    if face_x <= left_hand_x <= face_x + face_w and face_y <= left_hand_y <= face_y + face_h:
                        left_region_status = 1  # 左手在这个范围里
                    else:
                        pass
                if right_hand_max_index != -1:  # 如果检测到了左手
                    right_hand_x, right_hand_y = hands[right_hand_max_index]["lmList"][20][:2]  # 用小拇指头代表左手
                    if face_x <= right_hand_x <= face_x + face_w and face_y <= right_hand_y <= face_y + face_h:
                        right_region_status = 1  # 左手在这个范围里
                    else:
                        pass
                if left_region_status == 1:  # 左手在范围里 就需要检测右手指向
                    print("左手在范围内")
                    return 1
                if right_region_status == 1:
                    print("右手在范围内")
                    return 2
        if time.time() - atime > test_time:
            return 0
        cv2.imshow("test", frame)
        if cv2.waitKey(1) & 0xFF == 27:  # 每帧滞留20毫秒后消失,ESC键退出
            break


if __name__ == '__main__':
    print("开始载入视频")
    cap = cv2.VideoCapture(0)
    cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
    cap.set(3, 640)  # 设置摄像头宽度
    cap.set(4, 480)  # 设置摄像头高度
    print("载入视频完成")
    cover_eys_model = is_coverings_eye(cap, cover_mode=1, test_time=40)  # cover_mode = 1是检测捂左眼
    print(cover_eys_model)
    cover_eys_model = is_coverings_eye(cap, cover_mode=2, test_time=40)  # cover_mode = 1是检测捂右眼
    print(cover_eys_model)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值