OpenCV Tutorial 10 - Chapter 11

 ( 由于收到附件大小的限制,此篇的图片无法上传,请大家见谅,可登陆原网站查看:http://dasl.mem.drexel.edu/~noahKuntz/openCVTut10.html)

Author: Noah Kuntz (2009)
Contact: [email protected]

Keywords: OpenCV, computer vision, calibration, camera parameters

My Vision Tutorials Index

This tutorial assumes the reader:
(1) Has a basic knowledge of Visual C++
(2) Has some familiarity with computer vision concepts
(3) Has read the previous tutorials in this series

The rest of the tutorial is presented as follows:

  • Step 1: Camera Calibration
  • Final Words

Important Note!

More information on the topics of these tutorials can be found in this book:Learning OpenCV: Computer Vision with the OpenCV Library

Step 1: Camera Calibration(摄像机标定)


Corner Finding for Calibration(找到用于校准的角点)

 


Image Undistortion After Calibration(校准后的图像Undistortion)


Camera calibration is important for any image processing to be a highly accurate representation of the real world(摄像机标定对于任何图像处理都是非常重要的,是对现实世界的高度准确地表述). The basics of perspective geometry are covered in the book(在书中,涵盖了透视几何的基础知识). The concern of this tutorial is simply how to extract the relevant camera parameters from a sequence of images(本教程的关注仅仅是如何从一个摄像机图像序列中提取相关的参数). For this example you will need to print out this image as a full page(在这个例子中,你将需要将这个图片作为一整页打印出):


Example Checkerboard(棋盘法)


This code uses cvFindChessboardCorners to find the corners, and then draw them on the current image withcvDrawChessboardCorners(此代码使用cvFindChessboardCorners来找到角点,然后用cvDrawChessboardCorners把它们绘制在当前的图像上). If all the corners are successfully identified, the corners are added to image_points and object_points for later use in calibration(如果所有的角点都成功地确定,则角点被添加到image_points和object_points上为日后的校准使用). After all the different orientations are successfully stored (orientations are arbitrary but should have a variety of views to solve for the camera parameters), thencvCalibrateCamera2 is used to get the camera parameters(毕竟不同的方向被成功地存储(方向是任意的,但是应该有不同观点去解决摄像机的参数),然后用cvCalibrateCamera2来获取摄像机参数). Lastly,cvInitUndistoryMap is used with cvRemap to unwarp the camera images(最后,cvInitUndistoryMap是用于cvRemap到unwarp相机的图像). So for the user, simply print out the checkerboard, then point the camera at it in various orientations as the program marks the points in each one (it is successful if a variety of colors are used, all red or nothing is a failure)(因此,对于用户来说,只需打印出棋盘,然后对准它在各个方向相机,该方案标志着在每一个点(它是成功的,如果有多种颜色的使用,全是红色或没有东西则是失败的)). The intrinsics of the camera and the distortion are stored in xml files to use in other programs(摄像机的内建和失真被存储在XML文件中以便其他程序的使用). Here is the code(以下是代码):


 

int n_boards = 0;

const int board_dt = 20;

int board_w;

int board_h;

 

int _tmain(int argc, _TCHAR* argv[])

{

        board_w = 5; // Board width in squares

        board_h = 8; // Board height

        n_boards = 8; // Number of boards

        int board_n = board_w * board_h;

        CvSize board_sz = cvSize( board_w, board_h );

        CvCapture* capture = cvCreateCameraCapture( 0 );

        assert( capture );

 

        cvNamedWindow( "Calibration" );

        // Allocate Sotrage

        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, frame = 0;

 

        IplImage *image = cvQueryFrame( capture );

        IplImage *gray_image = cvCreateImage( cvGetSize( image ), 8, 1 );

 

        // Capture Corner views loop until we've got n_boards

        // succesful captures (all corners on the board are found)

 

        while( successes < n_boards ){

               // Skp every board_dt frames to allow user to move chessboard

               if( frame++ % board_dt == 0 ){

                       // Find chessboard corners:

                       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++;

                       }

               }

 

               // Handle pause/unpause and ESC

               int c = cvWaitKey( 15 );

               if( c == 'p' ){

                       c = 0;

                       while( c != 'p' && c != 27 ){

                               c = cvWaitKey( 250 );

                       }

               }

               if( c == 27 )

                       return 0;

               image = cvQueryFrame( capture ); // Get next image

        } // End collection while loop

 

        // Allocate matrices according to how many chessboards found

        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 );

 

        // At this point we have all the chessboard corners we need

        // Initiliazie the intrinsic matrix such that the two focal lengths

        // have a ratio of 1.0

 

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

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

 

        // Calibrate the camera

        cvCalibrateCamera2( object_points2, image_points2, point_counts2, cvGetSize( image ),

               intrinsic_matrix, distortion_coeffs, NULL, NULL, CV_CALIB_FIX_ASPECT_RATIO );

 

        // Save the intrinsics and distortions

        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" );

 

        // Build the undistort map that we will use for all subsequent frames

        IplImage* mapx = cvCreateImage( cvGetSize( image ), IPL_DEPTH_32F, 1 );

        IplImage* mapy = cvCreateImage( cvGetSize( image ), IPL_DEPTH_32F, 1 );

        cvInitUndistortMap( intrinsic, distortion, mapx, mapy );

 

        // Run the camera to the screen, now showing the raw and undistorted image

        cvNamedWindow( "Undistort" );

 

        while( image ){

               IplImage *t = cvCloneImage( image );

               cvShowImage( "Calibration", image ); // Show raw image

               cvRemap( t, image, mapx, mapy ); // undistort image

               cvReleaseImage( &t );

               cvShowImage( "Undistort", image ); // Show corrected image

 

               // Handle pause/unpause and esc

               int c = cvWaitKey( 15 );

               if( c == 'p' ){

                       c = 0;

                       while( c != 'p' && c != 27 ){

                               c = cvWaitKey( 250 );

                       }

               }

               if( c == 27 )

                       break;

               image = cvQueryFrame( capture );

        }

 

        return 0;

}

 


 

Final Words(结束语)

This tutorial's objective was to show how to extract camera parameters using calibration routines(本教程的目标是展示如何提取摄像机参数来校准程序).

Click here to email me.
Click here to return to my Tutorials page.

 

你可能感兴趣的:(计算机视觉)