第15回目の今回は、OpenCVに実装されているカメラキャリブレーションの概要について紹介します。

カメラキャリブレーションとは、レンズ焦点距離などの内部パラメータと、カメラの位置・姿勢を表す外部パラメータ、レンズの歪収差係数を求め、画像を補正する処理のことです(図1)。
Zhangの手法が有名で、OpenCVに実装されていることもあり世界で最も用いられています。ライブラリ化されているため誰でも簡単に利用することができますが、その反面キャリブレーションの処理について知らなくても実装できてしまいます。本記事では、そのOpenCVに実装されているZhangの手法について説明します。
内部パラメータ(Intrinsic parameters)、外部パラメータ(Extrinsic parameters)、歪収差係数(distortion coefficients)については、ここでは説明を割愛しますので、Wikipedia「Camera resectioning」「Distortion(optics)」などをご覧ください。

図1 カメラキャリブレーション結果を用いた画像の補正例

図1 カメラキャリブレーション結果を用いた画像の補正例

カメラキャリブレーションの概要

まず、カメラキャリブレーション処理のフローを示します。
ステップ1:
既知の平面パターン(OpenCVの場合、スクエアグリッド、サークルグリッド)を最低2方向から撮影します(図1)。
ステップ2:
撮影した画像から特徴点(直線の交点、または円の重心)を検出し、画像座標系での特徴点の座標を求めます。
ステップ3:
ステップ2で検出した特徴点の座標を用いて、カメラの内部パラメータの初期値を求めます。この時点では、レンズの歪収差係数はゼロです。
ステップ4:
バンドル調整と呼ばれている非線形最適化処理で、カメラの内部パラメータ、外部パラメータ、歪収差係数を求めます。
ステップ5:
求めた内部パラメータ、歪収差係数を用いて、歪みのない画像に補正します。

ステップ2の処理は、cv::findChessboardCorners()とcv::cornerSubPix()、あるいはcv::findCirclesGrid()です。ステップ3、4は、cv::calibrateCamera()で、魚眼レンズの場合はcv::fisheye::calibrate()です。ステップ5は、cv::undistort()、あるいはcv::initUndistortRectifyMap()とcv::remap()の組み合わせで処理できます。魚眼レンズの場合は、cv::fisheye::undistortImage()、またはcv::fisheye::initUndistortRectifyMap()とcv::remap()です。コーディングについては、OpenCVのカメラキャリブレーションのサンプルコードが公開されているので、そちらを参考にしてください。
ステップ3で求める初期値は、かなり大雑把にしか求まりません。カメラの設計値がわかっている場合は、calibrateCamera( )のフラグCV_CALIB_USE_INTRINSIC_GUESSをセットして、内部パラメータの初期値に設計値を与えると良いでしょう。外部パラメータも求めることができます。このキャリブレーションで求まる外部パラメータは、平面パターン上の3次元座標系とカメラ座標系間の外部パラメータです。

平面パターンの撮像例

異なる視点から撮像した画像が最低2枚必要と書きましたが、図2のとおり、正面、左斜め、右斜め、上斜め、下斜めから見た5枚があるとより良いです。異なる距離で各方向から撮像した5枚を加えた計10枚を用いると、さらに良いと思います。似たような視点の映像ばかりが多数含まれないようにしましょう。

図2 カメラキャリブレーションに用いる平面パターンの撮像例

図2 カメラキャリブレーションに用いる平面パターンの撮像例

スクエアグリッドとサークルグリッドどちらを使うべきか?

結論から言うと、サークルグリッドを使う方が良いです。理由は、ステップ2の特徴点の座標の算出精度がサークルグリッドの方が高いからです。楕円(円を含む)は、斜めから見ても楕円という特性があるため、重心を特徴点とすることで特徴点の座標を精度良く求めることができます。一方、スクエアグリッドの場合は、直線と直線の交点を特徴点とします。斜めから見ると正方形の形状が歪んでしまい、安定して座標を求めることができません。
スクエアグリッドとサークルグリッドの性能を比較した結果が図4です。各パラメータ、特徴点の座標の真値が既知である合成画像(図3)を用いて比較した結果です。

図3 性能比較実験に用いた合成画像(CG)

図3 性能比較実験に用いた合成画像(CG)

図の左から順に、fx、fy、u0、v0が内部パラメータ、k1、k2、p1、p2が歪収差係数、RMSE(Root Mean Squared Error)はステップ4のバンドル調整時の誤差、一番右は特徴点の座標の算出誤差です(赤色の縦の点線は真値)。平面パターンを撮像する視点を変えてカメラキャリブレーションを15回試行した結果です。特徴点の座標の算出精度が、スクエアグリッド(表の上段)よりもサークルグリッド(表の下段)の方が高い(すなわち誤差が小さい)ため、すべてのパラメータを安定的に精度良く求めることができます。

図4 性能比較実験の結果

図4 性能比較実験の結果

OpenCVのカメラキャリブレーションを用いる場合は、サークルグリッドの平面パターンを利用し、また魚眼レンズの場合は、魚眼レンズ用の関数を用いるようにしましょう。

次回は、カメラを用いた3次元計測手法の全体像について解説します!