Google MediaPipe:提供手势识别器 (Gesture Recognizer) 任务 DEMO实现
以下是使用 Google MediaPipe Gesture Recognizer 在Python、Web (JavaScript) 和 Android三个平台上的完整 DEMO 实现。
🐍 Python 实现
这是一个使用本地摄像头进行实时手势识别的 Python 脚本。
1. 环境准备
首先,安装 MediaPipe 库:
pip install mediapipe2. 下载模型
从 MediaPipe 官方下载训练好的手势识别模型 (gesture_recognizer.task)。你可以从 MediaPipe 官方模型页面 获取。
3. 完整代码
import cv2 import mediapipe as mp from mediapipe.tasks import python from mediapipe.tasks.python import vision # 模型文件路径 MODEL_PATH = 'gesture_recognizer.task' # 创建手势识别器 def create_recognizer(): base_options = python.BaseOptions(model_asset_path=MODEL_PATH) options = vision.GestureRecognizerOptions( base_options=base_options, running_mode=vision.RunningMode.IMAGE, # 处理单帧图像 num_hands=1 # 最多检测1只手 ) return vision.GestureRecognizer.create_from_options(options) # 主函数 def main(): recognizer = create_recognizer() cap = cv2.VideoCapture(0) # 打开摄像头 if not cap.isOpened(): print("无法打开摄像头") return print("按 'q' 键退出") while True: success, frame = cap.read() if not success: break # 将 OpenCV 的 BGR 图像转换为 RGB rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 转换为 MediaPipe Image 对象 mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=rgb_frame) # 执行手势识别 recognition_result = recognizer.recognize(mp_image) # 在图像上绘制结果 if recognition_result.gestures: # 获取第一个手势结果 top_gesture = recognition_result.gestures[0][0] gesture_name = top_gesture.category_name score = top_gesture.score # 显示手势名称和置信度 cv2.putText(frame, f'{gesture_name} ({score:.2f})', (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 绘制手部关键点 if recognition_result.hand_landmarks: for landmark in recognition_result.hand_landmarks[0]: # 将归一化坐标转换为像素坐标 x = int(landmark.x * frame.shape[1]) y = int(landmark.y * frame.shape[0]) cv2.circle(frame, (x, y), 5, (0, 255, 0), -1) # 显示图像 cv2.imshow('Gesture Recognizer', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() if __name__ == "__main__": main()官方参考:完整的 Python 示例代码可在 Google Colab 上直接运行。
🌐 Web (JavaScript) 实现
这是一个在浏览器中通过摄像头进行实时手势识别的 HTML 文件。
1. 完整 HTML 代码
创建一个index.html文件,复制以下内容:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>MediaPipe 手势识别</title> <!-- 引入 MediaPipe 视觉任务库 --> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.mjs" crossorigin="anonymous"></script> <style> body { font-family: Arial, sans-serif; text-align: center; background: #1a1a2e; color: white; padding: 20px; } video, canvas { border-radius: 12px; margin: 10px 0; max-width: 100%; } #gesture-status { font-size: 24px; font-weight: bold; padding: 16px; background: #16213e; border-radius: 12px; margin: 10px auto; display: inline-block; } #gesture-status .gesture-name { color: #a78bfa; } #gesture-status .confidence { color: #94a3b8; font-size: 18px; } #loading { color: #94a3b8; font-size: 18px; } .container { max-width: 800px; margin: 0 auto; } </style> </head> <body> <div class="container"> <h1>✋ 手势识别演示</h1> <div id="loading">⏳ 加载模型中...</div> <div id="gesture-status"> 👋 手势: <span class="gesture-name" id="gesture-name">等待识别</span> <span class="confidence" id="confidence"></span> </div> <div style="position: relative; display: inline-block;"> <video id="webcam" autoplay playsinline style="display: none;"></video> <canvas id="output-canvas"></canvas> </div> </div> <script> // ============================================================ // 使用 MediaPipe Gesture Recognizer 进行实时手势识别 // 参考: https://developers.google.com/mediapipe/solutions/vision/gesture_recognizer // ============================================================ const video = document.getElementById('webcam'); const canvas = document.getElementById('output-canvas'); const ctx = canvas.getContext('2d'); const gestureNameEl = document.getElementById('gesture-name'); const confidenceEl = document.getElementById('confidence'); const loadingEl = document.getElementById('loading'); let gestureRecognizer = null; let runningMode = 'IMAGE'; // ----- 1. 初始化手势识别器 ----- async function initGestureRecognizer() { // 使用 FilesetResolver 加载 WASM 文件 const vision = await FilesetResolver.forVisionTasks( 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm' ); gestureRecognizer = await GestureRecognizer.createFromOptions( vision, { baseOptions: { // 使用官方推荐的模型文件 modelAssetPath: 'https://storage.googleapis.com/mediapipe-models/gesture_recognizer/gesture_recognizer/float16/1/gesture_recognizer.task' }, runningMode: runningMode, numHands: 1, minHandDetectionConfidence: 0.5, minHandPresenceConfidence: 0.5, minTrackingConfidence: 0.5 } ); loadingEl.style.display = 'none'; console.log('✅ 手势识别器已加载'); // 加载完成后启动摄像头 startCamera(); } // ----- 2. 启动摄像头 ----- async function startCamera() { try { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user', width: 640, height: 480 } }); video.srcObject = stream; await video.play(); // 设置 Canvas 尺寸 canvas.width = video.videoWidth; canvas.height = video.videoHeight; // 开始识别循环 predictLoop(); } catch (err) { console.error('❌ 无法访问摄像头:', err); loadingEl.textContent = '❌ 无法访问摄像头,请检查权限'; } } // ----- 3. 实时识别循环 ----- let lastTime = 0; async function predictLoop() { if (!gestureRecognizer || video.readyState < 2) { requestAnimationFrame(predictLoop); return; } // 每帧执行识别 const startTimeMs = performance.now(); const result = gestureRecognizer.recognizeForVideo(video, startTimeMs); // 绘制结果 drawResults(result); // 更新 UI updateUI(result); requestAnimationFrame(predictLoop); } // ----- 4. 绘制手部关键点 ----- function drawResults(result) { ctx.clearRect(0, 0, canvas.width, canvas.height); // 在 Canvas 上绘制视频帧(作为背景) ctx.drawImage(video, 0, 0, canvas.width, canvas.height); if (!result || !result.landmarks || result.landmarks.length === 0) { return; } // 绘制手部关键点和连线 const landmarks = result.landmarks[0]; const connections = [ [0,1], [1,2], [2,3], [3,4], // 拇指 [0,5], [5,6], [6,7], [7,8], // 食指 [0,9], [9,10], [10,11], [11,12], // 中指 [0,13], [13,14], [14,15], [15,16], // 无名指 [0,17], [17,18], [18,19], [19,20] // 小指 ]; // 绘制连线 ctx.strokeStyle = '#a78bfa'; ctx.lineWidth = 2; for (const [i, j] of connections) { const p1 = landmarks[i]; const p2 = landmarks[j]; ctx.beginPath(); ctx.moveTo(p1.x * canvas.width, p1.y * canvas.height); ctx.lineTo(p2.x * canvas.width, p2.y * canvas.height); ctx.stroke(); } // 绘制关键点 for (const landmark of landmarks) { ctx.beginPath(); ctx.arc( landmark.x * canvas.width, landmark.y * canvas.height, 6, 0, 2 * Math.PI ); ctx.fillStyle = '#8b5cf6'; ctx.fill(); ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 1; ctx.stroke(); } } // ----- 5. 更新 UI 显示 ----- function updateUI(result) { if (result && result.gestures && result.gestures.length > 0) { const topGesture = result.gestures[0][0]; const name = topGesture.categoryName || '未知'; const score = (topGesture.score || 0) * 100; // 映射为更友好的名称 const displayName = { 'None': '👋 无手势', 'Closed_Fist': '✊ 拳头', 'Open_Palm': '🖐 张开手掌', 'Pointing_Up': '☝️ 食指指上', 'Thumb_Down': '👎 拇指朝下', 'Thumb_Up': '👍 拇指朝上', 'Victory': '✌️ 胜利手势', 'ILoveYou': '🤟 我爱你' }[name] || name; gestureNameEl.textContent = displayName; confidenceEl.textContent = `(${score.toFixed(1)}%)`; } else { gestureNameEl.textContent = '未检测到手势'; confidenceEl.textContent = ''; } } // ----- 6. 启动 ----- initGestureRecognizer(); </script> </body> </html>官方参考:完整的 Web 示例代码可在 StackBlitz 上直接运行。
📱 Android 实现
Android 平台的实现需要 Android Studio 环境。
1. 克隆官方示例代码
git clone https://github.com/google-ai-edge/mediapipe-samples cd mediapipe-samples2. 导入项目
使用 Android Studio 打开examples/gesture_recognizer/android目录。
3. 核心组件
官方示例包含以下关键文件:
| 文件 | 作用 |
|---|---|
GestureRecognizerHelper.kt | 初始化手势识别器,处理模型加载和代理选择 |
MainActivity.kt | 应用主入口,调用识别器和结果适配器 |
GestureRecognizerResultsAdapter.kt | 处理和格式化识别结果 |
4. Gradle 依赖
在build.gradle中添加以下依赖:
dependencies { implementation 'com.google.mediapipe:tasks-vision:latest.release' }📚 支持的手势类型
MediaPipe Gesture Recognizer 默认支持以下 8 种手势:
| 手势类别 | 说明 |
|---|---|
None | 无手势 |
Closed_Fist | ✊ 拳头 |
Open_Palm | 🖐 张开手掌 |
Pointing_Up | ☝️ 食指指向上方 |
Thumb_Down | 👎 拇指朝下 |
Thumb_Up | 👍 拇指朝上 |
Victory | ✌️ 胜利手势 |
ILoveYou | 🤟 我爱你 |
💎 关键配置参数
在初始化识别器时,可以调整以下参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
running_mode | 运行模式:IMAGE(单图)、VIDEO(视频帧)、LIVE_STREAM(实时流) | IMAGE |
num_hands | 最多检测的手部数量 | 1 |
min_hand_detection_confidence | 手部检测最低置信度 | 0.5 |
min_tracking_confidence | 手部追踪最低置信度 | 0.5 |
📖 更多资源
官方在线演示:MediaPipe Gesture Recognizer Web Demo
官方 Python Colab:Gesture Recognizer Python 示例
官方 GitHub:mediapipe-samples-
手势识别任务总览:Gesture Recognizer Overview
