OpenCV的Sample分析:相机标定(3)
在找到标定板之后,会进行如下的操作,
if ( found) // If done with success,
{
// improve the found corners' coordinate accuracy for chessboard
if( s.calibrationPattern == Settings::CHESSBOARD)
{
Mat viewGray;
cvtColor(view, viewGray, COLOR_BGR2GRAY);
cornerSubPix( viewGray, pointBuf, Size(11,11),
Size(-1,-1), TermCriteria( TermCriteria::EPS+TermCriteria::COUNT, 30, 0.1 ));
}
if( mode == CAPTURING && // For camera only take new samples after delay time
(!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) )
{
imagePoints.push_back(pointBuf);
prevTimestamp = clock();
blinkOutput = s.inputCapture.isOpened();
}
// Draw the corners.
drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
}
//! [pattern_found]
既然己经找到标定板,那么found=True,并且s.calibrationPattern == Settings::CHESSBOARD这条判断语句也是成立的,我们把彩色图像灰度化,即viewGray。对灰度图像进行cornerSubPix操作(作用是角点检测中精确角点位置),函数原型如下
void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize,
Size zeroZone, TermCriteria criteria);
在代码中,pointBuf是函数findChessboardCorners()得到的,也就是把棋盘格的角点找到,但是存在一些像素上的偏差。用cornerSubPix函数可以提高棋盘格角点的像素精度。
因为 mode == CAPTURING,所以这条if语句会被执行。pointBuf变量存放于imagePoints中。
最后drawChessboardCorners画出标定板上的角点位置。
总之,for的第一次循环干了这些事情:读取第一张图片,找到标定板,并把标定板上的角点找到,以亚像素级别储存在vector<vector<Point2f>>imagePoints中(以后的历次循环也都储存在这里)。在第一次循环中,因为imagePoints的数量达不到要求,不执行标定程序。
至少需要8张。
也就是说程序的第九次循环将执行标定。
if( mode == CAPTURING && imagePoints.size() >= (size_t)s.nrFrames )
{
if( runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints))
mode = CALIBRATED;
else
mode = DETECTION;
}
那么,函数runCalibrationAndSave()是怎样一回事呢?这个函数作用从它的名字就能了解。在这里,很想罗嗦罗嗦一句,就是看代码究竟是一探究竟好,把每个函数都看一遍,还是走马观花好。其实这得结合自己的需求。如果研究的项目跟它息息相关,就研究深一点,如果与当前研究关系不是特别大,那就研究浅一点,知道怎样去调用opencv函数。不要事事为完美。
bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,
vector<vector<Point2f> > imagePoints)
{
vector<Mat> rvecs, tvecs;
vector<float> reprojErrs;
double totalAvgErr = 0;
bool ok = runCalibration(s, imageSize, cameraMatrix, distCoeffs, imagePoints, rvecs, tvecs, reprojErrs,
totalAvgErr);
cout << (ok ? "Calibration succeeded" : "Calibration failed")
<< ". avg re projection error = " << totalAvgErr << endl;
if (ok)
saveCameraParams(s, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, reprojErrs, imagePoints,
totalAvgErr);
return ok;
}
先看函数变量,类Settings变量s记录了相机标定的初始设定信息,imageSize指图像大小,cameraMatrix指相机的投影矩阵(3×4的矩阵),而distCoeffs指畸变参数,而imagePoints指每帧图像中的角点位置。比如一个5×8的标定板,就有6×9=54个角点,假设我拍了八幅图片,就有54×8=432个角点信息。
投影矩阵由三部分组成,即相机内参数矩阵,旋转矩阵和平移向量。reprojErrs指重投影误差。有432个角点就有432个误差。
下次再来分析runCalibration()这个函数 : )