MediaPipe Hands 与 “火影结印” 实战解析
组件库介绍
MediaPipe Hands 是 Google 开源的一个高保真手部追踪解决方案。它利用机器学习(ML)从单帧图像中推断出每只手的 21 个 3D 关键点(Landmarks)。不同于传统的物体检测,它不需要依赖昂贵的深度摄像头,仅凭普通的 RGB 摄像头就能在移动设备和 Web 浏览器上实现实时的手势捕捉。其底层的轻量级模型架构经过高度优化,能够以毫秒级的延迟输出手掌、手指关节的精确坐标,是目前 Web 端最主流的手势识别方案之一。
使用场景
MediaPipe Hands 的应用场景非常广泛,主要包括:
- AR/VR 交互:在增强现实或虚拟现实中,用手直接抓取、控制虚拟物体,提供沉浸式体验。
- 手语翻译:实时捕捉手语动作并翻译成文本或语音,辅助听障人士沟通。
- 非接触式控制:智能家居或车载系统的手势控制(如挥手切歌、捏合调节音量)。
- 创意互动游戏:如我们开发的“火影结印”或“体感钓鱼”,利用手势作为游戏的核心输入控制器。
- 教学与康复:用于钢琴教学的手指指法纠正,或手部康复训练的动作监测。
简单交互演示

模拟火影忍者结印教学
先看看效果
https://heresmy.app/playground/mediaPipe-hands/naruto-handsign/index.html

本项目利用 MediaPipe Hands 实现了一个趣味演示:识别用户是否完成了特定的“忍术结印”动作。
项目背景:结印与十二地支
在《火影忍者》设定中,施放忍术需要通过特定的手势组合来引导查克拉。这些手势原型源自中国的“十二地支”。本质上,这是一个静态手势序列匹配的问题。系统需要按顺序识别出用户是否做出了正确的手势。
常见的手势对照如下:
| 地支 | 英文名 | 对应动作描述 |
|---|---|---|
| 子 | Rat | 食指中指伸直,其余手指弯曲 |
| 丑 | Ox | 手指交叉,类似握拳 |
| 寅 | Tiger | 双手食指中指竖起并在胸前交叉 |
| 卯 | Hare | 小指伸出,拇指并拢 |
| 辰 | Dragon | 复杂的指关节扣合 |
| 巳 | Snake | 双手合十,指尖向上 |
| 午 | Horse | 双手食指相抵,呈三角形 |
| 未 | Ram | 食指中指指尖向上 |
| 申 | Monkey | 手掌平放,手指弯曲 |
| 酉 | Bird | 指尖相对,形似鸟嘴 |
| 戌 | Dog | 右手握拳放在左手掌心 |
| 亥 | Boar | 双手并在下方,指尖向下 |
对照图

为什么需要数据预处理?
大家可能会尝试通过编写硬编码规则来识别手势,例如:“如果食指指尖的 Y 坐标小于关节 Y 坐标,且拇指打开角度大于 30 度,这就是【未】"。
这种基于规则(Rule-based)的方法有极大的局限性:
- 代码极其臃肿:每个人手大小、拍摄角度、距离镜头远近不同,需要写无数个
if-else来覆盖边界情况。 - 难以维护:一旦需要添加新动作,或者调整判定标准,整个逻辑很容易崩塌。
- 鲁棒性差:手稍微旋转一下,简单的坐标判断就会失效。
基于是一个入门级的程度,所以先不采用训练复杂的神经网络模型,而是采用一种叫做 “单样本学习 (One-Shot Learning)” 的思路。简单来说,就是把静态的照片变成数据,然后拿用户的实时数据跟这张照片的数据去“比距离”。
预处理的核心步骤如下:
- 数据清洗:筛选出清晰的 12 种手势图片。
- 特征提取:使用 Python 版的 MediaPipe 库处理图片,获取 21 个关键点坐标。
- 空间归一化 (关键步骤):
- 以腕部为中心:将所有点的坐标减去腕部 (Wrist) 的坐标,消除手在画面位置的影响。
- 尺度归一化:计算手掌最大距离,将所有坐标除以该距离,消除手掌大小(离镜头远近)的影响。
- 序列化:将归一化后的 21 个点 (x, y) 保存为 JSON 数组。
第一步:数据清洗
我这边使用的是在 kaggle 上面一位印度小哥的数据集,里面有十二个手部姿势,文件夹里面有很多视频帧图片,我们只需要每个姿势里面挑一张最清晰准确的。

印度小哥的数据集
https://www.kaggle.com/datasets/vikranthkanumuru/naruto-hand-sign-dataset/data
经过我的测试,使用动漫里面的手部动作是不能识别的,必须要用真人的。如果最后感觉不理想的话,可以通过拍摄自己的手部方式来调教效果。
第二步:安装环境
在我安装 python 环境的时候遇到很多坑,就是关于 mediapipe 依赖库的版本问题,所以必须严格按照我这边的版本来。
首先,python 使用 3.10.x 版本,以下我是通过 uv 工具进行环境的安装,如果你是通过 pip 也是类似的。
| |
第三步:生成 json 文件
我们准备好了素材,就是第一步中整理的 12 张图片,然后通过 python 脚本,将这些图片依次喂给 MediaPipe Hands。
我们还需要做数据标准化,这是很关键的步骤。MediaPipe 返回的坐标是绝对位置,直接对比没法用(因为用户手的大小、在屏幕的位置和你的照片不一样)。你需要对照片产生的坐标做归一化处理:
- 平移:将手腕点(索引 0)作为原点 (0,0,0)。即:所有点的坐标减去手腕点的坐标。
- 缩放:计算手掌的大小(例如手腕到中指指尖的距离),让所有点的坐标除以这个距离。这样无论手大如篮球还是小如硬币,数值范围都在 0~1 之间。
相关的代码、图片和 json 文件,可以通过关注公众号,回复【hand】获取
运行代码后,会输出如下的 JSON 格式内容:
| |
如果提供的图片无法识别,控制台会有输出相关的提示,到时候就替换那张图即可。
前端使用特征文件
在 Web 前端,我们加载这个 JSON 文件,并在每一帧进行实时的匹配计算。
核心逻辑代码解析 (script.js):
| |
通过这种方式,我们只需要维护一份 json 数据文件,代码逻辑非常通用且简洁。无论添加多少种新手势,核心算法都不需要修改。
实例解析:豪火球之术 (Fireball Jutsu)
为了更直观地理解,我们先整理并定义了“豪火球之术”的结印序列:
| |
其处理流程是一个典型的状态机 (State Machine):
- 初始状态:
currentStep = 0,系统期待用户结出第一个印 “巳 (Snake)”。 - 匹配检测:
- 每一帧,MediaPipe 返回当前手势的关键点。
- 系统将其与
snake的标准特征进行比对。 - 如果误差小于阈值(例如 0.3),且不在冷却期内,判定为匹配成功。
- 状态流转:
- 触发
nextStep()函数。 currentStep加 1,变为 1。- 系统提示用户结下一个印 “未 (Ram)”。
- 同时记录
lastSuccessTime防止瞬间重复触发(防抖)。
- 触发
- 循环与完成:
- 用户依次完成
monkey->boar->horse。 - 当最后一个印 “寅 (Tiger)” 匹配成功后,
currentStep等于序列长度。 - 触发
completeMove(),播放成功特效(如屏幕出现巨大的火球动画)。
- 用户依次完成
通过这种设计,我们将复杂的动态交互拆解为了一系列简单的静态匹配任务,既保证了识别的准确率,又大大降低了开发难度。
钓鱼游戏
作为钓鱼佬的最爱,那肯定是钓鱼了,于是也大概弄了一个 demo
https://heresmy.app/playground/mediaPipe-hands/fishing-game/index.html

