Skip to main content

将 MediaPipe 手势识别模型移植到 reCamera

介绍

本项目演示如何将 Google 官方的 MediaPipe 手势识别套件 完整移植到 reCamera 上,实现实时手势识别,并通过 UDP 将视频和识别结果流式传输到 PC 进行可视化。

系统可以识别 8 种手势类别(None / Closed_Fist / Open_Palm / Pointing_Up / Thumb_Down / Thumb_Up / Victory / ILoveYou),同时输出 21 个手部关键点 以及 左右手(handedness) 信息,适用于以下应用场景:

  • 智能家居手势控制:通过预设手势控制灯光、窗帘和家电开关,无需语音或手机 App。
  • 工业无接触交互:戴手套或双手被占用的工人可以通过简单手势向设备发送指令。
  • 教育与展陈交互:在科技馆或展览馆中,参观者可通过手势触发多媒体内容,获得沉浸式体验。
  • 无障碍辅助:为听力障碍或行动不便用户提供基于手势的设备控制入口。

硬件准备

要运行本演示,需要以下硬件:

  • 一台 reCamera 设备(支持所有 reCamera 型号)
  • 一台 PC(用于运行 Python 接收端进行可视化;必须与 reCamera 处于同一局域网)

你可以根据部署需求选择 任意版本的 reCamera

  • reCamera 2002 系列(Wi-Fi)
  • reCamera Gimbal
  • reCamera HQ PoE(以太网 + PoE)

注意:
PoE 版本不支持 Wi-Fi,必须通过支持 PoE 的交换机接入同一局域网。

reCamera 2002 系列reCamera GimbalreCamera HQ PoE

工作原理

模型转换流程(TFLite → ONNX → cvimodel)

从官方 MediaPipe 仓库下载 TFLite 格式的模型,需要将其转换为 reCamera TPU 支持的 .cvimodel 格式:

MediaPipe TFLite (FLOAT16)
│ tf2onnx (--channel_format none, keep NHWC)

ONNX (FLOAT32, NHWC) ← numerical reference (cos=1.0 vs TFLite)
│ tpu-mlir model_transform + model_deploy
├─ BF16
└─ INT8 (per-channel + real-data calibration)

CVIMODEL (cv181x)

精度验证

转换完成后,通过三方对比(TFLite vs ONNX vs cvimodel)对模型进行验证:

模型输出BF16 cosINT8 cos
detectorscores1.00000.9896
detectorboxes0.99990.9748
landmarklm631.00000.9999
landmarkworld630.99970.8098
embedderembedding1.00000.9992
classifierprobs1.00000.9978

注意:INT8 量化后,world63(世界坐标关键点)的精度有一定损失(cos=0.81),但端到端的手势分类结果与 TFLite 保持一致(类别判断可靠)。如果你的应用对世界坐标精度高度敏感,建议使用该模型的 BF16 版本。

构建示例

要构建本示例,你需要:

  1. 在 PC 上交叉编译 C++ 程序
  2. 在 reCamera 上运行编译好的可执行文件
  3. 在 PC 上运行 Python 接收脚本

步骤 1:编译 C++ 程序

note

在构建本方案之前,请确保已按照主项目文档配置好 ReCamera-OS 环境(版本 0.2.1 或更高),包括 SDK 路径和交叉编译工具链。

设置交叉编译工具链环境变量:

export PATH='current compile chain path'/host-tools/gcc/riscv64-linux-musl-x86_64/bin:$PATH

克隆仓库,并进入对应的 solution 目录进行构建:

git clone https://github.com/RobotXTeam/sscma-example-sg200x.git
cd sscma-example-sg200x/solutions/sesg-project/hand_gesture
export SG200X_SDK_PATH='current clone path'/sg2002_recamera_emmc
rm -rf build && mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-std=c++17" ..
make -j$(nproc)

编译生成的可执行文件位于:build/hand_gesture

步骤 2:准备模型文件

本示例需要 4 个 .cvimodel 模型文件(INT8 量化版本),已在仓库中提供。如果你需要自行转换模型,请参考模型转换指南

模型文件名说明
手掌检测hand_detector_cv181x_int8.cvimodel模型 1:SSD 手掌检测
关键点检测hand_landmarks_detector_cv181x_int8.cvimodel模型 2:21 个关键点
手势特征嵌入gesture_embedder_cv181x_int8.cvimodel模型 3:128 维特征嵌入
手势分类canned_gesture_classifier_cv181x_int8.cvimodel模型 4:8 类手势分类

将编译好的可执行文件和模型文件上传到 reCamera 的 /home/recamera/ 目录:

scp hand_gesture hand_detector_cv181x_int8.cvimodel hand_landmarks_detector_cv181x_int8.cvimodel \
gesture_embedder_cv181x_int8.cvimodel canned_gesture_classifier_cv181x_int8.cvimodel \
recamera@<reCamera_IP>:/home/recamera/ # Make sure the PC and reCamera are on the same network segment, then replace <reCamera_IP> with the corresponding IP address

步骤 3:配置 reCamera

warning

在运行 C++ 程序之前,必须先停止默认的 Node-RED 服务,因为它们会占用相机资源。请通过 SSH 运行以下命令:

sudo /etc/init.d/S03node-red stop
sudo /etc/init.d/S91sscma-node stop
sudo /etc/init.d/S93sscma-supervisor stop

步骤 4:在 reCamera 上运行可执行文件

通过 SSH 登录 reCamera,授予执行权限并运行:

cd /home/recamera/
chmod +x hand_gesture

参数说明

参数说明默认值
palm_model手掌检测模型(必选)-
landmark_model关键点检测模型(必选)-
embedder_model手势特征嵌入模型(必选)-
classifier_model手势分类模型(必选)-
min_score手掌检测阈值0.5
udp_ipPC 的 IP 地址(启用 UDP 流式传输)-
udp_portUDP 端口号-
jpeg_wJPEG 流视频帧宽度320
jpeg_hJPEG 流视频帧高度240
jpeg_fpsJPEG 流视频帧率10
skip_multi多手(≥2)时,每 N 帧运行一次推理3
skip_single单手时,每帧运行一次推理1

示例命令

基础用法(无 UDP 流,仅本地推理)

sudo ./hand_gesture \
hand_detector_cv181x_int8.cvimodel \
hand_landmarks_detector_cv181x_int8.cvimodel \
gesture_embedder_cv181x_int8.cvimodel \
canned_gesture_classifier_cv181x_int8.cvimodel

完整用法(UDP 流式传输 + 自定义参数)

sudo ./hand_gesture \
hand_detector_cv181x_int8.cvimodel \
hand_landmarks_detector_cv181x_int8.cvimodel \
gesture_embedder_cv181x_int8.cvimodel \
canned_gesture_classifier_cv181x_int8.cvimodel \
0.5 \
192.168.XX.XX 5001 \
320 240 10 \
3 1
note
  1. 请将 192.168.XX.XX 替换为与你的 reCamera 处于同一网络的 PC 实际 IP 地址。只有同时提供 udp_ipudp_port 时才会启用 UDP 流式传输。
  2. 如果程序显示 “[Heartbeat] Before the first retrieveFrame(RGB888) call...” 后卡住,请重启 reCamera。

步骤 5:在 PC 上运行 Python 接收端

在 PC 上,确保已安装所需的 Python 库:

pip install opencv-python numpy

进入解决方案目录并运行接收端脚本:

cd sscma-example-sg200x/solutions/sesg-project/hand_gesture
python3 tools/udp_receiver.py 5001

PC 端会显示一个实时视频窗口,包括:

  • JPEG 视频流
  • 手掌检测框(蓝色矩形)
  • 21 个手部关键点(红点 + 连接骨架)
  • 手势分类标签(左上角显示手势名称和置信度)
  • 左右手信息

PC 端实时手势识别结果

预期输出

在 reCamera 终端上

程序运行后,会显示推理性能日志:


[Perf] FPS=5.88 (inference=2.94) | palm=120.7ms | landmark=169.1ms | gesture=0.6ms | total=290.4ms | avg_hands=1.00
[Gesture] Open_Palm (70%) [R] palm=(0.43,0.34,0.69,0.69) score=0.85
[LB-DIAG] #2 warpAffine sx=0.3000 sy=0.3000 tx=0.0 ty=24.0
[LB-DIAG] #2 canvas 192x192: nonzero=82944 min=0 max=255 mean=80.7
[DET-DIAG] setInput ret=0, run ret=0
[Gesture] Open_Palm (70%) [R] palm=(0.45,0.36,0.72,0.73) score=0.85
[Gesture] Open_Palm (70%) [R] palm=(0.45,0.36,0.72,0.73) score=0.85
[LB-DIAG] #2 warpAffine sx=0.3000 sy=0.3000 tx=0.0 ty=24.0
[LB-DIAG] #2 canvas 192x192: nonzero=82944 min=0 max=255 mean=82.0
[DET-DIAG] setInput ret=0, run ret=0
[Gesture] Open_Palm (60%) [R] palm=(0.45,0.41,0.72,0.77) score=0.88
[Gesture] Open_Palm (60%) [R] palm=(0.45,0.41,0.72,0.77) score=0.88
[LB-DIAG] #2 warpAffine sx=0.3000 sy=0.3000 tx=0.0 ty=24.0
[LB-DIAG] #2 canvas 192x192: nonzero=82944 min=0 max=255 mean=81.9
[DET-DIAG] setInput ret=0, run ret=0
[Gesture] Open_Palm (60%) [R] palm=(0.47,0.42,0.73,0.76) score=0.81
[Perf] FPS=5.93 (inference=2.97) | palm=120.6ms | landmark=177.2ms | gesture=0.6ms | total=298.4ms | avg_hands=1.00
[Gesture] Open_Palm (60%) [R] palm=(0.47,0.42,0.73,0.76) score=0.81
[LB-DIAG] #2 warpAffine sx=0.3000 sy=0.3000 tx=0.0 ty=24.0
[LB-DIAG] #2 canvas 192x192: nonzero=82944 min=0 max=255 mean=81.8

注意:手掌模型需要 192×192 的输入,这低于 VPSS 的最小缩放分辨率。因此,CH0 使用 640×480(VPSS 支持),模型在内部通过软件 letterbox 将其缩放到 192×192。

摄像头访问错误

如果你看到 "No camera" 或 "Camera device not found" 错误:

  • 确保 Node-RED 服务已停止(参见步骤 3)
  • 检查摄像头连接

UDP 连接失败

如果 PC 未接收到数据:

  • 确认 PC 和 reCamera 在同一网络中
  • 检查 PC 上的防火墙设置
  • 确保 UDP 端口未被阻塞
  • 使用 ping 测试设备之间的连通性

手势识别置信度异常

如果识别出的手势置信度明显不对:

  • 确认分类器模型之后的 C++ softmax 补丁 已正确实现
  • 检查是否错误地使用了包含 Softmax 的 ONNX 输出,而不是使用 cvimodel 输出(logits)

C++ 代码结构

hand_gesture/
├── main/
│ ├── main.cpp # Entry: get frame → mmap → inference → UDP push
│ ├── hand_detector.{h,cpp} # Model 1: palm detection (SSD post-processing + NMS)
│ ├── hand_landmarker.{h,cpp} # Model 2: 21 landmarks (ROI warpAffine)
│ ├── gesture_recognizer.{h,cpp}# Model 3+4: embedder + classifier (with softmax patch)
│ ├── gesture_math.{h,cpp} # letterbox / math utilities
│ ├── engine_utils.h # tensor packing helpers
│ └── hand_types.h # data structures + UDP POD protocol
├── tools/udp_receiver.py # Python host receiver
└── CMakeLists.txt

技术支持与产品讨论

感谢你选择我们的产品!我们将为你提供多种支持,确保你在使用我们产品的过程中尽可能顺利。我们提供多种沟通渠道,以满足不同的偏好和需求。

Loading Comments...