Mediapipe 实现手势追踪

Mediapipe 实现手势追踪

环境:python3.8,pycharm2020
硬件:罗技c505e

Mediapipe hands

官网信息:https://google.github.io/mediapipe/solutions/hands.html
Mediapipe是谷歌开源的一个机器学习的库,里面有一些面部识别、手势识别的解决方案,且提供python、js等语言的封装。

MediaPipe Hands是一个高保真的手和手指跟踪解决方案。它使用机器学习(ML)从仅仅一帧中推断出21个3D手部关键信息。我们可以用它来实现提取手部的关键点坐标,关键点编号如下:

Mediapipe 实现手势追踪

简单的手势追踪示例:

根据官网的文档,我们可以很快得实现一个简单的手势追踪的示例:

import cv2
import mediapipe as mp
import time

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

mpHands = mp.solutions.hands
hands = mpHands.Hands()
mpDraw = mp.solutions.drawing_utils
# 帧率统计
pTime = 0
cTime = 0

while True:
    success, img = cap.read()
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#转换为rgb
    results = hands.process(imgRGB)

    print(results.multi_hand_landmarks)
    if results.multi_hand_landmarks:
        for handLms in results.multi_hand_landmarks:
            for id, lm in enumerate(handLms.landmark):
                print(id, lm)
                # 获取手指关节点
                h, w, c = img.shape
                cx, cy = int(lm.x*w), int(lm.y*h)
                cv2.putText(img, str(int(id)), (cx+10, cy+10), cv2.FONT_HERSHEY_PLAIN,
                            1, (0, 0, 255), 2)
            mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)

    # 统计屏幕帧率
    cTime = time.time()
    fps = 1 / (cTime - pTime)
    pTime = cTime
    cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3)

    cv2.imshow("image", img)
    if cv2.waitKey(2) & 0xFF == 27:
        break

cap.release()

实际效果如图所示:
Mediapipe 实现手势追踪

这里的帧数受限于摄像头的帧率。

部分api分析

Hands的初始化配置

我们在hands = mpHands.Hands()完成对Hands初始化配置,从下面的构造函数可以看见我们可以配置的初始化参数

def __init__(self,
            static_image_mode=False,
            max_num_hands=2,
            min_detection_confidence=0.5,
            min_tracking_confidence=0.5):
  • static_image_mode为静态图像模式,默认false,用于处理视频
  • max_num_hands为支持检测最多手的数量
  • 后面两个应该是检测和追踪的置信度阈值(概率论相关知识),当置信度小于改值时将对图像重新进行处理,该值越大结果将越准确。

手势信息的采集

results = hands.process(imgRGB)完成对图像的处理,需要注意的是这里的输入必须为RGB格式的。

如果检测到手,那么将返回一个列表,包含21个标志点的x、y、z的值

  • x、y范围为[0.1, 1], 乘以图像的宽度和高度我们就可以得到具体的像素点坐标。
  • z为深度,这个值越小,就代表该坐标点接近摄像头。

results.multi_hand_landmarks是检测到所有手的列表,对该列表进行访问我们可以得到每只手对应标志位的信息,具体示例如下,我们可以得到每个标志位的像素坐标:

if results.multi_hand_landmarks:
        for handLms in results.multi_hand_landmarks:
            for id, lm in enumerate(handLms.landmark):
                print(id, lm)
                # 获取手指关节点
                h, w, c = img.shape
                cx, cy = int(lm.x*w), int(lm.y*h)
                cv2.putText(img, str(int(id)), (cx+10, cy+10), cv2.FONT_HERSHEY_PLAIN,
                            1, (0, 0, 255), 2)

具体标志点提取

有了上面的介绍,我们就很容易得到具体标志点的坐标,例如获取4标志点的信息(也就是大拇指):
print(handLms.landmark[4])

相关连接

https://www.youtube.com/watch?v=9iEPzbG-xLE
https://google.github.io/mediapipe/solutions/hands.html

**后续会分享一些基于Mediapipe的应用,例如手势识别等

上一篇:P3078 [USACO13MAR]Poker Hands S


下一篇:jQuery Validation让验证变得如此容易(二)