手势敲木鱼先分清两种模型:MediaPipe 识别,LLM 编排

发布时间:2026/10/25 22:21:15
手势敲木鱼先分清两种模型:MediaPipe 识别,LLM 编排

给应用取名“多模态木鱼”很容易,证明每一步由谁完成更重要。摄像头画面变成手部坐标,需要一个具体的视觉模型、模型文件和运行时;语言模型能够帮助解释规则,并不自动意味着它能作为浏览器里的本地手部追踪器。

官方资料可以确认 Fable 系列的存在,却不能替代某个端侧手势 SDK 的安装与接口证据。这篇把识别交给有明确 Web 指南的 MediaPipe Hand Landmarker。LLM 是可选的规则草拟者,不放进每一帧的敲击热路径。

先统一坐标和触发条件

Hand Landmarker 的图像坐标和世界坐标不是一回事。图像 x、y 按画幅归一化,y 向下增大;世界坐标才使用米。下面取食指尖 y 减去指根 y,速度单位因此是“归一化坐标/秒”,不能写成 m/s。

我们也不尝试从两帧就猜到真实物理碰撞。这个原型定义了一块虚拟平面:先把手指抬高进入 ARMED,再向下跨过平面且速度达到阈值,才触发一次声音,随后冷却 200ms。0.5 的速度阈值和 -0.15 的抬起阈值是演示参数,需要以样本校准,不是手部生理常数。

以下检测器保存为 tap.mjs。它不调用摄像头、不加载模型,只接收已经取得的观测,因此可以先把时序逻辑单独跑通。

export class TapDetector { state = 'READY'; last = null; hand = null; until = -Infinity; push({t, tipY, mcpY, confidence, handId}) { if (![t,tipY,mcpY,confidence].every(Number.isFinite)) throw Error('finite observation required'); if (this.last && t <= this.last.t) return false; const y = tipY - mcpY; const previous = this.last; this.last = {t,y}; if (handId !== this.hand) { this.hand = handId; this.state = 'READY'; return false; } if (confidence < 0.7 || tipY < 0 || tipY > 1 || mcpY < 0 || mcpY > 1) { this.state = 'READY'; return false; } if (t < this.until) return false; if (this.state === 'COOLING') this.state = 'READY'; if (!previous || t-previous.t > 200) { this.state = y < -0.15 ? 'ARMED' : 'READY'; return false; } if (y < -0.15) this.state = 'ARMED'; const speed = (y-previous.y) / ((t-previous.t)/1000); const crossing = previous.y < 0 && y >= 0; if (this.state === 'ARMED' && crossing && speed > 0.5) { this.state = 'COOLING'; this.until = t+200; return true; } return false; } reset() { this.state='READY'; this.last=null; this.hand=null; this.until=-Infinity; } }

识别结果进入检测器之前,还缺什么

检测器的 confidence 是这个应用约定的观测质量输入;本例测试中的数值来自构造数据,不是 MediaPipe 对真实画面给出的分数。接入 SDK 时,应先确定可用的检测/追踪有效性判据;拿不到这个量就修改输入合同,不能伪造一个 1,也不能拿 handedness 的左右手分类分数代替关键点质量。多手场景还需要稳定 ID,数组第一个元素不保证永远是同一只手。这里仅讨论单手原型,丢失和重获时必须 reset。

官方 Web 指南指出 detect 和 detectForVideo 是同步调用,会阻塞调用线程。摄像头持续运行时,可以把检测放进 Worker,并控制在途任务数;页面主线程负责消费结果和绘制。这里没有给出一个未经锁版验证的 SDK 初始化大礼包,也不预设模型已下载成功。落地前应记录 tasks-vision 的精确版本、模型文件哈希和设备环境。

图中的两处指尖是跨过虚拟平面前后的两个时刻,不是额外的手。状态图只解释规则,不是摄像头实拍或模型跟踪截图。

声音由敲击事件驱动短包络合成,播放入口仍须满足浏览器用户激活条件。视觉识别、事件判定、音频排程分别记录时间戳,才有机会知道“慢”发生在哪一段。仅凭检测器在 Node 中通过测试,不能宣称端到端低延迟。

LLM 可以参与,但不能改掉边界

如果希望用户说“把木鱼敲得更轻一点”,可让 LLM 草拟音量或灵敏度参数,然后由本地白名单限制取值。模型输出不能成为任意 JavaScript 执行入口,更不应该未经确认把摄像头帧发到云端。

本轮仅用人工构造的抬起、下击、重复帧、冷却、换手和低置信度序列检查状态机。未启用摄像头、未运行手部模型、未测设备误触率,也未证明“零网络上行”或“零隐私风险”。后者还需要检查模型下载、遥测和实际网络请求。

复现记录

本轮在 Node.js v26.3.0 中运行随文核心逻辑的构造样例,进程退出码为 0。测试输出:

PASS: raise/cross, duplicate timestamp, cooldown, re-arm, hand change, weak observation, reset

将上方 JavaScript 保存为 example.mjs,可用 node example.mjs 加载;浏览器、音频节点、摄像头及外部服务入口另需对应环境。构造样例不等于真实业务效果。

资料与时效

  • Hand landmarks detection guide for Web:首次发布日期未核实;更新 2026-08-17。
  • Introducing Claude Fable 5.1 and Claude Mythos 5.1:2026-09。
  • How Block orchestrates Claude Fable across thousands of pull requests:2026-10-08。

本稿对应原预排时段;实际发布前须人工复核来源更正、SDK/API 版本及可用性,不据此预言 10 月 24–31 日的新事件。