MediaPipe 是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架,可以直接调用其API完成目标检测、人脸检测以及关键点检测等。本篇文章介绍其手部21个关键点检测。
在这里插入图片描述
官方文档:https://google.github.io/mediapipe/solutions/hands.html


一. 关键函数解释


(1)mediapipe.solutions.hands.Hands(): 手部关键点检测方法


参数:


  • static_image_mode: 默认为 False,将输入图像视为视频流。它将尝试在第一个输入图像中检测手,并在成功检测后进一步定位手的坐标。在随后的图像中,一旦检测到所有 max_num_hands 手并定位了相应的手的坐标,它就会跟踪这些坐标,而不会调用另一个检测,直到它失去对任何一只手的跟踪。这减少了延迟,非常适合处理视频帧。如果设置为 True,则在每个输入图像上运行手部检测,用于处理一批静态的、可能不相关的图像。
  • max_num_hands: 最多检测几只手,默认为2
  • min_detection_confidence: 手部检测模型的最小置信值(0-1之间),超过阈值则检测成功。默认为 0.5
  • min_tracking_confidence: 坐标跟踪模型的最小置信值 (0-1之间),用于将手部坐标视为成功跟踪,不成功则在下一个输入图像上自动调用手部检测。将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果 static_image_mode 为真,则忽略这个参数,手部检测将在每个图像上运行,默认为 0.5

返回值:


  • MULTI_HAND_LANDMARKS: 被检测/跟踪的手的集合,其中每只手被表示为21个手部地标的列表,每个地标由x, y, z组成。x和y分别由图像的宽度和高度归一化为[0,1]。Z表示地标深度。
  • MULTI_HANDEDNESS: 被检测/追踪的手是左手还是右手的集合。每只手由label(标签)和score(分数)组成。 label 是 ‘Left’ 或 ‘Right’ 值的字符串。 score 是预测左右手的估计概率。

(2)mediapipe.solutions.drawing_utils.draw_landmarks(): 绘制手部关键点的连线


参数:


  • image: 需要画图的原始图片

  • landmark_list: 检测到的手部关键点坐标

  • connections: 连接线,需要把那些坐标连接起来

  • landmark_drawing_spec: 坐标的颜色,粗细

  • connection_drawing_spec: 连接线的粗细,颜色等


二. 手部关键点检测并显示伸出的手指数


import cv2
import mediapipe as mp
import cmath

gesture = [“none”,“one”,“two”,“three”,“four”,“five”,“six”,“seven”,“eight”,“nine”,“ten”]
flag = 0

mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands

hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=2,
min_detection_confidence=0.75,
min_tracking_confidence=0.75)

cap = cv2.VideoCapture(0)
while True:
flag = 0
ret,frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 因为摄像头是镜像的,所以将摄像头水平翻转
# 不是镜像的可以不翻转
frame= cv2.flip(frame,1)
results = hands.process(frame)
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

# if results.multi_handedness:
# for hand_label in results.multi_handedness:
# print(hand_label)

if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
#print(‘hand_landmarks:’, hand_landmarks)
#计算关键点的距离,用于判断手指是否伸直
p0_x = hand_landmarks.landmark[0].x
p0_y = hand_landmarks.landmark[0].y
p5_x = hand_landmarks.landmark[5].x
p5_y = hand_landmarks.landmark[5].y
distance_0_5 = pow(p0_x-p5_x,2)+pow(p0_y-p5_y,2)
base = distance_0_5 / 0.6

p4_x = hand_landmarks.landmark[4].x
p4_y = hand_landmarks.landmark[4].y
distance_5_4 = pow(p5_x-p4_x,2)+pow(p5_y-p4_y,2)

p8_x = hand_landmarks.landmark[8].x
p8_y = hand_landmarks.landmark[8].y
distance_0_8 = pow(p0_x-p8_x,2)+pow(p0_y-p8_y,2)

p12_x = hand_landmarks.landmark[12].x
p12_y = hand_landmarks.landmark[12].y
distance_0_12 = pow(p0_x-p12_x,2)+pow(p0_y-p12_y,2)

p16_x = hand_landmarks.landmark[16].x
p16_y = hand_landmarks.landmark[16].y
distance_0_16 = pow(p0_x-p16_x,2)+pow(p0_y-p16_y,2)

p20_x = hand_landmarks.landmark[20].x
p20_y = hand_landmarks.landmark[20].y
distance_0_20 = pow(p0_x-p20_x,2)+pow(p0_y-p20_y,2)


if distance_0_8 > base:
flag += 1
if distance_0_12 > base:
flag += 1
if distance_0_16 > base:
flag += 1
if distance_0_20 > base:
flag += 1
if distance_5_4 > base*0.3:
flag += 1
if flag>=10:
flag = 10
# 关键点可视化
mp_drawing.draw_landmarks(frame,
hand_landmarks,
mp_hands.HAND_CONNECTIONS)


cv2.putText(frame,gesture[flag],(50,50),0,1.3,(0,0,255),3)
cv2.imshow(‘MediaPipe Hands’, frame)
if cv2.waitKey(1) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()

在这里插入图片描述