かみのメモ

コンピュータビジョン・プログラムな話題中心の勉強メモ

OpenCVのカメラ歪みシミュレータを作ってみた

OpenCVのカメラキャリブレーションの際に取得できる歪みパラメータを可視化するWebアプリを作ってみました。

キャリブレーション結果の確認などにお使いください。

https://kamino410.github.io/cv-snippets/camera_distortion_simulator/

screen shot

ソースコードこちら

できるだけの動作確認はしていますが、もしバグを見つけた場合はGitHubで報告していただけると幸いです。

実装をざっくり解説

OpenCV3.4では、カメラ歪みモデルを以下のように仮定しています。

 \begin{array}{l} x' = x _ {undistort} \\ y' = y _ {undistort} \\ r ^ 2 = x' ^ 2 + y' ^ 2 \\ x'' = x' \frac{1 + k _ 1 r ^ 2 + k _ 2 r ^ 4 + k _ 3 r ^ 6}{1 + k _ 4 r ^ 2 + k _ 5 r ^ 4 + k _ 6 r ^ 6} + 2 p _ 1 x' y' + p _ 2(r ^ 2 + 2 x' ^ 2) + s _ 1 r ^ 2 + s _ 2 r ^ 4 \\ y'' = y' \frac{1 + k _ 1 r ^ 2 + k _ 2 r ^ 4 + k _ 3 r ^ 6}{1 + k _ 4 r ^ 2 + k _ 5 r ^ 4 + k _ 6 r ^ 6} + p _ 1 (r ^ 2 + 2 y' ^ 2) + 2 p _ 2 x' y' + s _ 3 r ^ 2 + s _ 4 r ^ 4 \\ x _ {distort} = f _ x x'' + c _ x \\ y _ {distort} = f _ y y'' + c _ y \end{array}

※ カメラモデルの詳細はこちらの記事で解説しています↓

kamino.hatenablog.com

この式では、歪んだ後の画像座標を歪む前の画像座標の陽関数として定義しています。 このように定義すると、歪んだ画像を元に戻す処理(Undistort)はremap()を使って比較的簡単に実装できます。

一方、このモデルのとおりに画像を歪ませる処理は割合難しいものになります。 詳しい解説は省きますが、上記の多項式の逆問題を解くか、もしくは格子状に並んでいない点群の間での補間処理を実装する必要があるためです。

ということで、今回はWebGL上で適当な粗さの三角メッシュを歪めて、メッシュの中では線形補間を行う、という近似的な方法で実装しました。

放射状歪みの係数を負にしたとき背景に針山が現れるバグがあるんですが、WebGLはGeometry Shaderに対応していないらしく、修正困難なので放置しています。