【画像処理】Zhangのキャリブレーション

ひさびさに画像処理ネタです。


カメラキャリブレーションを勉強する必要が出てきたので
既に古い技術ですが、有名なマイクロソフトのZhangの方法を実装してみました。


元ネタ:http://research.microsoft.com/en-us/um/people/zhang/calib/


コード一式(VS2010、LAPCK等含みます):
http://navi.cs.kumamoto-u.ac.jp/~koutaki/calib.zip


Zhangの方法は、紙にマーカーを印刷して、それをカメラで何枚かとって、
各画像のマーカーの対応付けの情報を入力すると、各画像の撮影した位置や
カメラの内部パラメータ(カメラの光軸位置やレンズの歪みパラメータ)を
推定してくれるという、すごい方法です。
この方法が出てくる前はキャリブレーションは3Dの物体で計測する必要があり
大変だったのが、2Dで簡単にできるようになったらしいです。


OpenCVだと簡単にできるのですが、いざ自力で作ろうとすると、かなり大変でした。
(しかし、性能はOpenCVには及ばない・・・)
理論も難しいし、コンピュータビジョンも面白いと思った。
なお、論文にh_iという記号が出てきますが、iが列ベクトルを意味したり、
行ベクトルを意味したりするので注意が必要です。


基本的な考えは、リファレンスの点座標を画像上に投影するモデルを考えて、
画像上で観測した点座標との二乗残差を最小にするパラメタを求めるというものです。
この投影モデルが非線形(斜影変換とかレンズの歪とか)なのが厄介で、
これを解くためには、線形解法で推定した初期解から、マルカート法という非線形最適化で解を求めます。
こういう最適化をバンドル調整というらしい。


線形解法はlapackが使えて、マルカート法はminpackというライブラリが使えます。
minpackは初めて使ってみましたが、かなり便利ですね。
マルカート法は目的関数の微分が必要で、その計算が面倒だな、と思っていましたが、
minpackは前方差分で勝手にやってくれます。

結果

上のコードでは、シミュレーションのデータを作って、それでパラメタを推定するものです。
対応点が誤差もなく完全に分かっているという条件が良い設定です。
実際に使うためには、マーカーを高精度に検出する画像処理部分を作る必要があります。



こんな感じの画像を数枚撮影して、白点を検出&対応付けしたとして、
それから自動でカメラパラメタを計算する。画像はレンズの歪みのため、歪曲している。



カメラパラメタが分かれば、このようにレンズの歪みを取り除ける。
レンズの歪みはカメラの光軸中心やレンズパラメタに依存するので取り除くは大変です。

分からない点

レンズ歪は良く推定できるのだけど、gammaの値がおかしい。
また、観測点にノイズがのると全体的に結果がおかしくなる。


おそらく、カメラの回転行列の推定で、単純にマルカート法で更新をかけると
回転行列の直交性が崩れたまま最適化を続けているのが原因の一つだと思っています。
でも、この対策方法が分からないです。だれか教えてください。

自己解決しました

http://www.fractal.is.tohoku.ac.jp/okatani/pub/cvim.pdf
ここの最後の回転の差分表示を使えばできました。
つまり、線形解法で求まった回転行列Rを固定して、
最適化をかけるパラメータを3つのオイラー角を用意して、
それからできる回転行列δRを用いて、RδRとすれば回転行列の直交性を保ったまま
最適化が可能です。