Python
MMD
3d-pose-baseline

MMDモーショントレース自動化でのセンター推定


はじめに

この記事は【目次】MMDモーショントレース自動化への挑戦 の一環です。

導入方法や他の技術解説等は、上記目次から各記事を参照してください。

ほぼ自分用作業メモ。


Github

3d-pose-baseline-vmd

VMD-3d-pose-baseline-multi


課題

3d-pose-baseline-vmd で取得した3Dデータにはセンター移動データが含まれていない


アプローチ


  • Openposeでは関節位置の移動が取れている事から、Openposeのデータを流用すればセンター移動ができるのでは、と推定

  • 基準点があれば、移動量も計測できるのではないかと想定


解決策

力業です。スマートじゃない…

動画は、Babo様のSNOBBISMをお借りしております。利用許諾ありがとうございます!


事前準備


Openposeの関節位置情報取得

Openposeで解析された2Dの関節位置情報をVMD生成処理時に使用する。

ただし、Openposeそのもののデータは暴れたり飛んだりしているので、3d-pose-baseline-vmd で3Dに変換する直前の正規化2Dデータ(smoothed.txt)を準備する。


直立フレームの選定

できるだけ正面向きで直立しているフレームを決める。

具体的には、Openposeで首と両足付け根が二等辺三角形になっているフレーム。

直立図形.jpg

このフレームを、MMD上のセンターが(0,0,0)であると見なし、以下処理を行っていく。


X軸移動

処理対象フレームの首、左足付け根、右足付け根のX軸の平均値を求める。

首だけにしなかったのは、Y軸方向に傾いてた場合を考慮するため。

おおざっぱに言えば、へその位置を求めるようなもんです。

X軸移動2.jpg

# 首・左足・右足の中心部分をX軸移動

x_avg = ((smoothed_2d[n][0].x() + smoothed_2d[n][1].x() + smoothed_2d[n][2].x()) / 3) - smoothed_2d[upright_idx][0].x()
bone_frame_dic["センター"][n].position.setX(x_avg * upright_xy_scale)

カメラからの距離で移動量が変わるので、その辺は外部パラメータで今のところ吸収しています。


Y軸移動

処理対象フレームの左足付け根、右足付け根のY軸の平均値を求める。

片足だけにしなかったのは、Z軸方向に傾いてた場合を考慮するため。

# 左足と右足の位置の平均

leg_avg = abs((smoothed_2d[n][1].y() + smoothed_2d[n][2].y()) / 2)

# 足の上下差
leg_diff = upright_leg_avg - leg_avg

# Y軸移動
if is_groove:
# グルーブがある場合には、そっちに割り当てる
bone_frame_dic["グルーブ"][n].position.setY(leg_diff * upright_xy_scale)
else:
bone_frame_dic["センター"][n].position.setY(leg_diff * upright_xy_scale)

Y軸移動.jpg

これも外部パラメータで移動量調整できるようにしています。

準標準モデルをトレース対象として読み込んだ場合には、グルーブにY軸移動量を割り当てます。

#トレーサーとしての好みです


Z軸移動

※暫定処理です。今後調整の可能性大。

ざっくり言うと、首と両足付け根の二次元面積を、2Dと3Dの両方で算出して、その縮尺の割合で求めてます。


2D直立フレームの二次元面積

図は「直立フレームの選定」参照。

# 直立フレームの三角形面積

smoothed_upright_area = calc_triangle_area(smoothed_2d[upright_idx][0], smoothed_2d[upright_idx][1], smoothed_2d[upright_idx][2])


3D直立フレームの投影二次元面積

Z軸移動1.jpg

# 3Dでの首・左足・右足の投影三角形

pos_upright_area = calc_triangle_area(positions_multi[upright_idx][8], positions_multi[upright_idx][1], positions_multi[upright_idx][4])


2D処理フレームの二次元面積

Z軸移動2.jpg

# 2Dでの首・左足・右足の投影三角形

smoothed_now_area = calc_triangle_area(smoothed_2d[n][0], smoothed_2d[n][1], smoothed_2d[n][2])


3D処理フレームの投影二次元面積

Z軸移動3.jpg

# 3Dでの首・左足・右足の投影三角形

pos_now_area = calc_triangle_area(positions_multi[n][8], positions_multi[n][1], positions_multi[n][4])


2D面積の縮尺

カメラから見て、遠ざかるほど、縮尺は小さくなる

# 2Dでの現在の縮尺

smoothed_scale = smoothed_now_area / smoothed_upright_area


3D面積の縮尺

傾きが大きいほど、縮尺は小さくなる

# 3Dでの現在の縮尺

pos_scale = pos_now_area / pos_upright_area


Z軸の算出

3D面積の縮尺 * (1 - 2D面積の縮尺) で、傾きを考慮したZ軸距離を算出する

1. 1 - 2D面積の縮尺 は、MMDセンター基準のZ軸位置。

 → マイナス値であれば近づき、プラス値であれば遠ざかる

2.3D面積の縮尺で、傾き分の補正を行う

 → 傾きが大きい(3D縮尺が小さい)ほど、Z軸の移動量は小さくなる

   要は、真横向きとか、傾きが大きいと、2D面積が小さくてもあんまり奥には配置しない、って事です。

# Z軸移動位置の算出

now_z_scale = pos_scale * (1 - smoothed_scale)
# Z軸の移動補正
bone_frame_dic["センター"][n].position.setZ(now_z_scale * center_z_scale)

Z軸補正は、XY移動量と連動しないパターンがあったので、別途外部パラメータで移動量調整できるようにしています。


課題


  • 腰から上半身を前向きに折るような姿勢の場合、Z軸移動で、希望より前に移動しがち。

  • XYおよびZ軸の移動量が外部パラメータ依存。自動判定できたらいいなぁ…


次回予定

最大の難関、足IK化。いつになるやら…