基于mediapipe的手势游戏控制
玩游戏,那不是有手就行!!!
mediapipe介绍
Mediapipe是Google在2019年开发并提出的一款开源的跨平台多媒体处理框架,用于构建基于机器学习的应用程序,特别是涉及到计算机视觉、音频处理、姿势估计等领域。Mediapipe实际上是一个集成的机器学习视觉算法的工具库(包含人脸检测、人脸关键点、手势识别、头像分割和姿态识别等各种模型),该库提供了一系列预训练模型和工具,可以帮助开发者快速构建和部署计算机视觉和音频处理应用。它提供了一套易于使用的API,可以用于实时姿势估计、手势识别、面部识别、目标跟踪等任务。
手势捕捉
项目地址: https://github.com/google/mediapipe
pip安装mediapipe、opencv:
pip install mediapipe
pip install opencv-python
在文件中引入依赖
python">import cv2
import mediapipe as mp
通过cv2打开摄像头获取影像,电脑默认的输入是0,如果有其他输入通过更改序号来切换输入设备。
python">cap = cv2.VideoCapture(0)
初始化手势捕捉需要用到的对象
mpHands = mp.solutions.hands
hands = mpHands.Hands()
# 用于将识别到的点坐标绘制到输入的图片上
mpDraw = mp.solutions.drawing_utils
写一个死循环,频繁监听摄像头输入并对手势进行绘制
while True:ret, img = cap.read()if ret:# cv2默认获取的图片是BGR的颜色通道,需要将其转换为RGBimgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 对图像进行识别result = hands.process(imgRGB)if result.multi_hand_landmarks:# 遍历出现的手,这边仅用一只手进行操控,所以这边应该只有一个for handLms in result.multi_hand_landmarks:# 将识别到的手势坐标点绘制到获取的图像上 mpHands.HAND_CONNECTIONS是将所有坐标点连接起来mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)# 将操作后的图像显示在屏幕上cv2.imshow('img', img)
最终的效果如下
返回的结果每个点都有固定的序号,我们将序号也固定在图像上,方便我们观察每个序号处于什么节点。
先获取原始图像的高和宽
python">imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
imgHeight = img.shape[0]
imgWidth = img.shape[1]
在绘制手部坐标后,对坐标点进行遍历,得到每个点的坐标。
for i, lm in enumerate(handLms.landmark):xPos = int(lm.x * imgWidth)yPos = int(lm.y * imgHeight)cv2.putText(img, str(i), (xPos - 25, yPos + 5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 2)
绘制出来如图所示:
可以看到他是从手根部开始计数,按照拇指、食指、中指…的顺序进行排列,这样我们可以知道如果我们想要获取到某个位置的坐标应该用那个序号进行获取。
手势控制
上面我们获取到了每个节点的坐标,实际上我们只需要以一个点为参照就可以知道手是在向什么方向移动,因为在手势不变的情况下每个点的相对位置是基本一致的,所以我们只需要分析某个点的坐标移动,就可以得出手部的移动趋势。
例如我们固定以拇指的顶部,也就是图中的4号节点作为参照点分析,记录上一次的X轴坐标, 然后每次移动跟上一次做比较如果大于上一次则向右移动了,小于上次则向左移动了。
分析完手的移动意图后我们就可以使用pynput模拟键盘输入了。这边仅提供一个思路,具体的轨迹分析移动距离是一个大工程,简单代码实际得出来的操控体验不佳。
pip install pynput
python">from pynput.keyboard import Controller
import time
# 模拟按下键盘的D键
keyboard = Controller()keyboard.press('d')time.sleep(0.2)keyboard.release('d')
避免频繁输入,控制一个移动阈值,当移动的距离小于阈值时不进行按键输入。
最终效果如下,实际体验烂得一匹,动画中手部视频延迟于游戏是因为每次按键输入都有延迟,然后才会把手部图像输出到屏幕上,所以看上去手还没动,车把手就动了,现实其实还是蛮跟手的,但是没有什么用,就是图一乐。
结语
扩展一下,当我们握拳时,手指顶部的坐标和手掌根部的坐标相对距离会缩短,那我们也可以根据这个特性使用握拳以及张开程度来控制油门。再扩展一下,可以训练一个检测姿态的模型,检测人在骑着某个东西的时候身体的倾斜,同时输入到游戏中,是不是更有代入感一些。想要实现这些并且有一个还不错的游戏体验,需要大量时间进行调试,时间成本以及知识库都是一个大考验。