メインコンテンツまでスキップ

MediaPipe ハンドジェスチャー認識モデルの reCamera への移植

はじめに

このプロジェクトでは、Google 公式の MediaPipe ハンドジェスチャー認識スイートreCamera 上に完全移植してリアルタイムでジェスチャー認識を行い、その映像と認識結果を UDP 経由で PC にストリーミングして可視化する方法を示します。

本システムは 8 種類のジェスチャーカテゴリ(None / Closed_Fist / Open_Palm / Pointing_Up / Thumb_Down / Thumb_Up / Victory / ILoveYou)を認識でき、さらに 21 個のハンドランドマーク利き手情報(左手/右手) も出力します。以下のような用途に適しています:

  • スマートホームのジェスチャー操作:あらかじめ定義したジェスチャーで照明、カーテン、家電スイッチを操作でき、音声やスマホアプリが不要です。
  • 産業用途の非接触インタラクション:手袋を着用している、あるいは両手がふさがっている作業者でも、簡単なジェスチャーで装置にコマンドを送信できます。
  • 教育・展示でのインタラクション:科学館や展示ホールなどで、来場者がジェスチャーによってマルチメディアコンテンツをトリガーし、没入型の体験を提供できます。
  • アクセシビリティ支援:聴覚障害や身体の可動性が制限されているユーザーに対し、ジェスチャーによるデバイス操作の入口を提供します。

ハードウェアの準備

このデモを実行するには、以下のハードウェアが必要です:

  • reCamera デバイス 1 台(すべての reCamera バリアントに対応)
  • PC 1 台(可視化用の Python 受信プログラムを実行します。reCamera と同一ローカルネットワーク上にある必要があります)

デプロイ要件に応じて、任意のバージョンの reCamera を選択できます:

  • reCamera 2002 シリーズ(Wi-Fi)
  • reCamera Gimbal
  • reCamera HQ PoE(Ethernet + 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)

精度検証

変換後、モデルは 3 者比較(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++ プログラムをコンパイルする

注記

このソリューションをビルドする前に、メインプロジェクトドキュメントに従って ReCamera-OS 環境(バージョン 0.2.1 以上)を設定し、SDK パスとクロスコンパイルツールチェーンを構成しておいてください。

クロスコンパイルツールチェーンの環境変数を設定します:

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

リポジトリ をクローンし、ソリューションディレクトリに入ってビルドします:

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 量子化版)が必要です。これらはすでに リポジトリ に用意されています。自分でモデルを変換する必要がある場合は、モデル変換ガイド を参照してください:

モデルファイル名説明
Palm Detectionhand_detector_cv181x_int8.cvimodelモデル 1: SSD パーム検出
Landmark Detectionhand_landmarks_detector_cv181x_int8.cvimodelモデル 2: 21 ランドマーク
Gesture Embeddinggesture_embedder_cv181x_int8.cvimodelモデル 3: 128 次元埋め込み
Gesture Classificationcanned_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 を設定する

警告

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 フレームごとに 1 回推論を実行3
skip_single手が 1 本の場合、毎フレーム推論を実行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
注記
  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

Note: 手のひらモデルは 192×192 の入力を必要としますが、これは VPSS の最小スケーリング解像度を下回っています。そのため、CH0 では 640×480(VPSS がサポート)を使用し、モデル内部でソフトウェアのレターボックス処理により 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...