MediaPipeのpre/post-processメモ

GoogleのMediaPipe良いですね。コア部分はTensorFlowLiteでできていて、Pre/Postプロセス部分をUnityで書き直すことで移植できました。まだ勉強中ですがメモ。

github.com

↓ こんな感じでUnity上で動作してます。

Face Tracking and Blaze Face

Blaze Pose

Hand Tracking

全体

MediaPipeのBlaze Face, Balze Pose, Hand Trackingは細かい違いはあれど、かなり似ていて。大きく分けて2つTensorFlow Liteのモデルが動いています。

  1. SSD Detection: オブジェクトの矩形エリアを推定します。
  2. Landmark Detection: オブジェクトの画像からランドマーク(骨格など)を推定します。

MediaPipeはWebで処理を見ることができます。以下はBlaze Faceの例です。Max/MSPのノードのような感じで全体を俯瞰できるので、まずここから概要を掴みました。

f:id:asus4:20200904221738p:plain
MediaPipe Web Capture
https://viz.mediapipe.dev/demo/face_detection

その他のモデルもこちらから見れます。

それぞれのTFLiteについて見ていきます。

1. SSD Detection

SSD(Single Shot Detetor)でオブジェクトの矩形エリアを返します。

Pre Process

とくに難しいことはなく、入力画像のサイズにトリムしてfloatの配列に変換するだけです。

がPC上のWebカメラでやるときは簡単ですが、スマートフォンではWebcamTextureは回転とフリップしてるんですよね…。とても面倒くさいです。私の場合は入力画像とWebカメラの回転の正規化を一度にするシェーダーを用意しました。

Post Process

とりあえず重なる部分も含めて多めに返して、CPU側でNon Max Suppressionというアルゴリズムを使って精度を上げています。Courseraの動画で概要を理解しました。最近他のライブラリにも追加されてるの見ました。

通常のSSDモデルは推定された矩形エリアを返すだけですが。これはキーポイントと呼ばれる特徴点も返します。これは次のプロセスで使います。

2. Landmark Detection

Pre Process

カメラ画像から対象のオブジェクト部分をトリムします。トリムするときに、キーポイントの情報をもとに回転を直します。これは頭良いなーと。回転を直してからLandmarkを検出するモデルに画像を入力することで精度が上がるとのこと。当初バグで、間違った回転をした画像をLandmark Detectionのモデルに入力したのですが、精度が全然違いました。

youtu.be

緑色が矩形エリアとキーポイント。赤が回転とクロップする範囲。右上のちっこい手が実際のLandmark Detectionへの入力画像です。手が横向きになっても入力画像は上向きなのがわかると思います。

Post Process

FaceMeshとHand Landmarkは出力されたランドマークをそのまま表示しています。BlazePoseはすこし値が暴れるのかRelative Velocity Filterというものを使っています。移動が少ないときは強めのローパスフィルタ。移動が多いときはフィルタを弱めるというもののようです。

返されるランドマークは、入力画像に対しての値です。それを、2段階の画像入力で使ったMatrix4x4の逆行列をかけて、Unityの座標に戻しています。この変換も結構ややこしかったです。

まとめ

MediaPipeの処理はかなり似ていて、一度作るとHandTracking, BlazePose, BlazeFaceも大体同じプログラムが適用できました。機械学習の勉強のために初めてTensorFlow LiteのUnity移植ですが、共通する処理が結構出てきて。自分のためになっている気がします。

参考

TensorFlow Lite界隈は日本人が多く活躍していますね。@PINTO03091さん、@terrykyさんのTwitter, GitHubをよく参考にさせていただいております。