https://github.com/homuler/MediaPipeUnityPlugin
UnityでMediapipeを使った画像認識を色々試していたので、躓いた所とか参考になりそうな所をピックアップ
(執筆時点でのバージョンは
v0.6.2
、Unityは2020の最新版)
AndroidとWindowsでクロスプラットフォームにしたい
Windows向けでビルドしてから、Android版(WSL2でのビルド)をしたら両方のプラットフォームで動くようになった。ただし、DLLローディングのエラーは出る(無視出来る)ので、必要に応じてエラーをなんとかする必要があるかもしれない。
ざっくりVRM動かしたい
OpenCV For Unityをアセットストアから買ってCVVTuberExampleをベースにMediapipeを突っ込む。https://assetstore.unity.com/packages/tools/integration/opencv-for-unity-21088
具体的には、MediapipeForUnityでは「カメラと顔の特徴点推論」をやってくれるので、CVVTuberExampleのProcess Order ListでウェブカメラとDlibの処理を削って、MatSourceGetter, FaceLandmarkGetterは新しくスクリプトを作ってアタッチする。(スクリプト内では白い画像と顔の特徴点を返す実装をしてあげる)
MediapipeのFaceLandmarkは468ポイントありますが、Dlibの68ポイントとのいい感じの変換は自分で書いてあげないといけないので、私は以下のように実装しました。
// 特徴点68ポイントとLandmarkListsの位置をマッピング
// 左右は向かっての位置
// @see https://github.com/ManuelTS/augmentedFaceMeshIndices
private static int[] dlib68Order = new int[] {
// face edge 17
139,
34,
137,
177,
215,
135,
170,
171,
175, // center
396,
395,
364,
435,
401,
366,
264,
368,
// 左眉毛
225, 224, 223, 222, 221,
// 右眉毛
441, 442, 443, 444, 445,
// 鼻筋
197, 195, 5, 4,
// 鼻
115, 237, 1, 457, 344,
// 左目 6pt
33, 160, 158, 133, 153, 144,
// 右目 6pt
362, 385, 387, 263, 373, 380,
// 口(外周)12pt
76, 74, 73, 11, 303, 304, 306, 321, 405, 17, 181, 91,
// 口(内周)8pt
62, 41, 12, 271, 292, 402, 14, 178
};
internal void PushAnnotation(WebCamScreenController screenController, FaceMeshValue faceMeshValue)
{
if (screenController == null)
{
this.screenController = screenController;
}
// Debug Logging
//Debug.Log("PushAnnotation");
List<NormalizedLandmarkList> landmarkLists = faceMeshValue.MultiFaceLandmarks;
var drawingCount = Mathf.Min(landmarkLists.Count, 1);
List<Vector2> newLandmarkPoints = new List<Vector2>();
//Debug.Log("drawingCount: " + drawingCount);
for (var i = 0; i < drawingCount; i++)
{
NormalizedLandmarkList list = landmarkLists[i];
if (isEmpty(list))
{
//Clear();
// 何故かここには落ちない
return;
}
//Debug.Log("CalculateSize: " + list.CalculateSize());
for (var j = 0; j < Mathf.Min(list.CalculateSize(), 68); j++)
{
var landmark = list.Landmark[dlib68Order[j]];
newLandmarkPoints.Add(new Vector2(landmark.X * imageWidth, landmark.Y * imageHeight));
}
}
// ここで顔が「カメラから消えた」時にCountが0になる。
//Debug.Log("total landmarkPoints: " + newLandmarkPoints.Count);
landmarkPoints = newLandmarkPoints;
}
MediapipeForUnityでは毎フレーム推論が終わるたびに PushAnnotation
メソッドを呼ぶので、上記のように実装して出来たList<Vector2>をGetFaceLanmarkPointsメソッドで返してあげれば良い。MediapipeとCVVTuberでアップデートのライフサイクル(?)が違うのでイケてねーと思いつつこういう実装してあげれば動く。やっぱりうまく動かなかったのでBlenderで3Dビューで頂点のIndexを確認した。
Blender2.8系以上の最新版をインストール(無ければ)→「編集→プリファレンス→インターフェイス→開発者youオプション」をチェック→468の頂点を持つARキット用のFBXをインポート→「ビューポートオーバーレイ→インデックス」にチェックで上図のようになる。
現状適当なポイント当ててしか動作確認していないので、ガッツリ使うのであれば動作確認を含めて利用する頂点のIndexはチューニングする必要がありそう。
DllNotFoundException: mediapipe_c
公式のREADME.mdに雑にヒントが書いてあるけれど、実際は「ライブラリのビルドを行う前にUnityエディタでプロジェクトを開くと必要だったmetaファイルが消されて依存関係がぶっこわれる」ような動きをしているので、もし見に覚えがあったらソースコードを落とし直して、Packagesフォルダをまるごと上書きしてあげればmetaファイルが復活する。DllNotFoundException: mediapipe_jni
Android向けにビルドした時にこうなる場合→Player Settingsを見直しましょう。ソースコードに含まれているデモアプリで動くが、自分のアプリに突っ込んだ時に何故かこのエラーが……という場合、Player SettingsをデモアプリのようにIL2CPPでビルドしてみたり、APIレベルをいじってみましょう(深堀りしていないけれどコード呼び出しの時にMonoだとバグる気がする。)
WebCam一発でフルトラの時代が来そう
某社が某社と協業してWebカメラによる高品質なフルトラ技術を作った、などのPRが出てきたので、アバターを使ったアプリがどんどんコモディティ化してきそうな予感。僕はOSSのバグトラする位しか貢献できないので、色々いじった結果をこういう記事にしてみた感じ。
エンジニアとして働く90年生まれ。Web系技術を追っかけたり、PCガジェットや自転車いじりが趣味。オーディオオタク。