标签:
畸变矫正是上一篇博文的遗留问题,当畸变系数和内外参数矩阵标定完成后,就应该进行畸变的矫正,以达到消除畸变的目的,此其一。
在该系列第一部分的博文中介绍的立体成像原理中提到,要通过两幅图像估计物点的深度信息,就必须在两幅图像中准确的匹配到同一物点,这样才能根据该物点在两幅图像中的位置关系,计算物体深度。为了降低匹配的计算量,两个摄像头的成像平面应处于同一平面。但是,单单依靠严格的摆放摄像头来达到这个目的显然有些困难。立体校正就是利用几何图形变换(Geometric Image Transformation)关系,使得原先不满足上述位置关系的两幅图像满足该条件,此其二。
畸变矫正的方法就是用上一篇博文给出的公式对像素位置进行重新映射。这里重新写出重新映射的公式。
先矫正径向畸变,


再矫正切向畸变,


立体矫正是能够有效降低立体匹配的计算量,立体匹配的具体作用见下图,
立体矫正前,
立体矫正后,

立体矫正的算法原理没有详细了解,此处从略。
undistort() 是独立的一个畸变矫正函数,一次性可以完成映射矩阵的求解和重新映射。下面我们还会看到把这两步分开来做的函数。
调用方法,
stereoCalibrate() 是用来标定一个立体摄像头的,也就是同时标定两个摄像头。标定的结果除了能够求出两个摄像头的内外参数矩阵,跟能够得出两个摄像头的位置关系$$$R,T$$$。
调用方法,
double stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1,
InputArrayOfArrays imagePoints2, InputOutputArray cameraMatrix1,InputOutputArray distCoeffs1,
InputOutputArray cameraMatrix2, InputOutputArray distCoeffs2, Size imageSize, OutputArray R, OutputArray T, OutputArray E, OutputArray F, TermCriteria criteria= TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6), int flags=CALIB_FIX_INTRINSIC )
CV_CALIB_USE_INTRINSIC_GUESS , CV_CALIB_FIX_ASPECT_RATIO ,CV_CALIB_FIX_INTRINSIC , or CV_CALIB_FIX_FOCAL_LENGTH其中的一个或多个标志被设置,该摄像机矩阵的一些或全部参数需要被初始化flag-
stereoRectify() 的作用是为每个摄像头计算立体校正的映射矩阵。所以其运行结果并不是直接将图片进行立体矫正,而是得出进行立体矫正所需要的映射矩阵。
调用方法,
void stereoRectify(InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2,InputArray distCoeffs2, Size imageSize, InputArray R, InputArray T,OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY, double alpha=-1,
Size newImageSize=Size(), Rect* validPixROI1=0, Rect* validPixROI2=0 )
Rect型数据。其内部的所有像素都有效Rect型数据。其内部的所有像素都有效该函数功能是计算畸变矫正和立体校正的映射变换。
调用方法,
void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R,InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2)
调用方法,
void remap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation,int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
CV_16SC2 ,CV_32FC1 , 或 CV_32FC2类型CV_16UC1 , CV_32FC1类型。或者当map1是点(x,y)时,map2为空。
1 int main() 2 { 3 //initialize some parameters 4 bool okcalib = false; 5 Mat intrMatFirst, intrMatSec, distCoeffsFirst, distCoffesSec; 6 Mat R, T, E, F, RFirst, RSec, PFirst, PSec, Q; 7 vector<vector<Point2f>> imagePointsFirst, imagePointsSec; 8 vector<vector<Point3f>> ObjectPoints(1); 9 Rect validRoi[2]; 10 Size imageSize; 11 int cameraIdFirst = 0, cameraIdSec = 1; 12 double rms = 0; 13 14 //get pictures and calibrate 15 vector<string> imageList; 16 string filename = "stereo_calib.xml"; 17 bool okread = readStringList(filename, imageList); 18 if (!okread || imageList.empty()) 19 { 20 cout << "can not open " << filename << " or the string list is empty" << endl; 21 return false; 22 } 23 if (imageList.size() % 2 != 0) 24 { 25 cout << "Error: the image list contains odd (non-even) number of elements\n"; 26 return false; 27 } 28 29 //calibrate 30 cout << "calibrate left camera..." << endl; 31 okcalib = calibrate(intrMatFirst, distCoeffsFirst, imagePointsFirst, ObjectPoints, 32 imageSize, cameraIdFirst, imageList); 33 34 if (!okcalib) 35 { 36 cout << "fail to calibrate left camera" << endl; 37 return -1; 38 } 39 else 40 { 41 cout << "calibrate the right camera..." << endl; 42 } 43 44 okcalib = calibrate(intrMatSec, distCoffesSec, imagePointsSec, ObjectPoints, 45 imageSize, cameraIdSec, imageList); 46 47 if (!okcalib) 48 { 49 cout << "fail to calibrate the right camera" << endl; 50 return -1; 51 } 52 destroyAllWindows(); 53 54 //estimate position and orientation 55 cout << "estimate position and orientation of the second camera" << endl 56 << "relative to the first camera..." << endl; 57 rms = stereoCalibrate(ObjectPoints, imagePointsFirst, imagePointsSec, 58 intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec, 59 imageSize, R, T, E, F, CV_CALIB_FIX_INTRINSIC, 60 TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 1e-6)); 61 cout << "done with RMS error=" << rms << endl; 62 63 //stereo rectify 64 cout << "stereo rectify..." << endl; 65 stereoRectify(intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec, imageSize, R, T, RFirst, 66 RSec, PFirst, PSec, Q, 0, 1, imageSize, &validRoi[0], &validRoi[1]); 67 68 //read pictures for 3d-reconstruction 69 namedWindow("canvas", 1); 70 cout << "read the picture for 3d-reconstruction..."; 71 Mat canvas(imageSize.height, imageSize.width * 2, CV_8UC3), viewLeft, viewRight; 72 Mat canLeft = canvas(Rect(0, 0, imageSize.width, imageSize.height)); 73 Mat canRight = canvas(Rect(imageSize.width, 0, imageSize.width, imageSize.height)); 74 viewLeft = imread(imageList[cameraIdFirst], 1); 75 viewRight = imread(imageList[cameraIdSec], 1); 76 viewLeft.copyTo(canLeft); 77 viewRight.copyTo(canRight); 78 cout << "done" << endl; 79 imshow("canvas", canvas); 80 waitKey(50); 81 82 //stereoRectify 83 Mat rmapFirst[2], rmapSec[2], rviewFirst, rviewSec; 84 initUndistortRectifyMap(intrMatFirst, distCoeffsFirst, RFirst, PFirst, 85 imageSize, CV_16SC2, rmapFirst[0], rmapFirst[1]); 86 initUndistortRectifyMap(intrMatSec, distCoffesSec, RSec, PSec, 87 imageSize, CV_16SC2, rmapSec[0], rmapSec[1]); 88 remap(viewLeft, rviewFirst, rmapFirst[0], rmapFirst[1], INTER_LINEAR); 89 remap(viewRight, rviewSec, rmapSec[0], rmapSec[1], INTER_LINEAR); 90 rviewFirst.copyTo(canLeft); 91 rviewSec.copyTo(canRight); 92 93 rectangle(canLeft, validRoi[0], Scalar(255, 0, 0), 3, 8); 94 rectangle(canRight, validRoi[1], Scalar(255, 0, 0), 3, 8); 95 for (int j = 0; j <= canvas.rows; j += 16) 96 line(canvas, Point(0, j), Point(canvas.cols, j), Scalar(0, 255, 0), 1, 8); 97 cout << "stereo rectify done" << endl; 98 imshow("canvas", canvas); 99 waitKey(50);
子函数calibrate()和calcChessboardCorners()分别是用来表达相机和计算objectPoints的。函数体如下,
1 bool calibrate(Mat& intrMat, Mat& distCoeffs, vector<vector<Point2f>>& imagePoints, 2 vector<vector<Point3f>>& ObjectPoints, Size& imageSize,const int cameraId , 3 vector<string> imageList) 4 { 5 int w = 6; 6 int h = 9; 7 double rms = 0; 8 9 Size boardSize; 10 boardSize.width = w; 11 boardSize.height = h; 12 vector<Point2f> pointBuf; 13 float squareSize = 1.f; 14 vector<Mat> rvecs, tvecs; 15 bool ok = false; 16 17 int nImages = (int)imageList.size() / 2; 18 namedWindow("View", 1); 19 for (int i = 0; i<nImages ; i++) 20 { 21 Mat view, viewGray; 22 view = imread(imageList[i*2+cameraId], 1); 23 imageSize = view.size(); 24 cvtColor(view, viewGray, COLOR_BGR2GRAY); 25 26 bool found = findChessboardCorners(view, boardSize, pointBuf, 27 CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE); 28 29 if (found) 30 { 31 cornerSubPix(viewGray, pointBuf, Size(11, 11), 32 Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); 33 drawChessboardCorners(view, boardSize, Mat(pointBuf), found); 34 bitwise_not(view, view); 35 imagePoints.push_back(pointBuf); 36 cout << ‘.‘; 37 } 38 imshow("View", view); 39 waitKey(50); 40 } 41 //calculate chessboardCorners 42 calcChessboardCorners(boardSize, squareSize, ObjectPoints[0]); 43 ObjectPoints.resize(imagePoints.size(), ObjectPoints[0]); 44 45 rms = calibrateCamera(ObjectPoints, imagePoints, imageSize, intrMat, distCoeffs, 46 rvecs, tvecs); 47 ok = checkRange(intrMat) && checkRange(distCoeffs); 48 49 if (ok) 50 { 51 cout << "done with RMS error=" << rms << endl; 52 return true; 53 } 54 else 55 return false; 56 }
1 static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners) 2 { 3 corners.resize(0); 4 for (int i = 0; i < boardSize.height; i++) //height和width位置不能颠倒 5 for (int j = 0; j < boardSize.width; j++) 6 { 7 corners.push_back(Point3f(j*squareSize, i*squareSize, 0)); 8 } 9 }

标签:
原文地址:http://www.cnblogs.com/german-iris/p/5199203.html