5
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

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化。いつになるやら…

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?