OpenCV的Sample分析:相机标定(3)

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()这个函数 : )










猜你喜欢

转载自blog.csdn.net/qq_39732684/article/details/80350013