Zhangの論文:「Flexible Camera Calibration By Viewing a Plane From Unknown Orientations」によると
平面から平面への変換行列(ホモグラフィー行列)から併進・回転行列を求めることができるそうです。
3次元空間中の平面上にある点Mが画像平面状の点mに射影されるときの式は以下のように記述できるようです。
A がカメラの内部パラメータ行列、r1, r2がカメラの回転行列の1,2列目の列ベクトル、t が併進ベクトル。
ということはつまり、Aの逆行列を左から掛けてあげれば回転行列の成分と併進ベクトルがでてきそうですね。
実際にはスケールを考慮しなくてはならなく、以下の式になります。
ただし、H=[h1, h2, h3], R=[r1, r2, r3]です。
というわけで、実際に求まるのか試してみました。
実験に使った画像は以下の2枚。
コード(一部)は以下のカンジで書きました。
既にカメラ内部パラメータ行列A、ホモグラフィ行列Hは求まっているという前提です。 (実際には、OpenCVのAPIを用いて、チェスボードパターンのコーナー点抽出、カメラ内部パラメータ行列の推定、ホモグラフィ行列の推定を行いました。)
A 行列が
H行列が
コードは以下のカンジで書きました。
で、結果は以下のようになりました。 R行列の成分が
以下のサイト様の公開されている分度器を使いますと回転角は9度くらいだと分かります。 http://trojanbear.exblog.jp/6947322/
cos( 9[deg] ) = 0.9848・・・、 sin( 9[deg] ) = 0.1736・・・なので、
ちゃんと回転行列は
3次元空間中の平面上にある点Mが画像平面状の点mに射影されるときの式は以下のように記述できるようです。
A がカメラの内部パラメータ行列、r1, r2がカメラの回転行列の1,2列目の列ベクトル、t が併進ベクトル。
ということはつまり、Aの逆行列を左から掛けてあげれば回転行列の成分と併進ベクトルがでてきそうですね。
実際にはスケールを考慮しなくてはならなく、以下の式になります。
ただし、H=[h1, h2, h3], R=[r1, r2, r3]です。
というわけで、実際に求まるのか試してみました。
実験に使った画像は以下の2枚。
コード(一部)は以下のカンジで書きました。
既にカメラ内部パラメータ行列A、ホモグラフィ行列Hは求まっているという前提です。 (実際には、OpenCVのAPIを用いて、チェスボードパターンのコーナー点抽出、カメラ内部パラメータ行列の推定、ホモグラフィ行列の推定を行いました。)
A 行列が
H行列が
コードは以下のカンジで書きました。
cv::Mat RT = A.inv() * H; cv::Vec3f rVec1 = Vec3f( RT.at< double >(0,0), RT.at< double >(1,0), RT.at< double >(2,0) ); cv::Vec3f rVec2 = Vec3f( RT.at< double >(0,1), RT.at< double >(1,1), RT.at< double >(2,1) ); cv::Vec3f tVec = Vec3f( RT.at< double >(0,2), RT.at< double >(1,2), RT.at< double >(2,2) ); cv::Vec3f rVec3 = rVec1.cross ( rVec2 ); normalize ( rVec1 ); normalize ( rVec2 ); normalize ( rVec3 );
void normalize ( cv::Vec3f& vec ) { float a = vec[0] * vec[0]; float b = vec[1] * vec[1]; float c = vec[2] * vec[2]; float norm = sqrt ( a + b + c ); vec[0] /= norm; vec[1] /= norm; vec[2] /= norm; }
で、結果は以下のようになりました。 R行列の成分が
以下のサイト様の公開されている分度器を使いますと回転角は9度くらいだと分かります。 http://trojanbear.exblog.jp/6947322/
cos( 9[deg] ) = 0.9848・・・、 sin( 9[deg] ) = 0.1736・・・なので、
ちゃんと回転行列は
cos(θ) -sin(θ) 0 sin(θ) cos(θ) 0 0 0 1に近い値が求まっていますね。(θ=9[deg])