#继之前安装树莓派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)