踊ってみた動画から姿勢推定する実験

たまに, ニコニコ動画で踊ってみた動画とか, MMDで作られた動画とか見るんですけど, それを見てる時に「ボーカロイドの曲に合わせて踊っている人沢山いるしモーションを踊ってみた動画から生成できればいいんじゃないか?」と思ったわけですね. あとは, MMDで3次元のアニメーション作るのって初心者には難しくて, だったら2次元の動画から作れたらいいよねという思いもありました. Kinectにも対応しているようですけど, そもそも踊れないとダメですしね(´・ω・`)

一応, 目的は踊っている人の関節位置を動画の毎フレーム, ユーザが指定することで, 3次元の姿勢を推定することとします. しかも, カメラの内部, 外部パラメタは未知の状態から推定する必要があります. 当然, 使用したカメラの情報までうpしている人はいないので.

まずは, 人体のモデルを定義しないと話にならないので, 定義します. 骨は17本とします.
human-model
ユーザはこのモデルの関節に当たる部分を動画の1フレームごとに指定していきます.

カメラは弱中心射影カメラを仮定します. いくつか踊ってみた動画を見た感じ, ほぼ全身が映るように撮影されているようなので, カメラから人体までの距離が十分大きいと仮定できるんじゃないでしょうか.
弱中心射影カメラを仮定したことにより, カメラ座標系での点{\bf p} = \left(x, y, z\right)^Tは, {\bf x} = \left(u, v\right)^T =  \left(sx, sy\right)^Tに投影されます. sは未知の内部パラメタ, スケールファクタです.

上記を踏まえて, 拘束を導きます. i番目の骨の長さをl_iとすると, 以下の拘束が得られます.
\displaystyle{  l_i^2 = \left| {\bf p}_{i_1} - {\bf p}_{i_2}\right|^2, i=1, \ldots, B  }
ここで, B=17は骨の本数, {\bf p}_{i_1}, {\bf p}_{i_2}i番目の骨の始点, 終点です. これを画像平面上の点{\bf x}を使って書き直すと.
\displaystyle{  dz_i^2 = l_i^2 - \frac{\left| {\bf x}_{i_1} - {\bf x}_{i_2}\right|^2}{s}, i=1, \ldots, B  }
が得られます. ここで, dz_iは始点, 終点の相対的な深さです. この拘束が毎フレーム分得られるので, フレーム数をKとすると, KBの拘束が得られることになります. また, 人体は腕, 脚が左右で同じ長さであるはずなので, l_{i_1}^2 = l_{i_2}^2, i=1, \ldots, 7 の拘束が下腕, 上腕, 肩, 股関節, 上脚, 下脚, 足について合計7つ得られます. さらに, 人体モデルの図で点線で表した部分(以下, 仮想骨と呼びます)の長さはあらゆる姿勢でほぼ変化しないということがモーションキャプチャ関連の先行研究で分かっているので, 1フレームにつき以下の4つの拘束が得られます. あらゆる姿勢で仮想骨の長さは変わらない(仮想骨を1辺とする三角形は剛体とみなせる)ので, 仮想骨を1辺とする三角形を考えて, 1辺の相対深度は他の2辺の相対深度の和になってなければならないという条件と最初に導出した拘束を使って導出します.
\displaystyle{  \left( l_{B,C}^2 - \frac{\left| {\bf x}_B - {\bf x}_C \right|^2}{s^2} - dz_{A,B}^2 - dz_{A,C}^2 \right)^2 = 4 dz_{A,B}^2 dz_{A,C}^2  }
\displaystyle{  \left( l_{A,E}^2 - \frac{\left| {\bf x}_A - {\bf x}_E \right|^2}{s^2} - dz_{A,D}^2 - dz_{D,E}^2 \right)^2 = 4 dz_{A,D}^2 dz_{D,E}^2  }
\displaystyle{  \left( l_{A,F}^2 - \frac{\left| {\bf x}_A - {\bf x}_F \right|^2}{s^2} - dz_{A,D}^2 - dz_{D,F}^2 \right)^2 = 4 dz_{A,D}^2 dz_{D,F}^2  }
\displaystyle{  \left( l_{E,F}^2 - \frac{\left| {\bf x}_E - {\bf x}_F \right|^2}{s^2} - dz_{E,D}^2 - dz_{D,F}^2 \right)^2 = 4 dz_{E,D}^2 dz_{D,F}^2  }
ここで, 仮想骨の長さl_{B,C}, l_{A,F}, l_{A,E}, l_{E,F} を新たな未知数として導入しました.

一旦未知数と拘束の個数をまとめておきます. 未知数は各骨, フレームごとの相対深度{\bf dz}^2 \in R^{KB} , 各フレームごとのカメラのスケールファクタ{\bf s}^2 \in R^K, 骨長さ{\bf l}^2 \in R^{B-1}, 仮想骨長さ{\bf e}^2 = \left(l_{B,C}^2, l_{A,F}^2, l_{A,E}^2, l_{E,F}^2 \right)^Tなので, KB + K + B + 3個となっています. 骨長さの絶対的な長さは単眼カメラを使用しているため求めることは不可能なので, 1番目の骨の長さを1として他の骨の長さを求めます. そのため, 骨長さの未知数はB-1個となっています.
一方拘束は, 各骨, フレームごとに
\displaystyle{  dz_i^2 = l_i^2 - \frac{\left| {\bf x}_{i_1} - {\bf x}_{i_2}\right|^2}{s}, i=1, \ldots, B  }
KB個, l_{i_1}^2 = l_{i_2}^2が7個, 各フレームごとに
\displaystyle{  \left( l_{B,C}^2 - \frac{\left| {\bf x}_B - {\bf x}_C \right|^2}{s^2} - dz_{A,B}^2 - dz_{A,C}^2 \right)^2 = 4 dz_{A,B}^2 dz_{A,C}^2  }
\displaystyle{  \left( l_{A,E}^2 - \frac{\left| {\bf x}_A - {\bf x}_E \right|^2}{s^2} - dz_{A,D}^2 - dz_{D,E}^2 \right)^2 = 4 dz_{A,D}^2 dz_{D,E}^2  }
\displaystyle{  \left( l_{A,F}^2 - \frac{\left| {\bf x}_A - {\bf x}_F \right|^2}{s^2} - dz_{A,D}^2 - dz_{D,F}^2 \right)^2 = 4 dz_{A,D}^2 dz_{D,F}^2  }
\displaystyle{  \left( l_{E,F}^2 - \frac{\left| {\bf x}_E - {\bf x}_F \right|^2}{s^2} - dz_{E,D}^2 - dz_{D,F}^2 \right)^2 = 4 dz_{E,D}^2 dz_{D,F}^2  }
4K個, 合計KB+4K+7個の拘束があります. 拘束が未知数より多くなければ解けないので, K \geq 5以上のフレームが必要となります.

上記の拘束を用いてLevenberg-Marquardt法により解を求めます. 拘束の左辺を右辺の差が0にならなければならないので, 目的は
\displaystyle{  \arg \min_{{\bf dz}^2, {\bf s}^2, {\bf l}^2, {\bf e}^2} E_p \left({\bf l}^2, \frac{1}{{\bf s}^2}, {\bf dz}^2 \right) + \lambda_1 E_s \left({\bf l}^2\right)+ \lambda_2 E_r \left({\bf e}^2, \frac{1}{{\bf s}^2}, {\bf dz}^2\right)  }
となります. ここで, E_p, E_s, E_rはそれぞれ上記の3つの拘束の右辺を左辺に移項して2乗したものです. \lambda_1, \lambda_2はそれぞれ, どちらの拘束を優先して最適化を行うかというパラメタです.

ここまでで, 骨長さと相対深度, スケールファクタがわかりましたが, 各未知数を2乗したまま解いたので相対深度の符号が定まらず, 姿勢を一意に決定することができません. そこで, 関節の再投影誤差が最小になるように関節角度を求めることで, 最終的な姿勢を求めます. 関節の自由度は頭2, 首2, 背骨3, 左右の鎖骨2, 上腕骨3, 肘1, 大腿骨3, 膝1, 足首2の合計31なので, 各フレームを考えると未知数は{\bf q}_k \in R^{31}, k=1, \ldots, Kとなります.
関節角と上記で求めた骨長さを用いると, i番目の関節の座標は{\bf p}_{k,i} = {\bf f}_i \left({\bf q}_k, {\bf l} \right)となります. ここで, {\bf f}_ii番目の関節をカメラ座標系に座標変換する関数とします. そうすると, 関節の再投影誤差は
\displaystyle{  E_p^{\prime} = \sum_{k=1}^K \sum_{i=1}^B \left(s_k {\bf f}_i \left({\bf q}_k, {\bf l} \right)  - {\bf x}_{k,i} \right)^T  \left(s_k {\bf f}_i \left({\bf q}_k, {\bf l} \right)  - {\bf x}_{k,i} \right)  }
となります. また, 仮想骨長さは各フレームで変化しないので
\displaystyle{  E_r^{\prime} = \sum_{k=1}^K \sum_{i=1}^4 \left(   \left|    {\bf f}_{i_1} \left({\bf q}_k, {\bf l} \right)  -  {\bf f}_{i_2} \left({\bf q}_k, {\bf l} \right)   \right|^2 - e_i   \right)^2  }
となります. ここで, {\bf f}_{i_1},  {\bf f}_{i_2}はそれぞれ, i番目の仮想骨の始点, 終点の座標を表しています. これらの拘束を使うと, 関節角には可動域の上限, 下限{\bf q}^l, {\bf q}^uがあることから, 目的は
\displaystyle{  \arg \min_{\{{\bf q}_k\}} E_p^{\prime} +\lambda_1 E_r^{\prime} s.t. {\bf q}^l \leq {\bf q}_k \leq {\bf q}^u  }
となります. これをLevenberg-Marquardt法で解くことで, 全てではないですが, たいていの場合は姿勢を一意に決定することができます. {\bf q}_kの初期値は, 相対深度の符号をランダムに決定した値{\bf dz}と骨長さ{\bf l}を使って逆運動学により求めたものを使います.

とりあえずハロ/ハワユの踊ってみた動画から姿勢を推定してみました. 以下のようにフレームを移動しながら, マウスで各関節を指定していきます.
sc2-image
再投影誤差最小化をして関節角度を求めている様子です.
ss1
以下が得られた姿勢ですが, 奥行きの推定がうまくいってないのがわかります. やっぱり奥行きの推定は難しいですね.
sc2-model

sc2-model2

今回の実験ではあまり上手くいきませんでしたが, いくつか改善の余地はあると思っています. たとえば, 骨長さは身長が決まればだいたいわかるので, いくつか人体モデルを用意して骨長さは既知として解く, 踊ってみた動画は撮影中カメラが固定されていると考えられるので各フレームスケールファクタをすべて同じと仮定することで未知数を減らす, などです.

広告
カテゴリー: Computer Vision, OpenCV, OpenGL パーマリンク

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中