William Zhang2026-09-27

基于 MediaPipe Hand Landmarker 的双手捏合 9 滤镜演示

使用 MediaPipe Tasks 版 Hand Landmarker 模型在 CPU(XNNPACK 加速)上实时检测双手 21 个关键点与捏合状态,把「双手同时捏合」直接映射为「四边形 ROI 圈选」,对 ROI 内的像素实时应用 9 种图像滤镜

CVHand TrackingMediaPipeGithub

基于 reComputer-RK / Docker / RKNN / YOLO 的视觉滤镜展示

https://github.com/doublelf/filter_game


项目简介

本项目把 9 种滤镜集中到一份 FILTER_LIST 字典便于扩展——从而得到一个 191 行的纯滤镜工作室:gesture.py 检测双手捏合 → filter_game.FilterGame 维护四边形顶点 → filters.apply_filter 对 ROI 像素做图像处理。


快速开始

1. 获取并进入项目目录

bash
git clone https://github.com/doublelf/filter_game
cd filter_game

2. 安装依赖

bash
pip install -r requirements.txt

requirements.txt 固定四个依赖:

text
opencv-python>=4.8.0
mediapipe>=0.10.14
numpy>=1.26.0
Pillow>=10.4.0

9 种滤镜中的 EMBOSS / CONTOUR / POSTERIZE 由 Pillow 提供;INVERT / NEON / GRAY / SEPIA / HUE_SHIFT / PIXELATE 由 OpenCV + NumPy 实现,无需 Pillow 也可工作(届时自动返回原图,见 filters.py:36 _pil_filter_safe)。

3. 启动游戏

bash
python main.py                  # 默认摄像头 0,水平镜像开启
python main.py --cam 1          # 使用第 2 个摄像头
python main.py --no-flip        # 关闭水平镜像
python main.py --no-landmarks   # 关闭关键点叠加层(默认开启)
python main.py --hide-trails    # 关闭手势拖尾(默认开启)

启动后会先看到「Filter Studio」菜单画面,按任意键进入游戏。

4. 操作说明

操作玩家动作程序反馈
双手捏合任意一只手开始捏合食指指尖扩散环(金色)
双手同时捏合两手同时进入捏合两手锚点中点扩散环 + Toast CONNECTED
保持捏合 + 移动拖动双手(anchor_l, anchor_r, current_l, current_r) 四边形,对内部像素应用当前滤镜
任一手松开释放一只手四边形消失,回到 IDLE
横滑切滤镜任意未捏合手横扫画面SwipeIndicator 侧边渐变带 + Toast Filter N/9 NAME
键盘切滤镜1 – 9 直跳 / [ ] 或 , . 上下一个Toast Filter N/9 NAME
全程M 返回菜单摄像头持续采集,仅关掉游戏循环
全程ESC 退出释放摄像头、关闭 MediaPipe、销毁窗口

无摄像头环境运行

recomputer-rk3576-devkit 出厂默认没有 USB 摄像头插入;本项目附带三个工具保证在无摄像头下也能端到端跑通:

tools/verify_all.py —— 8 步验证套件

bash
cd /home/seeed/hand/filter_game
python3 -m tools.verify_all

逐项打印:

  • 模块导入(gesture / filter_game / filters / overlay / utils)
  • utils 几何 + 文本函数
  • 全部 9 种滤镜输出形状 / dtype 正确
  • FilterGame 状态机 + SwipeTracker 横滑检测
  • 真实 MediaPipe Hand Landmarker 在 aarch64 上加载模型(XNNPACK delegate,约 110 ms 预热)
  • HandOverlay.add_event + 渲染(both_connected / filter_switch / swipe)
  • 合成双手 pipeline 120 帧跑完,且 FilterGame 至少进入过 BOTH_PINCH 状态

tools/run_synthetic.py —— 离线渲染到 PNG

bash
python3 -m tools.run_synthetic --frames 200 --out /tmp/filter_demo
ls /tmp/filter_demo | wc -l      # → 200

驱动完整的 FilterGame + HandOverlay,打印:

Code
events total=N by_type={'both_connected': 1, ...}
BOTH_PINCH frames: 1   DRAG frames: 146

把每一帧写到 out/filter_XXXX.png。在无摄像头场景下用 ffmpeg 拼成 mp4:

bash
ffmpeg -framerate 30 -i /tmp/filter_demo/filter_%04d.png -c:v libx264 -pix_fmt yuv420p filter.mp4

tools/synthetic_source.py + tools/fake_tracker.py

合成视频源与合成 HandTracker,以接口完全等价于 cv2.VideoCapture / gesture.HandTracker 的形式存在;如果未来要接入真实摄像头,只需把这两行替换为:

python
cap = cv2.VideoCapture(args.cam)               # 替换 SyntheticHandSource
tracker = HandTracker(num_hands=2)              # 替换 SyntheticHandTracker

即可让 tools/run_synthetic.py 升级为真实摄像头驱动脚本。