2012年11月14日水曜日

ofxFaceTrackerの動かし方

ofxFaceTrackerはOpenFrameWorksのaddonで、安定して顔の3次元トラッキングができるプログラム。 試しにOpenFrameWorksからインストールして、動かしてみた。日本語でofxFaceTrackerのインストール方法など扱うサイトが見つからなかったので、メモを残しとく。

動作環境

  • Visual Studio 2010 SP1
  • Windows 7 Pro SP1
  • Nvidia Quadro 4000
  • NVIDIA CUDA Toolkit v4.2
  • OpenFrameWorks v0072 vs2010

コンパイル

  1. OpenFrameWorksをダウンロード
    http://www.openframeworks.cc/
  2. OpenFrameWorksをインストール。ここのページに従えば、特に問題なくサンプルコードが実行できる。
    http://www.myu.ac.jp/~xkozima/lab/mobile-iphone2011-wm.html
  3. oxfCVのダウンロード。
    https://github.com/kylemcdonald/ofxCv
  4. of_v0072_vs2010_release\addonsに展開したフォルダをコピーし、ofxCVというフォルダ名に変更。
  5. ofxFaceTrackerのダウンロード。
    https://github.com/kylemcdonald/ofxFaceTracker
  6. of_v0072_vs2010_release\addonsに展開したフォルダをコピーし、ofxFaceTrackerというフォルダ名に変更。
  7. AdvancedExample.slnを起動してビルド。
    of_v0072_vs2010_release\addons\ofxFaceTracker\example-advanced\AdvancedExample.sln

example-advancedの実行

  1. binフォルダにdataフォルダ作成
    of_v0072_vs2010_release\addons\ofxFaceTracker\example-advanced\bin\data\
  2. libs\FaceTracker\modelフォルダをexample-advanced\bin\data内にコピー
    of_v0072_vs2010_release\addons\ofxFaceTracker\libs\FaceTracker\model
  3. 実行

2012年11月13日火曜日

3次元計測による画像の平行化

平面を写した画像が手元にあり、そのカメラの姿勢(外部パラメータ)や画角など(内部パラメータ)が分かっている。さらに、その画像内の疎な(sparse)な点の3次元位置が分かっている時、その平面の画像を真正面から見た画像に変換することを考える。Stucture-from-motionやレーザレンジファインダ、MicrosoftのKinectなどで平面を含む対象を計測する場合に良くそのような状況に出くわす。Homography変換を使えばいいんだ、という程度の知識があることを前提に具体的方法をまとめる。

Homography変換による画像の平行化

このタスクは、平面に固定された座標$S$からカメラ座標$C$への剛体変換が回転行列$R_{S \rightarrow C}$と$t_{S \rightarrow C}$として分かっており、計測点の3次元位置が平面座標$S$で表現されていれば話は簡単である。まず通常の射影行列を考えてHomography変換行列を導出する。射影行列$P$は以下のように表す事ができる。

\[ P= \left[ \begin{array}{cccc} p_{11} & p_{12} & p_{13} & p_{14} \\ p_{21} & p_{22} & p_{23} & p_{24} \\ p_{31} & p_{32} & p_{33} & p_{34} \\ \end{array} \right] = K[R_{S \rightarrow C}|t_{S \rightarrow C}] \]

計測点の3次元位置をこの射影行列に掛ければ画像上のどの位置に投影されるかが計算できる。 今回、平面上の点を考えているので、平面座標$S$で表された3次元位置$(x_S, y_S, z_S)$の$z_S$は常に0だとすることができる。そうすると射影行列は下記のように$3 \times 3$の行列$H$に簡単化できてこれがHomography行列と呼ばれる。

\[ d \left[ \begin{array}{c} u\\ v\\ 1 \end{array} \right] = \left[ \begin{array}{cccc} p_{11} & p_{12} & p_{13} & p_{14} \\ p_{21} & p_{22} & p_{23} & p_{24} \\ p_{31} & p_{32} & p_{33} & p_{34} \\ \end{array} \right] \left[ \begin{array}{c} x_{S}\\ y_{S}\\ 0\\ 1 \end{array} \right] = \left[ \begin{array}{ccc} p_{11} & p_{12} & p_{14} \\ p_{21} & p_{22} & p_{24} \\ p_{31} & p_{32} & p_{34} \\ \end{array} \right] \left[ \begin{array}{c} x_{S}\\ y_{S}\\ 1 \end{array} \right] = H \left[ \begin{array}{c} x_{S}\\ y_{S}\\ 1 \end{array} \right] \]

3次元位置が世界座標系で表される場合

冒頭で示した状況もそうだけど、実際には、観測点やカメラの姿勢は平面に固定された座標で表されていることはなく、センサの位置を基準とした別の座標系で表されていることが一般的である。ここでは、その座標系を世界座標系$W$として、上のHomography行列$H$がどのようになるのか確認する。世界座標系で表現された平面座標$S$の基底ベクトル$e^{(x)}_W$、$e^{(y)}_W$、$e^{(z)}_W$と原点$O_W$は、それぞれ世界座標で表されたものが得られているものとする。また、カメラの姿勢は、世界座標$W$からカメラ座標$C$への変換$R_{W \rightarrow C}$、$t_{W \rightarrow C}$のみが得られており、平面座標$S$からカメラ座標$C$への剛体変換$R_{S \rightarrow C}$、$t_{S \rightarrow C}$は未知とする。

世界座標から平面座標への変換

観測点の3次元位置が世界座標で表されていても、 平面座標に変換することができれば後は上のHomography行列がそのまま使えることになる。 そこで下記のように平面座標$X_S$、$Y_S$、$Z_S$に変換する。

\[ \left[ \begin{array}{c} X_S\\ Y_S\\ Z_S \end{array} \right] = \left[ \begin{array}{c} {e^{(x)}_W}^T(X_W - O_W)\\ {e^{(y)}_W}^T(Y_W - O_W)\\ {e^{(z)}_W}^T(Z_W - O_W)\\ \end{array} \right] \]

同時座標表現をすれば、シンプルになる。

\[ \left[ \begin{array}{c|c} X_S\\ Y_S\\ Z_S\\ 1 \end{array} \right] = \left[ \begin{array}{cc} {e^{(x)}_W}^T & -{e^{(x)}_W}^T O_W\\ {e^{(y)}_W}^T & -{e^{(y)}_W}^T O_W\\ {e^{(z)}_W}^T & -{e^{(z)}_W}^T O_W\\ O & 1\\ \end{array} \right] \left[ \begin{array}{c} X_W\\ Y_W\\ Z_W\\ 1 \end{array} \right] = \left[ \begin{array}{cc} R_{W \rightarrow S} & -R_{W \rightarrow S} O_W\\ O & 1\\ \end{array} \right] \left[ \begin{array}{c} X_W\\ Y_W\\ Z_W\\ 1 \end{array} \right] \]

ただし、回転行列$R_{W->S}$は以下のように定義した。

\[ R_{W \rightarrow S} \equiv \left[ \begin{array}{c} {e^{(x)}_W}^T\\ {e^{(y)}_W}^T\\ {e^{(z)}_W}^T\\ \end{array} \right] \]

平面座標からカメラ座標への変換

これで世界座標$W$から平面座標$S$への変換が求まったので、この逆変換と世界座標$W$からカメラ座標$C$への変換$R_{W \rightarrow C}$、$t_{W \rightarrow C}$から、平面座標$S$からカメラ座標$C$への変換を求めHomography行列を算出する。

\[ \left[ \begin{array}{cc} R_{S \rightarrow C} & t_{S \rightarrow C}\\ O & 1\\ \end{array} \right] = \left[ \begin{array}{cc} R_{W \rightarrow C} & t_{W \rightarrow C}\\ O & 1\\ \end{array} \right] \left[ \begin{array}{cc} R_{W \rightarrow S} & -R_{W \rightarrow S} O_W\\ O & 1\\ \end{array} \right]^{-1} \] \[ = \left[ \begin{array}{cc} R_{W \rightarrow C} & t_{}\\ O & 1\\ \end{array} \right] \left[ \begin{array}{cccc} e^{(x)}_W & e^{(y)}_W & e^{(z)}_W & O_W\\ &O&&1 \end{array} \right] \]

求めるHomography行列$H$は、平面座標系$z$座標を0として以下のようになる。

\[ H= K \left[ \begin{array}{cc} R_{W \rightarrow C} & t_{}\\ O & 1\\ \end{array} \right] \left[ \begin{array}{cccc} e^{(x)}_W & e^{(y)}_W & O_W\\ 0 & 0 &1 \end{array} \right] \]

レンズの非線形歪みがある場合

レンズ歪は通常非線形変換であるから、レンズ歪を含む画像を扱う場合は、上記のように単純な変換にはならない。ここでは、$z=1$の面上で歪みが加わるレンズ歪みモデルの場合を扱う。

歪みのない座標$x_u$から歪みのある座標$x_v$へ変換する非線形変換関数を$f(x_u)$とすると、上記Homography変換は下記のような変換になる。

\[ x_d= K f\left( \left[ \begin{array}{cc} R_{W \rightarrow C} & t_{}\\ O & 1\\ \end{array} \right] \left[ \begin{array}{cccc} e^{(x)}_W & e^{(y)}_W & O_W\\ 0 & 0 &1 \end{array} \right] \left[ \begin{array}{c} X_S\\ Y_S\\ 1 \end{array} \right] \right) \]

ただし、オリジナルのTsaiのモデルでは、$z=f$の面上で歪が加わるため下記のようにはならない。 OpenCVに採用されているレンズ歪みモデルは、多項式モデルを含んでいるためTsaiのモデルの拡張とみなることができるが、$z=1$の面上で歪みが加わるモデルである。