在你看到這篇博文的時候,希望你能先看下我的上一篇博文,對相關的知識點有所了解后再看這篇博文
下面的幾個函數就是實現相機校正的關鍵
addChessboardPoints()
函數 - 用於讀入一系列的棋盤圖像並檢測角點;calibrate()
函數 - 用於進行相機校正,得到相機的參數矩陣和畸變系數;remap()
函數 - 用於根據相機校正結果修復圖像的畸變;//主要靠這個函數實現校正initUndistortRectifyMapaddPoints()
函數 -addChessboardPoints()
在檢測完角點后會調用這個函數。也可自己手動調用這個函數添加已知的角點位置和對應的空間坐標點。
main.c
1 #include <QCoreApplication> 2 #include <iostream> 3 #include <iomanip> 4 #include <vector> 5 #include <opencv2/core/core.hpp> 6 #include <opencv2/imgproc/imgproc.hpp> 7 #include <opencv2/highgui/highgui.hpp> 8 #include <opencv2/features2d/features2d.hpp> 9 10 #include "CameraCalibrator.h" 11 12 int main() 13 { 14 15 cv::namedWindow("Image"); 16 cv::Mat image; 17 std::vector<std::string> filelist; 18 19 // generate list of chessboard image filename 20 for (int i=1; i<=20; i++) { 21 22 std::stringstream str; 23 str << "/home/bi/pic/chessboards/chessboard" << std::setw(2) << std::setfill('0') << i << ".jpg"; 24 std::cout << str.str() << std::endl; 25 26 filelist.push_back(str.str()); 27 image= cv::imread(str.str(),0);//直接變為灰度圖 28 //cvtColor(image,image,CV_BGR2GRAY); 29 cv::imshow("Image",image); 30 31 cv::waitKey(1000); 32 } 33 34 // Create calibrator object 35 CameraCalibrator cameraCalibrator; 36 // add the corners from the chessboard 37 cv::Size boardSize(6,4); 38 cameraCalibrator.addChessboardPoints( 39 filelist, // filenames of chessboard image 40 boardSize); // size of chessboard 41 // calibrate the camera 42 // cameraCalibrator.setCalibrationFlag(true,true); 43 cameraCalibrator.calibrate(image.size()); 44 45 // Image Undistortion 46 image = cv::imread(filelist[6]); 47 cv::Mat uImage= cameraCalibrator.remap(image); 48 49 // display camera matrix 50 cv::Mat cameraMatrix= cameraCalibrator.getCameraMatrix(); 51 std::cout << " Camera intrinsic: " << cameraMatrix.rows << "x" << cameraMatrix.cols << std::endl; 52 std::cout << cameraMatrix.at<double>(0,0) << " " << cameraMatrix.at<double>(0,1) << " " << cameraMatrix.at<double>(0,2) << std::endl; 53 std::cout << cameraMatrix.at<double>(1,0) << " " << cameraMatrix.at<double>(1,1) << " " << cameraMatrix.at<double>(1,2) << std::endl; 54 std::cout << cameraMatrix.at<double>(2,0) << " " << cameraMatrix.at<double>(2,1) << " " << cameraMatrix.at<double>(2,2) << std::endl; 55 56 imshow("Original Image", image); 57 imshow("Undistorted Image", uImage); 58 59 cv::waitKey(); 60 return 0; 61 }
CameraCalibrator.h
addChessboardPoints()
函數 - 用於讀入一系列的棋盤圖像並檢測角點;calibrate()
函數 - 用於進行相機校正,得到相機的參數矩陣和畸變系數;remap()
函數 - 用於根據相機校正結果修復圖像的畸變;//主要靠這個函數實現校正initUndistortRectifyMapaddPoints()
函數 -addChessboardPoints()
在檢測完角點后會調用這個函數。也可自己手動調用這個函數添加已知的角點位置和對應的空間坐標點。

1 #ifndef CAMERACALIBRATOR_H 2 #define CAMERACALIBRATOR_H 3 4 #include <vector> 5 #include <iostream> 6 7 #include <opencv2/core/core.hpp> 8 #include "opencv2/imgproc/imgproc.hpp" 9 #include "opencv2/calib3d/calib3d.hpp" 10 #include <opencv2/highgui/highgui.hpp> 11 12 class CameraCalibrator { 13 14 // input points 15 std::vector<std::vector<cv::Point3f>> objectPoints; 16 std::vector<std::vector<cv::Point2f>> imagePoints; 17 // output Matrices 18 cv::Mat cameraMatrix; 19 cv::Mat distCoeffs; 20 // flag to specify how calibration is done 21 int flag; 22 // used in image undistortion 23 cv::Mat map1,map2; 24 bool mustInitUndistort; 25 26 public: 27 CameraCalibrator() : flag(0), mustInitUndistort(true) {}; 28 29 // Open the chessboard images and extract corner points 30 int addChessboardPoints(const std::vector<std::string>& filelist, cv::Size & boardSize); 31 // Add scene points and corresponding image points 32 void addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners); 33 // Calibrate the camera 34 double calibrate(cv::Size &imageSize); 35 // Set the calibration flag 36 void setCalibrationFlag(bool radial8CoeffEnabled=false, bool tangentialParamEnabled=false); 37 // Remove distortion in an image (after calibration) 38 cv::Mat CameraCalibrator::remap(const cv::Mat &image); 39 40 // Getters 41 cv::Mat getCameraMatrix() { return cameraMatrix; } 42 cv::Mat getDistCoeffs() { return distCoeffs; } 43 }; 44 45 #endif // CAMERACALIBRATOR_H
CameraCalibrator.cpp

1 #include "CameraCalibrator.h" 2 3 // Open chessboard images and extract corner points 4 int CameraCalibrator::addChessboardPoints( 5 const std::vector<std::string>& filelist, 6 cv::Size & boardSize) { 7 8 // the points on the chessboard 9 std::vector<cv::Point2f> imageCorners; 10 std::vector<cv::Point3f> objectCorners; 11 12 // 3D Scene Points: 13 // Initialize the chessboard corners 14 // in the chessboard reference frame 15 // The corners are at 3D location (X,Y,Z)= (i,j,0) 16 for (int i=0; i<boardSize.height; i++) { 17 for (int j=0; j<boardSize.width; j++) { 18 19 objectCorners.push_back(cv::Point3f(i, j, 0.0f)); 20 } 21 } 22 23 // 2D Image points: 24 cv::Mat image; // to contain chessboard image 25 int successes = 0; 26 // for all viewpoints 27 for (int i=0; i<filelist.size(); i++) { 28 29 // Open the image 30 image = cv::imread(filelist[i],0); 31 32 // Get the chessboard corners 33 bool found = cv::findChessboardCorners( 34 image, boardSize, imageCorners); 35 36 // Get subpixel accuracy on the corners 37 cv::cornerSubPix(image, imageCorners, 38 cv::Size(5,5), 39 cv::Size(-1,-1), 40 cv::TermCriteria(cv::TermCriteria::MAX_ITER + 41 cv::TermCriteria::EPS, 42 30, // max number of iterations 43 0.1)); // min accuracy 44 45 // If we have a good board, add it to our data 46 if (imageCorners.size() == boardSize.area()) { 47 48 // Add image and scene points from one view 49 addPoints(imageCorners, objectCorners); 50 successes++; 51 } 52 53 //Draw the corners 54 cv::drawChessboardCorners(image, boardSize, imageCorners, found); 55 cv::imshow("Corners on Chessboard", image); 56 cv::waitKey(100); 57 } 58 59 return successes; 60 } 61 62 // Add scene points and corresponding image points 63 void CameraCalibrator::addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners) { 64 65 // 2D image points from one view 66 imagePoints.push_back(imageCorners); 67 // corresponding 3D scene points 68 objectPoints.push_back(objectCorners); 69 } 70 71 // Calibrate the camera 72 // returns the re-projection error 73 double CameraCalibrator::calibrate(cv::Size &imageSize) 74 { 75 // undistorter must be reinitialized 76 mustInitUndistort= true; 77 78 //Output rotations and translations 79 std::vector<cv::Mat> rvecs, tvecs; 80 81 // start calibration 82 return 83 calibrateCamera(objectPoints, // the 3D points 84 imagePoints, // the image points 85 imageSize, // image size 86 cameraMatrix, // output camera matrix 87 distCoeffs, // output distortion matrix 88 rvecs, tvecs, // Rs, Ts 89 flag); // set options 90 // ,CV_CALIB_USE_INTRINSIC_GUESS); 91 92 } 93 94 // remove distortion in an image (after calibration) 95 cv::Mat CameraCalibrator::remap(const cv::Mat &image) { 96 97 cv::Mat undistorted; 98 99 if (mustInitUndistort) { // called once per calibration 100 101 cv::initUndistortRectifyMap( 102 cameraMatrix, // computed camera matrix 103 distCoeffs, // computed distortion matrix 104 cv::Mat(), // optional rectification (none) 105 cv::Mat(), // camera matrix to generate undistorted 106 cv::Size(640,480), 107 // image.size(), // size of undistorted 108 CV_32FC1, // type of output map 109 map1, map2); // the x and y mapping functions 110 111 mustInitUndistort= false; 112 } 113 114 // Apply mapping functions 115 cv::remap(image, undistorted, map1, map2, 116 cv::INTER_LINEAR); // interpolation type 117 118 return undistorted; 119 } 120 121 122 // Set the calibration options 123 // 8radialCoeffEnabled should be true if 8 radial coefficients are required (5 is default) 124 // tangentialParamEnabled should be true if tangeantial distortion is present 125 void CameraCalibrator::setCalibrationFlag(bool radial8CoeffEnabled, bool tangentialParamEnabled) { 126 127 // Set the flag used in cv::calibrateCamera() 128 flag = 0; 129 if (!tangentialParamEnabled) flag += CV_CALIB_ZERO_TANGENT_DIST; 130 if (radial8CoeffEnabled) flag += CV_CALIB_RATIONAL_MODEL; 131 }
findChessboardCorners
Finds the positions of internal corners of the chessboard.
C++: bool findChessboardCorners(InputArray image, Size patternSize, OutputArray corners, int
flags=CV_CALIB_CB_ADAPTIVE_THRESH+CV_CALIB_CB_NORMALIZE_IMAGE
)//如果找到了棋盤內部的角點,會返回true這個時候正好對應繪制角點的patternWasFound
Parameters
image – Source chessboard view. It must be an 8-bit grayscale or color image.
patternSize – Number of inner corners per a chessboard row and column ( patternSize
= cvSize(points_per_row,points_per_colum) = cvSize(columns,rows) ).
corners – Output array of detected corners.
flags – Various operation flags that can be zero or a combination of the following values:
– CV_CALIB_CB_ADAPTIVE_THRESH Use adaptive thresholding to convert the image
to black and white, rather than a fixed threshold level (computed from the average
image brightness).
– CV_CALIB_CB_NORMALIZE_IMAGE Normalize the image gamma with
equalizeHist() before applying fixed or adaptive thresholding.
– CV_CALIB_CB_FILTER_QUADS Use additional criteria (like contour area, perimeter,
square-like shape) to filter out false quads extracted at the contour retrieval stage.
– CALIB_CB_FAST_CHECK Run a fast check on the image that looks for chessboard
corners, and shortcut the call if none is found. This can drastically speed up the call in
the degenerate condition when no chessboard is observed.
drawChessboardCorners
Renders the detected chessboard corners.
C++: void drawChessboardCorners(InputOutputArray image, Size patternSize, InputArray corners, bool
patternWasFound)
Python: cv2.drawChessboardCorners(image, patternSize, corners, patternWasFound)! None
C: void cvDrawChessboardCorners(CvArr* image, CvSize patternSize, CvPoint2D32f* corners, int
count, int patternWasFound)
Python: cv.DrawChessboardCorners(image, patternSize, corners, patternWasFound)! None
Parameters
image – Destination image. It must be an 8-bit color image.
patternSize – Number of inner corners per a chessboard row and column (patternSize =
cv::Size(points_per_row,points_per_column)).//注意這里表示的是棋盤的大小,別弄錯了
corners – Array of detected corners, the output of findChessboardCorners.
patternWasFound – Parameter indicating whether the complete board was found or not.
The return value of findChessboardCorners() should be passed here.
The function draws individual chessboard corners detected either as red circles if the board was not found, or as
colored corners connected with lines if the board was found.
initUndistortRectifyMap
Computes the undistortion and rectification transformation map.
C++: void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R,
InputArray newCameraMatrix, Size size, int m1type, OutputArray
map1, OutputArray map2)
Parameters
cameraMatrix – Input camera matrix A =
cameraMatrix //不用解釋了吧 相機的內參矩陣
distCoeffs畸變矩陣 – Input vector of distortion coefficients (k1; k2; p1; p2[; k3[; k4; k5; k6]]) of 4,
5, or 8 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed.
R代表的是旋轉矩陣
R – Optional rectification transformation in the object space (3x3 matrix). R1 or R2 , computed
by stereoRectify() can be passed here. If the matrix is empty, the identity transformation
is assumed. In cvInitUndistortMap R assumed to be an identity matrix.
newCameraMatrix – New camera matrix A0 =
size – Undistorted image size.
m1type – Type of the first output map that can be CV_32FC1 or CV_16SC2 . See
convertMaps() for details.
map1 – The first output map.//即是 u
map2 – The second output map.//即是 v


