パンチルト運台に載ったカメラの外部パラメータキャリブレーション
(編集中、まだできてない)
カメラ座標系とパンチルト運台の回転中心とのオフセットを求めてみたいと思います。真面目に幾何学問題を解くのは苦手なので、出来るだけ手軽にできる方法を探します。
パンチルト運台の回転中心は、パンもチルトも仮想的に一点を中心に回転していると仮定できるとすると、可動範囲を走査した時の、その上に載せられたカメラの軌跡は球を描くことになるはずです。走査中の3次元空間中のカメラの位置が得られれば、そこから最小二乗法で球の中心を推定してやれば、それが回転中心になります。カメラの3次元位置を求めるのにSFM(Structure From Motion)が使えそうです。
SfmのためにBundlerのインストール
Windowsにインストールします。
1.[1]からbundler-v0.4-source.zipをダウンロードして解凍します。自分でコンパイルするのが面倒臭い場合は、v0.3のコンパイル済みバイナリを持ってきます。特徴点抽出のためにSIFTの実装も準備する必要があります。Keypoint detectorからSIFT demo program (Version 4, July 2005)をダウンロードし展開後、中のsiftWin32.exeをBundlerのBinにコピーします。
2.cygwinを入れます。[4]によるとperl,graphicsパッケージも入れる必要があるようです。パッケージ名横のdefaultをinstallに変更してから、インストールを進めます。
3.Windowsのシステムの環境変数PATHに、Bundlerのベースディレクトリとその下のbinを加える。
4.Cygwin上で./RunBundler.sh examples/kermit/で動作テスト。cd /cygdrive/c/workspace/bundler-v0.3などインストールディレクトリに移動。
RunBundler.shファイルを下手にワードパッド等で編集してしまうと、改行コードがおかしくなって正しく動作しない場合があるようです。
パンチルト運台を動かしながら、カメラ撮影
ダミーコードを書くとこんな感じ。
int min_pan = -120;
int max_pan = 120;
int min_tilt = -70;
int max_tilt = 20;
int pan_step = 5;
int tilt_step = 5;
string ip = "10.254.20.15";
string port = "5008";
lo_address a = lo_address_with_ptroto(LO_TCP, ip.data, port.data);
int idx = 0;
// pan = tilt = 0 を基準にしたい
// 首を動かす
lo_send(a, "/hiro/moveBody", "ii", 0, 0);
// 待つ
cv::waitKey(500);
cam.grab(img_l);
cam.grab(img_r);
char img_l, img_r;
sprintf_s(img_l, "L_%03d_%03d_%03d.jpg", 0, 0, 0);
sprintf_s(img_r, "R_%03d_%03d_%03d.jpg", 0, 0, 0);
cv::imwrite(filename_l, img_l);
cv::imwrite(filename_r, img_r);
for(int pan = min_pan; pan<max_pan; pan += pan_step){
for(int tilt = min_tilt; tilt<max_tilt; tilt += tilt_step){
// 首を動かす
lo_send(a, "/hiro/moveBody", "ii", pan, tilt);
// 待つ
cv::waitKey(500);
cam.grab(img_l);
cam.grab(img_r);
sprintf_s(img_l, "L_%03d-%03d.jpg", pan, tilt);
sprintf_s(img_r, "R_%03d-%03d.jpg", pan, tilt);
cv::imwrite(filename_l, img_l);
cv::imwrite(filename_r, img_r);
}
}
カメラに動くものが入らないようにして、全周分撮影する。
Bundlerによるカメラ位置姿勢の推定結果を図示したものがこちら。何となく、弧を描いているのが見えます、が、精度悪いですね・・・。
また、大問題が一つあって、それはスケールに冗長性が残っていることです。
カメラパラメータを画像ごとに推定するのではなく、ステレオキャリブレーションですでに得られているものを使えばマシになるでしょうか?ということで調べてみると、BundlerのFAQに秘密のオプション--intrinsicsの使い方が書かれています。
1行目:カメラパラメータの数
2行目:3×3の内部パラメータ行列 fw 0 cx 0 fh cy 0 0 1
[fw, 0, cx]
[0, fh, cy]
[0,0,1]
3行目:レンズの歪み係数 k1 k2 k3 k4 k5
をintrinsics.txt等に記述する。複数のカメラにそれぞれ違うパラメータを与えたい時は、その台数分順番に記述する。すべて同じカメラパラメータでいい時は一つで良い。
Cygwinで./Run_Bundler.sh を一度動かして対応点の情報などを得た後、
Bundler.exe list.txt --options_file option2.txt > bundler/out
などのようにしてBundlerを実行する。
option2.txtはoption.txtを編集して作る。focal_estimateをしないように関連オプションを消す。
intrinsic.txtの適当な例
1
9.3002122663905698e+002 0 6.3357145490729965e+002 0 9.3002122663905698e+002 5.2056352402898324e+002 0 0 1
-5.4804389490301905e-002 6.8502229971153947e-002 0 0 0
optionsの例
--match_table matches.init.txt
--output bundle.out
--output_all bundle_
--output_dir bundle
--intrinsics intrinsics.txt
--run_bundle
途中・・・
[1]Bundler - Structure from Motion (SfM) for Unordered Image Collections
[2]私の研究開発ツール(第46回)- Bundler: Structure from Motion for Unordered Image Collections
[3]http://www.riken.jp/brict/Ijiri/study/VC2010_4.html