hen_cyberneの備忘録

C++とかメインで勉強中の情報系専攻の学生です。 え〜と 2×2は22・・・

2010年08月

Homography行列から併進・回転行列を算出するテスト(回転のみ)

Zhangの論文:「Flexible Camera Calibration By Viewing a Plane From Unknown Orientations」によると 平面から平面への変換行列(ホモグラフィー行列)から併進・回転行列を求めることができるそうです。

3次元空間中の平面上にある点Mが画像平面状の点mに射影されるときの式は以下のように記述できるようです。


eq_calcH




A がカメラの内部パラメータ行列、r1, r2がカメラの回転行列の1,2列目の列ベクトル、t が併進ベクトル。
ということはつまり、Aの逆行列を左から掛けてあげれば回転行列の成分と併進ベクトルがでてきそうですね。
実際にはスケールを考慮しなくてはならなく、以下の式になります。



eq_calcH_1



eq_calcH_2



eq_calcH_3



eq_calcH_4




ただし、H=[h1, h2, h3], R=[r1, r2, r3]です。
というわけで、実際に求まるのか試してみました。

実験に使った画像は以下の2枚。

image_0000    image_0002









コード(一部)は以下のカンジで書きました。
既にカメラ内部パラメータ行列A、ホモグラフィ行列Hは求まっているという前提です。 (実際には、OpenCVのAPIを用いて、チェスボードパターンのコーナー点抽出、カメラ内部パラメータ行列の推定、ホモグラフィ行列の推定を行いました。)

A 行列が

A











H行列が
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行列の成分が r















以下のサイト様の公開されている分度器を使いますと回転角は9度くらいだと分かります。 http://trojanbear.exblog.jp/6947322/

bundoki

















cos( 9[deg] ) = 0.9848・・・、 sin( 9[deg] ) = 0.1736・・・なので、

ちゃんと回転行列は

cos(θ)  -sin(θ) 0
sin(θ)  cos(θ)  0
 0         0      1
に近い値が求まっていますね。(θ=9[deg])

[opencv][カメラキャリブレーション]コーナー検出の中身読み込みサンプル

前日のカメラキャリブレーション関連の話の延長ですが、 コーナー検出点を外部ファイル(XML)に出力した後に、 別のプログラムで読み込みなおしたい時があると思います。(ありませんか?)

そこで、外部出力したXMLファイルの中身が以下のような場合の 読み込みプログラムのサンプル(擬似)を書いてみます。

XMLファイルの中身の一部は↓ <image_points type_id="opencv-matrix"> <rows>48</rows> <cols>1</cols> <dt>"2f"</dt> <data> 1.45261063e+002 1.03501350e+002 1.83908447e+002 1.03499428e+002 2.22637817e+002 1.03492523e+002 2.61512451e+002 1.03504921e+002 3.00406433e+002 1.03507042e+002 3.39133636e+002 1.03504784e+002 1.45256027e+002 1.42439774e+002 1.83901962e+002 1.42441360e+002 2.22630371e+002 1.42450546e+002 2.61518127e+002 1.42441422e+002 3.00402191e+002 1.42437820e+002 3.39119171e+002 1.42445007e+002 1.45262695e+002 1.81231094e+002 1.83892944e+002 1.81228958e+002 2.22636139e+002 1.81222672e+002 2.61512817e+002 1.81228012e+002 3.00409637e+002 1.81226669e+002 3.39118439e+002 1.81223877e+002 1.45260040e+002 2.19860550e+002 1.83899765e+002 2.19866409e+002 2.22635010e+002 2.19868073e+002 2.61519745e+002 2.19875381e+002 3.00408325e+002 2.19888107e+002 3.39114105e+002 2.19883896e+002 1.45259308e+002 2.58594360e+002 1.83893616e+002 2.58596405e+002 2.22629639e+002 2.58583466e+002 2.61518524e+002 2.58596924e+002 3.00402466e+002 2.58598633e+002 3.39113342e+002 2.58592438e+002 1.45256531e+002 2.97484161e+002 1.83910233e+002 2.97485260e+002 2.22633179e+002 2.97491486e+002 2.61515625e+002 2.97483490e+002 3.00404877e+002 2.97481171e+002 3.39123230e+002 2.97485077e+002 1.45263092e+002 3.36367126e+002 1.83926605e+002 3.36367310e+002 2.22640457e+002 3.36359009e+002 2.61506042e+002 3.36366302e+002 3.00415436e+002 3.36371429e+002 3.39131256e+002 3.36366272e+002 1.45265610e+002 3.75086609e+002 1.83912460e+002 3.75085052e+002 2.22629974e+002 3.75067566e+002 2.61512878e+002 3.75090027e+002 3.00406433e+002 3.75105591e+002 3.39134064e+002 3.75100952e+002 </data> </image_points> フォーマットとしては、"点1のx,y、点2のx,y、・・・点48のx,y" という風に並んでいます。 このデータを読み込むためのコードは以下のとおり。
loadCvPointList(
			cv::Mat            &pointList,
			const std::string  &fileName,
			const std::string  &nodeName )
{
	FileStorage fs ( fileName, FileStorage::READ );

	FileNode    topNode ( fs.fs, NULL ); // top node
	FileNode    pointsNode= top_node[nodeName];


	cv::read ( pointsNode, pointList );

	return ;
}


main ()
{
	cv::Mat    pointListMat;

	loadCvPointList ( pointListMat, "input.xml" , "image_points" );

	cv::Point2f  point1 = pointListMat.at< cv::Point2f >( 0, 0 );
	cv::Point2f  point2 = pointListMat.at< cv::Point2f >( 1, 0 );
}



するとこんなカンジに・・・

imagePoint

このコードはtakmin氏のコードを参考にさせていただきました。 http://d.hatena.ne.jp/takmin/20100108/1262938079

[opencv]カメラ内部パラメータ行列の内容確認

前日の画像を入力としてOpenCVを使って
カメラパラメータを求めて見ました。
以下に内部パラメータを表す3x3行列のcameraMatrixの
内容を表示します。

cameraMatrix_data
見た感じ、行列の中身の順序は、1次元配列の要素を
下のように並べてあるように思われます。

[0] [1] [2]
[3] [4] [5]
[6] [7] [8]

行ベクトルが上から下に並んでいるようです。
これがいわゆる row-order って言うのですかね・・・
良く分かっていません。

キャリブレーション用チェスボードのシミュレーションデータ(右併進カメラ)

画像のIDは

0    1   2
3    4   5
6    7   8
9   10  11
12  13  14
15  16  17
18  19  20
21  22
image_0000 image_0001 image_0002 image_0003 image_0004 image_0005 image_0006 image_0007 image_0008 image_0009 image_0010 image_0011 image_0012 image_0013 image_0014 image_0015 image_0016 image_0017 image_0018 image_0019 image_0020 image_0021 image_0022

キャリブレーション用チェスボードのシミュレーションデータ(左回転カメラ)

画像のIDは

0    1   2
3    4   5
6    7   8
9   10  11
12  13  14
15  16  17
18  19  20
21  22
image_0000 image_0001 image_0002 image_0003 image_0004 image_0005 image_0006 image_0007 image_0008 image_0009 image_0010 image_0011 image_0012 image_0013 image_0014 image_0015 image_0016 image_0017 image_0018 image_0019 image_0020 image_0021 image_0022

キャリブレーション用チェスボードのシミュレーションデータ(左併進カメラ)

画像のIDは

0    1   2
3    4   5
6    7   8
9   10  11
12  13  14
15  16  17
18  19  20
21  22
image_0000 image_0001 image_0002 image_0003 image_0004 image_0005 image_0006 image_0007 image_0008 image_0009 image_0010 image_0011 image_0012 image_0013 image_0014 image_0015 image_0016 image_0017 image_0018 image_0019 image_0020 image_0021 image_0022

キャリブレーション用チェスボードのシミュレーションデータ(正面カメラ)

画像のIDは

0    1   2
3    4   5
6    7   8
9   10  11
12  13  14
15  16  17
18  19  20
21  22
image_0000 image_0001 image_0002 image_0003 image_0004 image_0005 image_0006 image_0007 image_0008 image_0009 image_0010 image_0011 image_0012 image_0013 image_0014 image_0015 image_0016 image_0017 image_0018 image_0019 image_0020 image_0021 image_0022

キャリブレーション用チェスボードのシミュレーションデータ(右回転カメラ)

画像のIDは

0    1   2
3    4   5
6    7   8
9   10  11
12  13  14
15  16  17
18  19  20
21  22
image_0000 image_0001 image_0002 image_0003 image_0004 image_0005 image_0006 image_0007 image_0008 image_0009 image_0010 image_0011 image_0012 image_0013 image_0014 image_0015 image_0016 image_0017 image_0018 image_0019 image_0020 image_0021 image_0022

キャリブレーション用チェスボードのシミュレーションデータの構成情報メモ

中心にある、正面向いているカメラ
  光学中心(?) : 0, 0, 0;
  注視点      : 0, 1, 0;
  カメラの向き: 0, 1, 0;


上記カメラから回転移動しているカメラ

  回転角 : 20[deg]


最上記カメラから併進移動しているカメラ
  併進移動距離 : 0.2[M]


チェスボードの情報

  length : 0.932[M]
  width  : 0.72[M]

  chass_pattern_size : 0.1[M]??
screenShot002screenShot001
QRコード
QRコード
  • ライブドアブログ