OpenCVのチェスボードコーナー検出について
キャリブレーションプログラムをデバッグしてたら気付いたのでメモ.
結論から言うと,最近のOpenCVではcv::findChessboardCorners()
を使う際にcv::cornerSubPix()
は必要ない.
内部で何が行なわれているか?
ネットに沢山転がっている典型的なチェスボードを使ったOpenCVのキャリブレーションサンプルは,例えば次のようなもの.(OpenCV.jpのOpenCV2.2日本語documentationより引用)
Size patternsize(8,6); // 内部にあるコーナーの個数 Mat gray = ....; // 入力画像 vector<Point2f> corners; // 検出されたコーナーがここに入ります // CALIB_CB_FAST_CHECK を使うと,画像中にチェスボードコーナーが // 無かった場合に,時間を大幅に節約できます bool patternfound = findChessboardCorners(gray, patternsize, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FAST_CHECK); if(patternfound) cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); drawChessboardCorners(img, patternsize, Mat(corners), patternfound);
さてこれをデバッグしてみると,findChessboardCorners()
を通り抜けた瞬間にcorners
にサブピクセル精度の座標値が入っているじゃないか!どうもおかしいと思って元々のcvFindChessboardCorners()
関数の定義(src/modules/calib3d/src/calibinit.cpp
)を見てみると...
CV_IMPL int cvFindChessboardCorners( const void* arr, CvSize pattern_size, CvPoint2D32f* out_corners, int* out_corner_count, int flags ) { //-------------537行目まで中略--------------- if( found ) { cv::Ptr<CvMat> gray; if( CV_MAT_CN(img->type) != 1 ) { gray = cvCreateMat(img->rows, img->cols, CV_8UC1); cvCvtColor(img, gray, CV_BGR2GRAY); } else { gray = cvCloneMat(img); } int wsize = 2; cvFindCornerSubPix( gray, out_corners, pattern_size.width*pattern_size.height, cvSize(wsize, wsize), cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); } //------------------後略--------------------- }
やっぱり.
思った通り,コーナーを見つけた直後にcvFindCornerSubPix()
が入っていました.完全にしてやられた気分.
というわけで,この記事を見つけた良い子の皆はcv::cornerSubPix()
などという無駄なコードを書くのを今すぐやめましょう.