MediaPipe 手势识别全解析:如何在移动端实现实时手部跟踪
1. 引言
手势识别是计算机视觉的重要应用之一,广泛用于 AR/VR 交互、智能家居控制、手势识别输入 等场景。Google 开源的 MediaPipe Hands 提供了一种高效的 手部关键点检测 方案,支持实时检测手掌,并识别 21 个手部关键点,适用于移动端和边缘设备。
本教程将深入解析 MediaPipe 手势识别 的原理,并介绍如何在 Android 和 iOS 设备 上实现实时 手部跟踪,最终构建一个能够在移动端运行的手势识别应用。
2. MediaPipe Hands 简介
MediaPipe Hands 是 Google 开源的一款 手势识别模型,基于 深度学习 + 传统计算机视觉 方法,能够:
- 检测单手/双手,并返回 21 个关键点坐标。
- 高效运行,支持 CPU 和 GPU 加速,适用于移动端设备。
- 跨平台,支持 Android / iOS / Web / Edge 设备。
2.1 关键点定义
MediaPipe Hands 识别的 21 个关键点如下(按索引编号):
关键点编号 | 部位名称 |
---|---|
0 | 手腕 |
1-4 | 拇指 |
5-8 | 食指 |
9-12 | 中指 |
13-16 | 无名指 |
17-20 | 小指 |
每个关键点包含以下信息:
- x, y:关键点在图像中的归一化坐标(范围 0-1)。
- z:深度信息(相对手腕,负值表示更靠近摄像头)。
3. MediaPipe 手势识别原理
MediaPipe Hands 采用 两个神经网络 进行手部识别:
- 手部检测模型(Palm Detector)
- 采用 BlazePalm 进行手掌检测。
- 返回手部边界框,为关键点检测提供初始输入。
- 手部关键点检测模型(Hand Landmark Model)
- 通过边界框裁剪手部区域。
- 运行深度学习模型提取 21 个手部关键点。
优化策略:
- 手部跟踪加速:如果上一帧已检测到手部,则下一帧不再运行手掌检测,仅更新关键点位置,提高帧率。
- 支持双手识别:可同时检测并识别双手。
4. 在 Android 设备上实现实时手势识别
本节介绍如何在 Android Studio 中使用 MediaPipe Hands + CameraX 进行实时手势识别。
4.1 环境准备
安装 Android Studio 并创建新项目
- 下载 Android Studio 并安装。
- 创建一个 Empty Activity 项目,选择 Kotlin 作为语言。
- 在
build.gradle
添加 MediaPipe 依赖:dependencies { implementation 'com.google.mediapipe:tasks-vision:latest_version' }
4.2 设置 CameraX 进行实时视频流
MediaPipe Hands 需要实时摄像头输入,因此我们使用 CameraX 捕捉视频流:
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// 选择后置摄像头
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
// 预览 View
val preview = Preview.Builder().build()
preview.setSurfaceProvider(previewView.surfaceProvider)
// 图像分析
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(executor, { image ->
processImage(image)
image.close()
})
// 绑定 CameraX
val camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis)
}, ContextCompat.getMainExecutor(this))
解释:
- CameraX 用于实时采集摄像头图像。
- 通过
imageAnalysis.setAnalyzer()
将图像流传递给 MediaPipe 处理。
4.3 运行 MediaPipe Hands 进行手势识别
import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarker
import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarkerResult
val handLandmarker = HandLandmarker.createFromFile(
context, "hand_landmarker.task"
)
fun processImage(image: ImageProxy) {
val result: HandLandmarkerResult = handLandmarker.detect(image.toBitmap())
for (hand in result.hands) {
for (point in hand.landmarks) {
Log.d("HandLandmarks", "x: ${point.x}, y: ${point.y}, z: ${point.z}")
}
}
}
代码解析:
HandLandmarker.createFromFile()
加载手势识别模型(.task
文件可从 MediaPipe 官方下载)。handLandmarker.detect(image)
运行手势识别,返回 21 个关键点坐标。- 通过
hand.landmarks
遍历关键点数据。
4.4 绘制手势关键点
使用 Canvas
在 SurfaceView
绘制检测到的手部关键点:
val canvas = surfaceView.holder.lockCanvas()
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
for (point in hand.landmarks) {
val x = point.x * canvas.width
val y = point.y * canvas.height
canvas.drawCircle(x, y, 10f, paint)
}
surfaceView.holder.unlockCanvasAndPost(canvas)
5. 在 iOS 设备上实现手势识别
(简要介绍 iOS 端开发)
- 安装 Xcode,创建
SwiftUI
项目。 - 在
Podfile
添加:pod 'GoogleMLKit/HandLandmarker'
- 使用
ML Kit
运行手势识别:let handLandmarker = HandLandmarker() let result = try? handLandmarker.process(image) print(result?.landmarks)
6. 进阶优化
6.1 提高性能
- 使用 GPU 加速:在 Android 上启用 GPU delegate 提高推理速度:
val options = HandLandmarkerOptions.builder() .setRunningMode(RunningMode.LIVE_STREAM) .setDelegate(Delegate.GPU) .build()
- 使用 C++ + JNI 加速计算:可用
Cython + JNI
结合 C++ 实现高效推理。
6.2 识别手势动作
- 结合 21 关键点坐标,定义不同手势:
- ✌️ 胜利手势:食指和中指展开,其余手指收拢。
- 👍 点赞手势:拇指伸展,其余手指弯曲。
- 训练 自定义手势分类模型,实现更多手势识别。
7. 总结
本教程介绍了 MediaPipe Hands 手势识别的原理,并展示了如何在 Android 和 iOS 端实现 实时手部跟踪。未来可以结合 AI 手势分类、AR 交互、手势控制 等技术,打造更智能的应用。🚀