1 /* This is sample from the OpenCV book. The copyright notice is below */
3 /* *************** License:**************************
5 Right to use this code in any way you want without warrenty, support or any guarentee of it working.
7 BOOK: It would be nice if you cited it:
8 Learning OpenCV: Computer Vision with the OpenCV Library
9 by Gary Bradski and Adrian Kaehler
10 Published by O'Reilly Media, October 3, 2008
13 http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134
14 Or: http://oreilly.com/catalog/9780596516130/
15 ISBN-10: 0596516134 or: ISBN-13: 978-0596516130
18 * The source code is on sourceforge at:
19 http://sourceforge.net/projects/opencvlibrary/
20 * The OpenCV wiki page (As of Oct 1, 2008 this is down for changing over servers, but should come back):
21 http://opencvlibrary.sourceforge.net/
22 * An active user group is at:
23 http://tech.groups.yahoo.com/group/OpenCV/
24 * The minutes of weekly OpenCV development meetings are at:
25 http://pr.willowgarage.com/wiki/OpenCV
26 ************************************************** */
40 // Given a list of chessboard images, the number of corners (nx, ny)
41 // on the chessboards, and a flag: useCalibrated for calibrated (0) or
42 // uncalibrated (1: use cvStereoCalibrate(), 2: compute fundamental
43 // matrix separately) stereo. Calibrate the cameras and display the
44 // rectified results along with the computed disparity images.
47 StereoCalib(const char* imageList, int useUncalibrated)
50 int displayCorners = 0;
51 int showUndistorted = 1;
52 bool isVerticalStereo = false;//OpenCV can handle left-right
53 //or up-down camera arrangements
54 const int maxScale = 1;
55 const float squareSize = 1.f; //Set this to your actual square size
56 FILE* f = fopen(imageList, "rt");
57 int i, j, lr, nframes, n, N = 0;
58 vector<string> imageNames[2];
59 vector<CvPoint3D32f> objectPoints;
60 vector<CvPoint2D32f> points[2];
62 vector<uchar> active[2];
63 vector<CvPoint2D32f> temp;
64 CvSize imageSize = {0,0};
65 // ARRAY AND VECTOR STORAGE:
66 double M1[3][3], M2[3][3], D1[5], D2[5];
67 double R[3][3], T[3], E[3][3], F[3][3];
68 CvMat _M1 = cvMat(3, 3, CV_64F, M1 );
69 CvMat _M2 = cvMat(3, 3, CV_64F, M2 );
70 CvMat _D1 = cvMat(1, 5, CV_64F, D1 );
71 CvMat _D2 = cvMat(1, 5, CV_64F, D2 );
72 CvMat _R = cvMat(3, 3, CV_64F, R );
73 CvMat _T = cvMat(3, 1, CV_64F, T );
74 CvMat _E = cvMat(3, 3, CV_64F, E );
75 CvMat _F = cvMat(3, 3, CV_64F, F );
79 cvNamedWindow( "corners", 1 );
80 // READ IN THE LIST OF CHESSBOARDS:
83 fprintf(stderr, "can not open file %s\n", imageList );
87 if( !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &nx, &ny) != 2 )
94 int count = 0, result=0;
96 vector<CvPoint2D32f>& pts = points[lr];
97 if( !fgets( buf, sizeof(buf)-3, f ))
99 size_t len = strlen(buf);
100 while( len > 0 && isspace(buf[len-1]))
104 IplImage* img = cvLoadImage( buf, 0 );
107 imageSize = cvGetSize(img);
108 imageNames[lr].push_back(buf);
109 //FIND CHESSBOARDS AND CORNERS THEREIN:
110 for( int s = 1; s <= maxScale; s++ )
112 IplImage* timg = img;
115 timg = cvCreateImage(cvSize(img->width*s,img->height*s),
116 img->depth, img->nChannels );
117 cvResize( img, timg, CV_INTER_CUBIC );
119 result = cvFindChessboardCorners( timg, cvSize(nx, ny),
121 CV_CALIB_CB_ADAPTIVE_THRESH |
122 CV_CALIB_CB_NORMALIZE_IMAGE);
124 cvReleaseImage( &timg );
125 if( result || s == maxScale )
126 for( j = 0; j < count; j++ )
137 IplImage* cimg = cvCreateImage( imageSize, 8, 3 );
138 cvCvtColor( img, cimg, CV_GRAY2BGR );
139 cvDrawChessboardCorners( cimg, cvSize(nx, ny), &temp[0],
141 cvShowImage( "corners", cimg );
142 cvReleaseImage( &cimg );
143 int c = cvWaitKey(1000);
144 if( c == 27 || c == 'q' || c == 'Q' ) //Allow ESC to quit
150 pts.resize(N + n, cvPoint2D32f(0,0));
151 active[lr].push_back((uchar)result);
152 //assert( result != 0 );
155 //Calibration will suffer without subpixel interpolation
156 cvFindCornerSubPix( img, &temp[0], count,
157 cvSize(11, 11), cvSize(-1,-1),
158 cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,
160 copy( temp.begin(), temp.end(), pts.begin() + N );
162 cvReleaseImage( &img );
166 // HARVEST CHESSBOARD 3D OBJECT POINT LIST:
167 nframes = active[0].size();//Number of good chessboads found
168 objectPoints.resize(nframes*n);
169 for( i = 0; i < ny; i++ )
170 for( j = 0; j < nx; j++ )
171 objectPoints[i*nx + j] =
172 cvPoint3D32f(i*squareSize, j*squareSize, 0);
173 for( i = 1; i < nframes; i++ )
174 copy( objectPoints.begin(), objectPoints.begin() + n,
175 objectPoints.begin() + i*n );
176 npoints.resize(nframes,n);
178 CvMat _objectPoints = cvMat(1, N, CV_32FC3, &objectPoints[0] );
179 CvMat _imagePoints1 = cvMat(1, N, CV_32FC2, &points[0][0] );
180 CvMat _imagePoints2 = cvMat(1, N, CV_32FC2, &points[1][0] );
181 CvMat _npoints = cvMat(1, npoints.size(), CV_32S, &npoints[0] );
187 // CALIBRATE THE STEREO CAMERAS
188 printf("Running stereo calibration ...");
190 cvStereoCalibrate( &_objectPoints, &_imagePoints1,
191 &_imagePoints2, &_npoints,
192 &_M1, &_D1, &_M2, &_D2,
193 imageSize, &_R, &_T, &_E, &_F,
194 cvTermCriteria(CV_TERMCRIT_ITER+
195 CV_TERMCRIT_EPS, 100, 1e-5),
196 CV_CALIB_FIX_ASPECT_RATIO +
197 CV_CALIB_ZERO_TANGENT_DIST +
198 CV_CALIB_SAME_FOCAL_LENGTH );
200 // CALIBRATION QUALITY CHECK
201 // because the output fundamental matrix implicitly
202 // includes all the output information,
203 // we can check the quality of calibration using the
204 // epipolar geometry constraint: m2^t*F*m1=0
205 vector<CvPoint3D32f> lines[2];
208 _imagePoints1 = cvMat(1, N, CV_32FC2, &points[0][0] );
209 _imagePoints2 = cvMat(1, N, CV_32FC2, &points[1][0] );
212 CvMat _L1 = cvMat(1, N, CV_32FC3, &lines[0][0]);
213 CvMat _L2 = cvMat(1, N, CV_32FC3, &lines[1][0]);
214 //Always work in undistorted space
215 cvUndistortPoints( &_imagePoints1, &_imagePoints1,
216 &_M1, &_D1, 0, &_M1 );
217 cvUndistortPoints( &_imagePoints2, &_imagePoints2,
218 &_M2, &_D2, 0, &_M2 );
219 cvComputeCorrespondEpilines( &_imagePoints1, 1, &_F, &_L1 );
220 cvComputeCorrespondEpilines( &_imagePoints2, 2, &_F, &_L2 );
222 for( i = 0; i < N; i++ )
224 double err = fabs(points[0][i].x*lines[1][i].x +
225 points[0][i].y*lines[1][i].y + lines[1][i].z)
226 + fabs(points[1][i].x*lines[0][i].x +
227 points[1][i].y*lines[0][i].y + lines[0][i].z);
230 printf( "avg err = %g\n", avgErr/(nframes*n) );
231 //COMPUTE AND DISPLAY RECTIFICATION
232 if( showUndistorted )
234 CvMat* mx1 = cvCreateMat( imageSize.height,
235 imageSize.width, CV_32F );
236 CvMat* my1 = cvCreateMat( imageSize.height,
237 imageSize.width, CV_32F );
238 CvMat* mx2 = cvCreateMat( imageSize.height,
240 imageSize.width, CV_32F );
241 CvMat* my2 = cvCreateMat( imageSize.height,
242 imageSize.width, CV_32F );
243 CvMat* img1r = cvCreateMat( imageSize.height,
244 imageSize.width, CV_8U );
245 CvMat* img2r = cvCreateMat( imageSize.height,
246 imageSize.width, CV_8U );
247 CvMat* disp = cvCreateMat( imageSize.height,
248 imageSize.width, CV_16S );
249 CvMat* vdisp = cvCreateMat( imageSize.height,
250 imageSize.width, CV_8U );
252 double R1[3][3], R2[3][3], P1[3][4], P2[3][4];
253 CvMat _R1 = cvMat(3, 3, CV_64F, R1);
254 CvMat _R2 = cvMat(3, 3, CV_64F, R2);
255 // IF BY CALIBRATED (BOUGUET'S METHOD)
256 if( useUncalibrated == 0 )
258 CvMat _P1 = cvMat(3, 4, CV_64F, P1);
259 CvMat _P2 = cvMat(3, 4, CV_64F, P2);
260 cvStereoRectify( &_M1, &_M2, &_D1, &_D2, imageSize,
262 &_R1, &_R2, &_P1, &_P2, 0,
263 0/*CV_CALIB_ZERO_DISPARITY*/ );
264 isVerticalStereo = fabs(P2[1][3]) > fabs(P2[0][3]);
265 //Precompute maps for cvRemap()
266 cvInitUndistortRectifyMap(&_M1,&_D1,&_R1,&_P1,mx1,my1);
267 cvInitUndistortRectifyMap(&_M2,&_D2,&_R2,&_P2,mx2,my2);
269 //OR ELSE HARTLEY'S METHOD
270 else if( useUncalibrated == 1 || useUncalibrated == 2 )
271 // use intrinsic parameters of each camera, but
272 // compute the rectification transformation directly
273 // from the fundamental matrix
275 double H1[3][3], H2[3][3], iM[3][3];
276 CvMat _H1 = cvMat(3, 3, CV_64F, H1);
277 CvMat _H2 = cvMat(3, 3, CV_64F, H2);
278 CvMat _iM = cvMat(3, 3, CV_64F, iM);
279 //Just to show you could have independently used F
280 if( useUncalibrated == 2 )
281 cvFindFundamentalMat( &_imagePoints1,
282 &_imagePoints2, &_F);
283 cvStereoRectifyUncalibrated( &_imagePoints1,
287 cvInvert(&_M1, &_iM);
288 cvMatMul(&_H1, &_M1, &_R1);
289 cvMatMul(&_iM, &_R1, &_R1);
290 cvInvert(&_M2, &_iM);
291 cvMatMul(&_H2, &_M2, &_R2);
292 cvMatMul(&_iM, &_R2, &_R2);
293 //Precompute map for cvRemap()
294 cvInitUndistortRectifyMap(&_M1,&_D1,&_R1,&_M1,mx1,my1);
296 cvInitUndistortRectifyMap(&_M2,&_D1,&_R2,&_M2,mx2,my2);
300 cvNamedWindow( "rectified", 1 );
301 // RECTIFY THE IMAGES AND FIND DISPARITY MAPS
302 if( !isVerticalStereo )
303 pair = cvCreateMat( imageSize.height, imageSize.width*2,
306 pair = cvCreateMat( imageSize.height*2, imageSize.width,
308 //Setup for finding stereo corrrespondences
309 CvStereoBMState *BMState = cvCreateStereoBMState();
310 assert(BMState != 0);
311 BMState->preFilterSize=33;
312 BMState->preFilterCap=33;
313 BMState->SADWindowSize=33;
314 if( useUncalibrated )
316 BMState->minDisparity=-64;
317 BMState->numberOfDisparities=128;
321 BMState->minDisparity=-32;
322 BMState->numberOfDisparities=192;
324 BMState->textureThreshold=10;
325 BMState->uniquenessRatio=15;
326 for( i = 0; i < nframes; i++ )
328 IplImage* img1=cvLoadImage(imageNames[0][i].c_str(),0);
329 IplImage* img2=cvLoadImage(imageNames[1][i].c_str(),0);
333 cvRemap( img1, img1r, mx1, my1 );
334 cvRemap( img2, img2r, mx2, my2 );
335 if( !isVerticalStereo || useUncalibrated != 0 )
337 // When the stereo camera is oriented vertically,
338 // useUncalibrated==0 does not transpose the
339 // image, so the epipolar lines in the rectified
340 // images are vertical. Stereo correspondence
341 // function does not support such a case.
342 cvFindStereoCorrespondenceBM( img1r, img2r, disp,
344 cvNormalize( disp, vdisp, 0, 256, CV_MINMAX );
345 cvNamedWindow( "disparity" );
346 cvShowImage( "disparity", vdisp );
348 if( !isVerticalStereo )
350 cvGetCols( pair, &part, 0, imageSize.width );
351 cvCvtColor( img1r, &part, CV_GRAY2BGR );
352 cvGetCols( pair, &part, imageSize.width,
354 cvCvtColor( img2r, &part, CV_GRAY2BGR );
355 for( j = 0; j < imageSize.height; j += 16 )
356 cvLine( pair, cvPoint(0,j),
357 cvPoint(imageSize.width*2,j),
362 cvGetRows( pair, &part, 0, imageSize.height );
363 cvCvtColor( img1r, &part, CV_GRAY2BGR );
364 cvGetRows( pair, &part, imageSize.height,
365 imageSize.height*2 );
366 cvCvtColor( img2r, &part, CV_GRAY2BGR );
367 for( j = 0; j < imageSize.width; j += 16 )
368 cvLine( pair, cvPoint(j,0),
369 cvPoint(j,imageSize.height*2),
372 cvShowImage( "rectified", pair );
373 if( cvWaitKey() == 27 )
376 cvReleaseImage( &img1 );
377 cvReleaseImage( &img2 );
379 cvReleaseStereoBMState(&BMState);
380 cvReleaseMat( &mx1 );
381 cvReleaseMat( &my1 );
382 cvReleaseMat( &mx2 );
383 cvReleaseMat( &my2 );
384 cvReleaseMat( &img1r );
385 cvReleaseMat( &img2r );
386 cvReleaseMat( &disp );
390 int main(int argc, char** argv)
392 StereoCalib(argc > 1 ? argv[1] : "stereo_calib.txt", 1);