使用数码相机进行相机校准

Posted

技术标签:

【中文标题】使用数码相机进行相机校准【英文标题】:Camera Calibration with a Digital Camera 【发布时间】:2012-01-26 04:58:16 【问题描述】:

知道我已经从事相机校准大约一周了。我从在线文章和博客中看到的示例使用网络摄像头来捕获图像。

但对于我的场景,我使用的是卡西欧 Exilim EX-Z77 数码相机。我将图像添加到设置的程序参数中,并使用 for 循环单独访问它们。通过这种方式,我能够模仿网络摄像头的工作方式。

我有可能得到正确的扭曲和内在函数吗? 如果我错了或有误解,请纠正我。

Here 是我基于我的代码的文章。下面的代码是我能做的。

     int n_boards = 0;
     int board_w;
     int board_h;
     using namespace std;
    int main( int argc, char *argv[] )
    
 board_w = 5; // Board width in squares
 board_h = 8; // Board height
 n_boards = 16; // Number of boards
 int board_n = board_w * board_h;
 CvSize board_sz = cvSize( board_w, board_h );

 CvMat* image_points        = cvCreateMat( n_boards*board_n, 2, CV_32FC1 );
 CvMat* object_points       = cvCreateMat( n_boards*board_n, 3, CV_32FC1 );
 CvMat* point_counts            = cvCreateMat( n_boards, 1, CV_32SC1 );
 CvMat* intrinsic_matrix        = cvCreateMat( 3, 3, CV_32FC1 );
 CvMat* distortion_coeffs   = cvCreateMat( 5, 1, CV_32FC1 );

 CvPoint2D32f* corners = new CvPoint2D32f[ board_n ];
 int corner_count;
 int successes = 0;
 int step;

      int a;
      for(a =1; a<=n_boards; a++)

   while( successes < n_boards )

        IplImage *image = cvLoadImage(argv[a]);
        IplImage *gray_image = cvCreateImage( cvGetSize( image ), 8, 1 );

        int found = cvFindChessboardCorners( image, board_sz, corners,
            &corner_count, CV_CALIB_CB_ADAPTIVE_THRESH |         CV_CALIB_CB_FILTER_QUADS );

        // Get subpixel accuracy on those corners
        cvCvtColor( image, gray_image, CV_BGR2GRAY );
        cvFindCornerSubPix( gray_image, corners, corner_count, cvSize( 11, 11 ),
            cvSize( -1, -1 ), cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));

        // Draw it
        cvDrawChessboardCorners( image, board_sz, corners, corner_count, found );
        //cvShowImage( "Calibration", image );

        // If we got a good board, add it to our data
        if( corner_count == board_n )
            step = successes*board_n;
            for( int i=step, j=0; j < board_n; ++i, ++j )
                CV_MAT_ELEM( *image_points, float, i, 0 ) = corners[j].x;
                CV_MAT_ELEM( *image_points, float, i, 1 ) = corners[j].y;
                CV_MAT_ELEM( *object_points, float, i, 0 ) = j/board_w;
                CV_MAT_ELEM( *object_points, float, i, 1 ) = j%board_w;
                CV_MAT_ELEM( *object_points, float, i, 2 ) = 0.0f;
            
            CV_MAT_ELEM( *point_counts, int, successes, 0 ) = board_n;
            successes++;
        


  IplImage *image1 = cvLoadImage(argv[1]);
CvMat* object_points2 = cvCreateMat( successes*board_n, 3, CV_32FC1 );
CvMat* image_points2 = cvCreateMat( successes*board_n, 2, CV_32FC1 );
CvMat* point_counts2 = cvCreateMat( successes, 1, CV_32SC1 );


// Transfer the points into the correct size matrices
for( int i = 0; i < successes*board_n; ++i )
    CV_MAT_ELEM( *image_points2, float, i, 0) = CV_MAT_ELEM( *image_points, float, i, 0 );
    CV_MAT_ELEM( *image_points2, float, i, 1) = CV_MAT_ELEM( *image_points, float, i, 1 );
    CV_MAT_ELEM( *object_points2, float, i, 0) = CV_MAT_ELEM( *object_points, float, i, 0 );
    CV_MAT_ELEM( *object_points2, float, i, 1) = CV_MAT_ELEM( *object_points, float, i, 1 );
    CV_MAT_ELEM( *object_points2, float, i, 2) = CV_MAT_ELEM( *object_points, float, i, 2 );


for( int i=0; i < successes; ++i )
    CV_MAT_ELEM( *point_counts2, int, i, 0 ) = CV_MAT_ELEM( *point_counts, int, i, 0 );

cvReleaseMat( &object_points );
cvReleaseMat( &image_points );
cvReleaseMat( &point_counts );

CV_MAT_ELEM( *intrinsic_matrix, float, 0, 0 ) = 1.0;
CV_MAT_ELEM( *intrinsic_matrix, float, 1, 1 ) = 1.0;

cvCalibrateCamera2( object_points2, image_points2, point_counts2, cvGetSize( image1 ),
    intrinsic_matrix, distortion_coeffs, NULL, NULL, CV_CALIB_FIX_ASPECT_RATIO );

cvSave( "Intrinsics.xml", intrinsic_matrix );
cvSave( "Distortion.xml", distortion_coeffs );

// Example of loading these matrices back in
CvMat *intrinsic = (CvMat*)cvLoad( "Intrinsics.xml" );
CvMat *distortion = (CvMat*)cvLoad( "Distortion.xml" );

IplImage* mapx = cvCreateImage( cvGetSize( image1 ), IPL_DEPTH_32F, 1 );
IplImage* mapy = cvCreateImage( cvGetSize( image1 ), IPL_DEPTH_32F, 1 );
cvInitUndistortMap( intrinsic, distortion, mapx, mapy );

cvNamedWindow( "Undistort" );

while( image1 )
    IplImage *t = cvCloneImage( image1 );
    cvShowImage( "Calibration", image ); // Show raw image
    cvRemap( t, image1, mapx, mapy ); // undistort image
    cvReleaseImage( &t );
    cvShowImage( "Undistort", image1 ); // Show corrected image

    


return 0;

我正在使用代码块 10.05 和 Opencv 2.3.0,Mingw GNU GCC 编译器。

【问题讨论】:

【参考方案1】:

卡西欧 Exilim EX-Z77 等数码相机通常会在相机内执行一定量的图像校正。

相信您从这台相机获得的图像已经过校正(关于镜头失真),但我找不到支持此声明的参考。

至于您使用的多张图片,实际上您只需要一张即可找到失真。有关使用 OpenCV 进行此过程的更多信息,请查看 this answer。

编辑

既然你提到了图像拼接,OpenCV started to support this feature on version 2.2:

OpenCV 2.2 已发布! 在此版本之后已经发布了很长的预告片:全景拼接

在这个主题上,这个interesting post 分享了一些source code。

【讨论】:

根据您尝试对参数执行的操作,是否已经进行了一些更正并不重要。您只需要考虑您正在确定整个相机的参数,而不仅仅是它的光学元件。自从我在大学接触 OpenCV 已经有一段时间了,但我总是使用不止一个棋盘图像进行校准。只是这样更准确,尤其是。没有完美的照明和东西。 感谢您的即时响应。实际上我也在考虑同样的事情。数码相机在进入市场之前已经过预校准。 .但问题是我正在做一个项目。它是图像拼接.. opencv 邮件列表中的一个示例要求校准相机以对图像执行成功的图像变形.. 希望你明白我的意思.. 如果捕捉到的图像失真,您只需要使用 OpenCV 校准相机。您的相机显然不是这种情况。但是发布该示例的人必须处理这个问题。您无需执行此步骤。 @mario .. 我使用了 16 张图像,用 May 相机获得。但是当我使用产生的失真和内在的图像去扭曲图像时......结果图像不成功,不仅不成功而且被破坏了..我会尝试不扭曲另一张图像以确保..谢谢。 顺便看看this thread用opencv拼接图片。

以上是关于使用数码相机进行相机校准的主要内容,如果未能解决你的问题,请参考以下文章

使用 MATLAB Camera Calibrator 进行单相机校准的问题

相机校准和重新映射是不是会产生针孔相机模型?

使用适用于 Matlab 与 OpenCV 的相机校准工具箱进行校准

使用 OpenCV 进行相机校准 - findChessboardCorners 返回 false

无目标非重叠立体相机校准

相机校准,焦距值似乎太大