この記事は、 North Detail Advent Calendar 2019 の22日目の記事です
概要
やりたいこと
- ピアノ演奏中の手のモーションをスマホカメラで記録する
- Unityでアニメーションしてピアノ演奏する
技術的なこと
- google/mediapipeでハンドトラッキング用のiOSアプリをビルド
- iPhoneカメラで手のモーションを記録
- Blenderでアニメーション化 & ピアノオブジェクト作成
- Unityに取り込んで再生、指と鍵盤の当たり判定で音を鳴らす
成果物
※雑音が流れるのでご注意を
Unityでピアノを弾いてみたかった
— ヤマト (@yamatohkd) December 21, 2019
(雑音が流れますのでご注意を) pic.twitter.com/fVuHP9Xb0K
......はい(出落ち)
作業環境
・MacBook Pro (Retina, 15-inch, Mid 2014) : Mojave 10.14.6
・iPhoneXs : iOS 13.2.2
・Xcode : 11.3
・Blender : 2.79
・Unity : 2019.2.12
今回はiPhoneのカメラを利用しますが、AndroidやPCのカメラでも同じことができるはず
※後述しますが、PCカメラ利用の場合はLinuxでGPUが利用できる環境推奨
Google / MediaPipeでモーション記録用のアプリをビルド
MediaPipeってなぁに?
MediaPipe is a framework for building multimodal (eg. video, audio, any time series data) applied ML pipelines. With MediaPipe, a perception pipeline can be built as a graph of modular components, including, for instance, inference models (e.g., TensorFlow, TFLite) and media processing functions.
MediaPipeは、マルチモーダル(ビデオ、オーディオ、時系列データなど)を適用したMLパイプラインを構築するためのフレームワークです。 MediaPipeを使用すると、たとえばパイプラインモデル(TensorFlow、TFLiteなど)やメディア処理機能など、モジュラーコンポーネントのグラフとして認識パイプラインを構築できます。
......なるほど(?)
どうやら機械学習パイプライン(画像処理→モデル推論→描画 など)の構築や、
それをグラフとして視覚化できるフレームワークらしい
サンプルではTensorFlowやTensorFlow Liteなどを利用して、
顔認識や物体の識別、手のモーション取得(ハンドトラッキング)などができる
Linux/Win/Macで実行したり、iOS/Android用にアプリをビルドしたりできる
MediaPipeをインストール
0. PCで実行したい人向け
モバイルアプリのビルドではなく、PCで直接実行したい人はLinux環境(OS Xは含まない)推奨です
2019/12/11現在、MediaPipeではデスクトップ用サンプルはLinuxのみGPUサポートが対応しています
(Win/MacでもCPU実行モード
はあるのですが私の環境では即座にフリーズしました......)
また、VMやdocker上のLinux環境ではホストGPUが使えないため、
MacならデュアルブートでOSインストールなどが必要です
(これを知らずにVirtualBoxのUbuntu上で作業していて土日まるまる潰しました......超頑張ればできないこともないとかなんとか?)
1. 事前準備
インストールガイドページのInstalling on macOS
を参考に進めていきます
-
Homebrewをインストール
-
Xcodeと
Command Line Tools
をインストール -
Pythonバージョンの確認
私の環境ではPython 2.7ではビルドが通らなかったため、下記サイトを参考にPython 3.7.5
をインストールしました
参考:pyenvを使ってMacにPythonの環境を構築する -
"six"ライブラリをインストール
$ pip install --user future six
2. MediaPipeリポジトリをクローン
$ git clone https://github.com/google/mediapipe.git
$ cd mediapipe
3. Bazelをインストール
二通りの方法がありますが、今回はOption 1
の方法でやります
※2019/12/11現在、MacではBazel 1.1.0より上のバージョンは対応していないため注意
# Bazel 1.1.0より上のバージョンがインストールされている場合はアンインストール
$ brew uninstall bazel
# Install Bazel 1.1.0
$ brew install https://raw.githubusercontent.com/bazelbuild/homebrew-tap/f8a0fa981bcb1784a0d0823e14867b844e94fb3d/Formula/bazel.rb
$ brew link bazel
4. OpenCVとFFmpegをインストール
こちらも二通りあるのでOption 1
の方法でインストール
$ brew install opencv@3
5. Hello World desktop exampleを実行
$ export GLOG_logtostderr=1
$ bazel run --define MEDIAPIPE_DISABLE_GPU=1 \
mediapipe/examples/desktop/hello_world:hello_world
# しばし待ったのち以下が表示されたらOK
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
ここで私の環境ではPython2.7で以下のエラーが発生しました
同じ現象が起こった人は1. 事前準備を参考にPythonのバージョンを上げてみてください
ERROR: An error occurred during the fetch of repository 'local_config_git':
Traceback (most recent call last):
モバイルアプリのビルド
今回は両手のモーションを取得するモバイルアプリをビルドしたいので、以下のサンプルを利用します
Multi-Hand Tracking (GPU)
※PCで直接実行したい場合は以下を利用してください
Multi-Hand Tracking on Desktop
Androidの場合
Androidの方が簡単にビルドできます
トラッキングには2Dと3Dモードの二通りあるので、3Dモードでビルドします
$ bazel build -c opt --config=android_arm64 --define 3D=true mediapipe/examples/android/src/java/com/google/mediapipe/apps/multihandtrackinggpu
かなり時間がかかるので待ちましょう
下記ディレクトリにapkファイルができるので実機にインストールすれば完了です!
mediapipe/bazel-bin/mediapipe/examples/android/src/java/com/google/mediapipe/apps/multihandtrackinggpu/multihandtrackinggpu.apk
iOSの場合
iOSの場合はこちらの設定がもうひと手間必要です
始めの方にあるXcodeやBazelのインストールは既に完了しているので不要です
(しかもこちらの方法でBazelをインストールすると最新バージョンを取得して動かなくなるという罠。間違えてインストールしてしまった場合は前述の方法でv1.1.0に置き換えてください)
1. Provisioning Profileの用意
AppleDeveloperProgram加入者はデベロッパサイトでProvisioning Profileを作成してダウンロードしてください
そうでない方は以下のサイトなどを参考に作成してください
参考:[Xcode][iOS] 有料ライセンスなしでの実機インストール 全工程解説!
Bundle Identifierを固有のものにしないとエラーが起きるので注意
どこかの誰かが使っているIDだとFailed to create provisioning profile.
と怒られます
作成されたファイルは以下のpathにあります
~/Library/MobileDevice/Provisioning Profiles/
用意したファイルはprovisioning_profile.mobileprovision
にリネームして、
mediapipe/mediapipe/
に配置します
2. BUILDファイルの修正
mediapipe/mediapipe/examples/ios/multihandtrackinggpu/BUILD
45行目のbundle_idを、
Provisioning Profileで設定したBundle Identifier
に変更
bundle_id = "com.google.mediapipe.MultiHandTrackingGpu",
↓
bundle_id = "hoge.fuga.piyo",
3. アプリのビルド
3Dモードでビルドします
$ bazel build -c opt --config=ios_arm64 --define 3D=true mediapipe/examples/ios/multihandtrackinggpu:MultiHandTrackingGpuApp
長いのでしばらく待ちます
ビルドが完了すると下記ディレクトリにipaファイルができます
bazel-bin/mediapipe/examples/ios/multihandtrackinggpu/
4. 実機にインストール
XcodeのWindow > Devices and Simulators
から、
USB接続した実機デバイスを選択して、
画面下部の+ボタンからipaファイルをインストールすれば完了です!
手の動きをトラッキング
ビルドしたアプリを動かしてみる
おお!両手の動きがリアルタイムで反映されていますね
このときのiPhoneのプロセス状態を、USB接続したMacのコンソール
アプリで確認してみましょう
MultiHandTrackingGpuApp
というプロセス名で何やらログが表示されています
hand[0]
とhand[1]
の二つあり、それぞれ21個のLandmark
を持っています
先程のgifの片手のポイントの数が21なので、その座標のようですね
それぞれの手のログは約0.05秒毎に表示されているようです
ちなみに、ログ出力のコードは下記ファイルに記述されていました
・mediapipe/mediapipe/examples/ios/multihandtrackinggpu/ViewController.mm : L177あたり
フロントカメラではなく背面カメラを使用したい場合は、同ファイルの以下を変更してビルドし直すと可能です
// 100行目をYESからNOに
_renderer.mirrored = NO;
// 109行目を~Frontから~Backに
_cameraSource.cameraPosition = AVCaptureDevicePositionBack;
Unityで表示してみる
取得した座標をUnityの3D空間に浮かべてみます
なぁにこれぇ?
ログをよくみるとz座標だけ数値が異様に大きいですね
倍率を変更してみます
おっ!なんかそれっぽくなった!
向きと大きさを調整して線で繋いでみると・・・
完全に手だコレ! \\ ٩( 'ω' )و//
あとはピアノを演奏しているところを撮影して座標を取得するだけです
Blenderでアニメーション化
Blenderとは?
- 3Dモデル作成、アニメーション作成、レンダリングなどができる
- 高機能・高品質、だけど高難度
- オープンソースで無料で使える
最近 v2.8がリリースされ、UIや操作方法が変わり直感的に操作できるようになりました
参考サイトはv2.7xの方が多く、古いプロジェクトをインポートすると壊れてしまう場合もあるため今回はv2.79を使用します
「Blender アニメーション 作成」で検索すると、
手動でボーンを動かしてキーフレーム毎にポーズを設定する方法が主流のようです
参考:かんたんBlender講座 アニメーションの基本
この方法は単純なアニメーションだとよいのですが、
ミリ秒単位で複雑な動きをさせる場合は骨が折れます(ボーンだけに)
そのため今回はスクリプトで作成します
Pythonでスクリプト作成
BlenderではPythonスクリプトが実行できます
MediaPipeで取得した座標をCSVファイルにまとめて、スクリプトからアニメーション化します
1. 座標CSVファイルの作成
こんな感じでCSVファイルを作成しました
左から以下の値となってます
- 手(0=左手、1=右手)
- Landmark
- 開始からの秒数
- x座標
- y座標
- z座標
2. Landmarkオブジェクトの作成
以下のSphereオブジェクトを追加
これをLandmarkポイントとして動かします
- Left.000 ~ Left.020
- Right.000 ~ Right.020
3. スクリプトの作成
Pythonスクリプトはこんな感じ
投稿時間を過ぎてしまったので説明は省略...
(倍率とかfpsとか適当。。。)
コメント追記しました
import bpy
import os
leftLandmarks = []
rightLandmarks = []
fps = 24
scale = (0.015,0.015,0.015)
# Landmarkオブジェクトを割当
for i in range(21):
leftLandmarks.append(bpy.data.objects["Left.0" + str(i).zfill(2)])
leftLandmarks[i].scale = scale
for i in range(21):
rightLandmarks.append(bpy.data.objects["Right.0" + str(i).zfill(2)])
rightLandmarks[i].scale = scale
# csvのあるディレクトリ
dirpath = "/Path/to/csv"
filename = "animation.csv"
filepath = os.path.join(dirpath, filename)
# csvを一行ずつ処理
with open(filepath, mode='rt', encoding='utf-8') as f:
for line in f:
params = line.split(",")
# 左手 or 右手
landmarks = leftLandmarks if params[0] == "0" else rightLandmarks
# 座標を指定
landmarks[int(params[1])].location = (float(params[3]),float(params[4]),float(params[5])/512)
# 指定した座標、フレームにキーフレームを設定
landmarks[int(params[1])].keyframe_insert(data_path="location", frame=int(float(params[2])*fps))
4. スクリプトの実行
Editor Type「Text Editor」にスクリプトを貼り付けてRun Script!
5. Animationの再生
Editor Type「Timeline」から再生!
勝ったな(フラグ)
6. オブジェクトのエクスポート
File > Export > FBXなどでエクスポートすれば完了!
.blendファイルもUnityでそのまま読み込めます
Blenderでピアノ作成
白鍵と黒鍵をCubeで並べていきます
アニメーションと合わせるので、実物の鍵盤と同じサイズ比を意識します
Unityに取り込んで再生
まずは用意した素材を取り込みます
- アニメーションを適用した3Dモデル
- ピアノオブジェクト
ピアノの設定
1. 音源Assetのインポート
ここにきて大誤算
ピアノの単音のフリー音源ってあまり無いんですね。。。
自前の電子ピアノから音源を作成しました
コーラス音源であれば、以下のUnity Assetを無料で利用できます
(同じ販売者から「グランドピアノ音源」も出品されているのですが$50もする・・・)
2. 鍵盤の動きを設定
鍵盤は以下の条件で動かします
- 動きはy座標回転のみ(xyz位置とxz回転を制限)
- 指との衝突で回転
- 天井と床(鍵盤のみと衝突する)を作り、元の位置より上下しないようにする
鍵盤にはRigidbodyとBoxColliderで当たり判定を付与します
3. 打鍵すると音が鳴るよう設定
以下の条件で音が鳴るようにしました
- ハンドオブジェクトと当たり判定がある(OnCollisionStay関数)
- かつ鍵盤の角度が一定以下
アニメーションの設定
-
アニメーションコントローラの作成
-
3Dモデルに適用
サイズ比率の調整
手と鍵盤とのサイズ比を調整します
サイズ比や位置の調整用に別途アニメーションを作成しておくとよいかもしれません
今回調整用のアニメーションも作成していたのですが、
手がドリルしていて使えませんでした。。。
再生
雑音が流れました
まとめ
MediaPipe面白い技術ですね!
想像していたよりはきれいにアニメーションしてくれました
ちゃんと調整すればメロディーを奏でそうなムーブではある
簡単な曲 → 複雑な曲というシナリオだったのですが思い通りにいかず
本当は3Dモデルにアニメーションさせたかったのですが、
時間も技術も足りませんでした。。。
アプリのログからアニメーションを作成するという方法もスマートじゃないですね
Linuxで実行できたらもう少しやりようがあったかもしれません
MediaPipe開発者がUnityのサポートについて反応しているので今後に期待ですね
また先日、VRヘッドセットのOculus Questにハンドトラッキングが実装されました
Unity対応のSDKも今月中にリリースとのことなので、Oculus Questをお持ちの方は是非試してみてください
参考:「Oculus Quest」にハンドトラッキング機能実装。コントローラなしでメニューなどの操作が可能に
ちなみに演奏していた曲は「We Wish You a Merry Christmas」でした
よいクリスマスを✨