Jetson 22 基于 MediaPipe 的手势识别
基于 MediaPipe 的手势识别
本章节介绍如何使用 MediaPipe + OpenCV 来实现手势识别。
什么是 MediaPipe?
MediaPipe 是 Google 开发的一种开源框架,用于构建基于机器学习的多媒体处理应用程序。它提供了一组工具和库,可以用于处理视频、音频和图像数据,并应用机器学习模型来实现各种功能,如姿态估计、手势识别、人脸检测等。MediaPipe 的设计目标是提供高效、灵活和易用的解决方案,使开发者能够快速构建出各种多媒体处理应用。
准备工作
由于产品开机默认会自动运行主程序,主程序会占用摄像头资源,这种情况下是不能使用本教程的,需要结束主程序或禁止主程序自动运行后再重新启动机器人。
这里需要注意的是,由于机器人主程序中使用了多线程且由 crontab 配置开机自动运行,所以常规的 sudo killall python 的方法通常是不起作用的,所以我们这里介绍禁用主程序自动运行的方法。
如果你已经禁用了机器人主程序的开机自动运行,则不需要执行下面的结束主程序章节。
结束主程序
1. 点击上方本页面选项卡旁边的 “+”号,会打开一个新的名为 Launcher 的选项卡。
2. 点击 Other 内的 Terminal,打开终端窗口。
3. 在终端窗口内输入 bash 后按回车。
4. 现在你可以使用 Bash Shell 来控制机器人了。
5. 输入命令: sudo killall -9 python
例程
以下代码块可以直接运行:
1. 选中下面的代码块
2. 按 Shift + Enter 运行代码块
3. 观看实时视频窗口
4. 按 STOP 关闭实时视频,释放摄像头资源
如果运行时不能看到摄像头实时画面
- 需要点击上方的 Kernel - Shut down all kernels
- 关闭本章节选项卡,再次打开
- 点击 STOP 释放摄像头资源后重新运行代码块
- 重启设备
注意事项
如果使用USB摄像头则需要取消注释 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 这一句。
本章节特性
当代码块正常运行时,你可以把自己手放在摄像头前面,实时视频画面中会标注出人手的关节,标注出的关节会随人手的变化而变化,同时也会输出各个关节的位置,方便进行手势控制方面的二次开发。
MediaPipe 的手势识别过程采用不同的名称来对应不同的关节,你可以通过调用对应的编号来获取该关节的位置信息。
MediaPipe Hand
- WRIST
- THUMB_CMC
- THUMB_MCP
- THUMB_IP
- THUMB_TIP
- INDEX_FINGER_MCP
- INDEX_FINGER_PIP
- INDEX_FINGER_DIP
- INDEX_FINGER_TIP
- MIDDLE_FINGER_MCP
- MIDDLE_FINGER_PIP
- MIDDLE_FINGER_DIP
- MIDDLE_FINGER_TIP
- RING_FINGER_MCP
- RING_FINGER_PIP
- RING_FINGER_DIP
- RING_FINGER_TIP
- PINKY_MCP
- PINKY_PIP
- PINKY_DIP
- PINKY_TIP
import cv2
import imutils, math
from picamera2 import Picamera2 # 用于访问 Raspberry Pi Camera 的库
from IPython.display import display, Image # 用于在 Jupyter Notebook 中显示图像
import ipywidgets as widgets # 用于创建交互式界面的小部件,如按钮
import threading # 用于创建新线程,以便异步执行任务
import mediapipe as mp # 导入 MediaPipe 库,用于手部关键点检测
# 创建一个“停止”按钮,用户可以通过点击它来停止视频流
# ================
stopButton = widgets.ToggleButton(
value=False,
description='Stop',
disabled=False,
button_style='danger', # 'success', 'info', 'warning', 'danger' or ''
tooltip='Description',
icon='square' # (FontAwesome names without the `fa-` prefix)
)
# 初始化 MediaPipe 绘图工具和手部关键点检测模型
mpDraw = mp.solutions.drawing_utils
mpHands = mp.solutions.hands
hands = mpHands.Hands(max_num_hands=1) # 初始化手部关键点检测模型,最多检测一只手
# 定义显示函数,用于处理视频帧并进行手部关键点检测
def view(button):
# 如果你使用的是CSI摄像头 需要取消注释 picam2 这些代码,并注释掉 camera 这些代码
# 因为新版本的 OpenCV 不再支持 CSI 摄像头(4.9.0.80),你需要使用 picamera2 来获取摄像头画面
# picam2 = Picamera2() # 创建 Picamera2 的实例
# 配置摄像头参数,设置视频的格式和大小
# picam2.configure(picam2.create_video_configuration(main={"format": 'XRGB8888', "size": (640, 480)}))
# picam2.start() # 启动摄像头
camera = cv2.VideoCapture(-1) # 创建摄像头实例
#设置分辨率
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
display_handle=display(None, display_id=True) # 创建显示句柄用于更新显示的图像
while True:
# frame = picam2.capture_array()
_, frame = camera.read() # 从摄像头捕获一帧图像
# frame = cv2.flip(frame, 1) # if your camera reverses your image
img = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
results = hands.process(img)
# 如果检测到手部关键
if results.multi_hand_landmarks:
for handLms in results.multi_hand_landmarks: # 遍历检测到的每只手
# 绘制手部关键点
for id, lm in enumerate(handLms.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h) # 计算关键点在图像中的位置
cv2.circle(img, (cx, cy), 5, (255, 0, 0), -1) # 在关键点位置绘制圆点
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
mpDraw.draw_landmarks(frame, handLms, mpHands.HAND_CONNECTIONS) # 绘制手部骨架连接线
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
target_pos = handLms.landmark[mpHands.HandLandmark.INDEX_FINGER_TIP]
_, frame = cv2.imencode('.jpeg', frame)
display_handle.update(Image(data=frame.tobytes()))
if stopButton.value==True:
# picam2.close() # 如果是,则关闭摄像头
cv2.release() # 如果是,则关闭摄像头
display_handle.update(None)
# 显示“停止”按钮并启动显示函数的线程
# ================
display(stopButton)
thread = threading.Thread(target=view, args=(stopButton,))
thread.start()