こんにちは、皆さん。
Webカメラの前で手を上げたら、3Dアバターも同じように手を上げる。専用のモーションキャプチャ機材がなくても、ブラウザだけでそこまでできるのでしょうか。
さて、今日はMediaPipe Holisticで身体・顔・両手を推定し、VRM 1.0アバターへリアルタイムに反映できるか検証します。
先に結果を書くと、Apple M1 MaxのCPU/WASMで1280×720のカメラ映像を 実効17.3 fps で処理し、姿勢を検出した141フレームすべてでVRMのボーンを更新できました。身体の追従は確認できましたが、今回の短い計測だけでは、顔と両手を含む安定した同時キャプチャまでは確認できていません。
MediaPipe Holisticとは
MediaPipe Holisticは、Googleが2020年12月10日に発表した、1台のカメラから身体・顔・両手をまとめて推定するパイプラインです。landmarkとは、肩、肘、指先などの位置を表す点のことです。発表時は姿勢33点、顔468点、左右の手21点ずつの合計543点でした。今回のbundleは瞳の10点を含むFace Mesh V2を使うため、顔478点、全体では553点です。
今回使った13.7 MBのholistic_landmarker.taskを展開すると、7つのTensorFlow Liteモデルが入っています。役割を短くまとめると次のとおりです。
| モデル | 役割 |
|---|---|
| pose detector | 画像内から人物を見つける |
| pose landmarks detector | 身体の33点と3D座標を推定する |
| face detector | 顔の範囲を見つける |
| face landmarks detector | 瞳を含む顔の478点を推定する |
| face blendshapes | まばたきや口の開きなど52種類の係数を出す |
| hand ROI refinement | 手を詳しく見るための切り出し範囲を補正する |
| hand landmarks detector | 片手21点を推定し、左右の手に共用する |
Holisticは、まず身体の位置から顔と手のおおよその範囲を決め、元画像の高い解像度から各部分を切り出します。身体全体を縮小した画像だけで小さな指先まで読もうとしないための多段構成です。
今回固定したtask bundleは2023年12月21日更新のfloat16版です。構成モデルの資料は、身体のBlazePoseが2021年4月、Hand Trackingが2021年10月、Face Mesh V2が2022年9月、Blendshape V2が2022年11月の日付です。各モデルカード(BlazePose GHUM 3D、Hand Tracking、Face Mesh V2、Blendshape V2)はいずれもApache License 2.0としています。MediaPipe本体と@mediapipe/tasks-visionもApache License 2.0です。
labの付属モデルと測定には、VirtualCast, Inc.の公式サンプルSeed-sanを使いました。VRMファイル内の設定ではVRM Public License 1.0で、クレジット表記が必要です。再配布と改変物の再配布が許可され、アバター利用者はeveryone、商用利用設定はcorporationです。
実演動画では、別のVRMを読み込める機能を使い、VRoid StudioのサンプルモデルAvatarSample_Aを表示しています。公式のサンプルモデル利用条件では、無料で営利・非営利を問わず利用でき、クレジット表記は不要です。ただしCC0ではなく、著作権は放棄されていません。ライブラリの@pixiv/three-vrmとThree.jsはMIT Licenseです。
今回検証する内容
確認したいのは次の5点です。
- ブラウザ版Holistic Landmarkerがカメラ映像をリアルタイムに処理できるか
- 身体の33点をVRM 1.0のボーン回転へ変換できるか
- 左右各21点から手首と指を動かせるか
- 顔の係数をVRMの表情へ変換できるか
- 揺れを抑えても操作可能な応答に収まるか
完全なコードと測定記録は、kiarina/labsのmediapipe-holistic-vrm labで公開しています。
検証環境の再現
mise、WebGLとカメラ入力に対応したブラウザ、初回ダウンロード用のインターネット接続が必要です。Node.js 22.22.0はmiseが用意します。
git clone --depth 1 --filter=blob:none --sparse \
https://github.com/kiarina/labs.git
cd labs
git sparse-checkout set .gitignore .mise/tasks Makefile mise.toml \
2026/07/18/mediapipe-holistic-vrm
mise -C 2026/07/18/mediapipe-holistic-vrm run
mise -C 2026/07/18/mediapipe-holistic-vrm run preview
表示されたlocalhost URLを開き、カメラを開始を選びます。初回はMediaPipeモデルとSeed-sanを取得し、SHA-256を検証します。カメラ映像と推論はブラウザ内で処理し、外部サーバーへ送信しません。別のVRMファイルも、ファイル選択または画面へのドロップで読み込めます。
データの流れ
Webカメラ(1280×720)
-> Holistic Landmarker(身体・顔・両手を推定)
-> landmarkと52 face blendshape
-> 座標系をMediaPipeからThree.jsへ変換
-> 2点間の方向や身体・顔・手のひらの向きを計算
-> VRM 1.0の34ボーンと表情へ割り当て
-> 前フレームとの補間で揺れを抑える
-> Three.jsで描画
retargetingは、人の推定姿勢を別の骨格へ移す処理です。腕や脚では、肩から肘のような2点間の方向と、VRMの初期姿勢のボーン方向を一致させます。腰・肩・顔・手のひらは複数点から3軸を作り、身体のひねりや手の表裏も近似しました。
手指はMediaPipeの各関節をVRMの指ボーンへ対応させます。顔は、たとえばeyeBlinkLeftをblinkLeft、jawOpenをaaへ変換します。これは発音を認識しているのではなく、顔の形から表情係数を割り当てる簡易的な対応です。
推定値の細かな揺れは、そのままアバターへ渡すと震えに見えます。そこで通常のボーンは2度未満、手首と指は3度未満の変化を保持し、それを超える動きを時間に応じて滑らかに補間しました。脚の点が見えている確率が0.65未満なら誤推定を採用せず、姿勢全体を0.5秒以上見失った場合は中立姿勢へ戻します。
検証結果
MacBook Pro(Apple M1 Max、64 GB)、macOS 26.5.2、Codex in-app browserでローカルサーバーへ接続しました。推論はブラウザのWASM上で動き、CPUのXNNPACK delegateが使われています。
12秒の計測結果は次のとおりです。被写体が常に全身を画角内に保つようには統制していません。
| 指標 | 実測値 |
|---|---|
| 入力 | 1280×720 |
| 処理フレーム | 207 |
| 実効スループット | 17.3 fps |
| 推論時間 平均 | 49.17 ms |
| 推論時間 中央値 | 59.60 ms |
| 推論時間 p95 | 70.60 ms |
| 計測終了時の推論レート | 23 fps |
| 計測終了時の描画レート | 43 fps |
| 姿勢検出 | 141 / 207フレーム |
| VRMへ姿勢を反映 | 141 / 141検出フレーム |
| 右手検出 | 1 / 207フレーム |
| 左手検出 | 0 / 207フレーム |
| 顔検出 | 0 / 207フレーム |
カメラからHolistic推論、座標変換、VRM 1.0の読み込み、ボーン更新までの経路は成立しました。平均49.17 msはモデル呼び出しにかかった時間であり、カメラの露光や画面表示までを含む総遅延ではありません。
実演の様子はこちらです。動画内のアバターは、lab付属のSeed-sanではなく、VRoid StudioのAvatarSample_Aです。カメラ映像を隠しても推論を続けられるため、landmarkとアバターの追従を見やすくしています。
手と顔の0件をどう読むか
この0件は「モデルが手や顔を検出できなかった」という精度評価ではありません。全身を映す短い計測では、顔と手が小さくなり、継続的に検出できる画角ではありませんでした。別の短い試行では身体と顔が同時にactiveになるフレームを確認しています。
手指の全ボーンと表情の変換は実装し、合成データによるテストで指の回転とjawOpen -> aaを確認しました。ただし、実カメラで顔・両手・全身が同時にどの程度安定するかは、この結果からは判断できません。
処理速度の意味
17.3 fpsは、1秒に約17回姿勢を更新できたという意味です。動きの確認や対話デモには使えますが、60 fpsの滑らかなモーションキャプチャではありません。
ブラウザ版0.10.35のdetectForVideoは同期処理です。つまり、推論中は画面描画も同じmain threadで待たされます。p95の70.60 msがかかったフレームでは描画もその間止まるため、推論と描画を完全に独立させた構成ではありません。
結果を簡単に読む
専門的な内容を3点にまとめます。
-
普通のWebカメラから3Dアバターを動かせた
姿勢を検出した141フレームすべてでVRMの更新まで到達しました。専用センサーなしで、身体の動きをブラウザ上のアバターへ渡す基本経路は成立しています。
-
速度はデモに使えるが、滑らかなモーションキャプチャには足りない
実効17.3 fps、平均推論49.17 msでした。操作への反応は確認できますが、速い動きや配信用途では引っ掛かりが見える可能性があります。
-
顔と指を含む総合評価はまだできていない
今回の12秒計測は画角を固定した精度試験ではありません。身体の同期成功と、全身・顔・両手の安定同時同期は分けて考える必要があります。
制限
この実装は、2点間の方向を合わせる軽量な近似です。腕を軸にひねる動きには自由度が残るため、前腕、手首、足首の回転は正確ではありません。また、腰の位置移動、足を床へ固定する処理、床との接触を解くIKは入れていません。IKは、手足の目標位置から各関節の角度を逆算する方法です。そのため、足滑りや腰がその場に固定される動きが発生します。
評価も1台のM1 Max、12秒、207フレームに限られます。モデル自体の精度、照明や背景の違い、複数人、長時間の安定性、実際の画面までの総遅延は測定していません。
検証後の感想
MediaPipe Holisticは、身体・顔・手を別々に接続する手間を減らし、ブラウザだけでVRMまで届く土台として扱いやすいものでした。M1 MaxのCPU/WASMでも身体の追従を目で確認できる速度が出た点は、想像より実用的です。
一方で、553点が出せることと、1台の単眼カメラから全身・表情・指を同時に安定取得できることは同じではありません。今回成立した身体の同期を中心に使い、顔や手は画角と用途に応じて扱う構成なら、軽量なアバターデモやブラウザ内のジェスチャー操作にも使えそうです。