《手势遥控器》的核心就是一句话:把摄像头里的手,变成一个可靠的遥控器。这句话里最难的是"可靠"两个字。这篇记录我踩过的坑,给同样想玩 MediaPipe 的朋友铺路。
坑一:性能,不是识别准不准,而是省不省电
MediaPipe Hands 在中端机上的识别速度没问题,但持续开启摄像头是另一个命题。做遥控器意味着识别服务可能挂着几十分钟,功耗直接决定这个 App 是否可用。
我的做法:
- 降采样:给识别的帧直接降到 480P 级别。手部关键点不需要 1080P,分辨率降下来,CPU 和 NPU 的压力断崖式下降,识别精度几乎不受影响。
- 帧间隔:不必每帧都识别。控制好节拍,隔帧送入,手部动作的连续性靠插值补足,肉眼无感。
- 空闲降频:连续 N 秒没有检测到手,自动进入低频轮询模式,手一出现立刻恢复。刷视频的场景里,手不是一直举着的,这个优化对续航贡献巨大。
坑二:误触发——90% 的正确率等于不可用
演示的时候一切都好,实际用起来全是灾难,原因通常是误触发。你想切歌的时候它切了,你没想动的时候它也切了。
解决方案是一套组合拳:
- 手势确认窗口:一个手势必须连续命中若干帧才算数,瞬间闪过的手势直接丢弃。这个窗口太短会误触,太长会"跟手性差",我最终取在 200ms 上下。
- 动作冷却:同一个动作触发后有一段冷却时间,防止"抖动导致的连发"。切歌这种动作冷却 800ms,体感刚刚好。
- 关键点平滑:对 21 个关键点做指数滑动平均,滤掉手抖的高频噪声。平滑系数是玄学,调的时候要开着摄像头一帧帧看。
这三条单独看都很朴素,但调参的顺序很重要:先平滑、再窗口、最后冷却,反过来调你会怀疑人生。
坑三:前置摄像头镜像
一个让我笑了很久的 bug:测试"向右滑"手势的时候,识别方向总是反的。
原因很简单:前置摄像头默认是镜像的(自拍预览所见即所得),而 MediaPipe 输出的是画面坐标系里的关键点。你举着右手在画面左侧,镜像之后坐标就到了右边。滑动方向的判定必须先决定"用哪套坐标系",否则所有的方向类手势都是反的。一行 1 - x 解决,但定位到这一行花了一晚上。
坑四:低光环境是重灾区
晚上关灯躺着刷视频,恰恰是目标场景。但摄像头在低光下噪点爆炸,关键点开始漂移,识别率骤降。
- 曝光策略:识别用的是一个单独的 ImageAnalysis 用例,可以单独调曝光偏好,宁要"亮而糊"不要"暗而清"。
- 预期管理:我最后没有强行解决暗光识别,而是在 App 里坦诚提示"光线过暗可能影响识别"。识别这件事上,诚实的降级好过虚假的承诺。
坑五:机型差异
同一套参数,在 A 机器上丝般顺滑,在 B 机器上像喝了假酒。原因包括摄像头标定差异、SoC 算力差异、系统对后台服务的限制差异。我的策略是给默认值 + 允许用户调:识别灵敏度、动作冷却都在设置里开放,默认值取大多数机型体验的交集。
总结
MediaPipe 本身很好用,真正的工作量都在它外面:功耗、防抖、镜像、暗光、机型适配。如果说模型是"耳朵",那这些工程细节才是"听懂人话"的部分。
如果只让我留一条建议给要做手势交互的人:先花一周做"手势确认窗口 + 冷却"的框架,再去调模型参数。稳定性是设计出来的,不是调出来的。