Update the trunk to the OpenCV's CVS (2008-07-14)
[opencv] / tests / cv / src / acameracalibration.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "cvtest.h"
43
44 #if 0
45 class CV_ProjectPointsTest : public CvArrTest
46 {
47 public:
48     CV_ProjectPointsTest();
49
50 protected:
51     int read_params( CvFileStorage* fs );
52     void fill_array( int test_case_idx, int i, int j, CvMat* arr );
53     int prepare_test_case( int test_case_idx );
54     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
55     double get_success_error_level( int test_case_idx, int i, int j );
56     void run_func();
57     void prepare_to_validation( int );
58
59     bool calc_jacobians;
60 };
61
62
63 CV_ProjectPointsTest::CV_ProjectPointsTest()
64     : CvArrTest( "3d-ProjectPoints", "cvProjectPoints2", "" )
65 {
66     test_array[INPUT].push(NULL);  // rotation vector
67     test_array[OUTPUT].push(NULL); // rotation matrix 
68     test_array[OUTPUT].push(NULL); // jacobian (J)
69     test_array[OUTPUT].push(NULL); // rotation vector (backward transform result)
70     test_array[OUTPUT].push(NULL); // inverse transform jacobian (J1)
71     test_array[OUTPUT].push(NULL); // J*J1 (or J1*J) == I(3x3)
72     test_array[REF_OUTPUT].push(NULL);
73     test_array[REF_OUTPUT].push(NULL);
74     test_array[REF_OUTPUT].push(NULL);
75     test_array[REF_OUTPUT].push(NULL);
76     test_array[REF_OUTPUT].push(NULL);
77
78     element_wise_relative_error = false;
79     calc_jacobians = false;
80
81     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
82     default_timing_param_names = 0;
83 }
84
85
86 int CV_ProjectPointsTest::read_params( CvFileStorage* fs )
87 {
88     int code = CvArrTest::read_params( fs );
89     return code;
90 }
91
92
93 void CV_ProjectPointsTest::get_test_array_types_and_sizes(
94     int /*test_case_idx*/, CvSize** sizes, int** types )
95 {
96     CvRNG* rng = ts->get_rng();
97     int depth = cvTsRandInt(rng) % 2 == 0 ? CV_32F : CV_64F;
98     int i, code;
99     
100     code = cvTsRandInt(rng) % 3;
101     types[INPUT][0] = CV_MAKETYPE(depth, 1);
102
103     if( code == 0 )
104     {
105         sizes[INPUT][0] = cvSize(1,1);
106         types[INPUT][0] = CV_MAKETYPE(depth, 3);
107     }
108     else if( code == 1 )
109         sizes[INPUT][0] = cvSize(3,1);
110     else
111         sizes[INPUT][0] = cvSize(1,3);
112
113     sizes[OUTPUT][0] = cvSize(3, 3);
114     types[OUTPUT][0] = CV_MAKETYPE(depth, 1);
115
116     types[OUTPUT][1] = CV_MAKETYPE(depth, 1);
117
118     if( cvTsRandInt(rng) % 2 )
119         sizes[OUTPUT][1] = cvSize(3,9);
120     else
121         sizes[OUTPUT][1] = cvSize(9,3);
122
123     types[OUTPUT][2] = types[INPUT][0];
124     sizes[OUTPUT][2] = sizes[INPUT][0];
125
126     types[OUTPUT][3] = types[OUTPUT][1];
127     sizes[OUTPUT][3] = cvSize(sizes[OUTPUT][1].height, sizes[OUTPUT][1].width);
128
129     types[OUTPUT][4] = types[OUTPUT][1];
130     sizes[OUTPUT][4] = cvSize(3,3);
131
132     calc_jacobians = 1;//cvTsRandInt(rng) % 3 != 0;
133     if( !calc_jacobians )
134         sizes[OUTPUT][1] = sizes[OUTPUT][3] = sizes[OUTPUT][4] = cvSize(0,0);
135
136     for( i = 0; i < 5; i++ )
137     {
138         types[REF_OUTPUT][i] = types[OUTPUT][i];
139         sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
140     }
141 }
142
143
144 double CV_ProjectPointsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
145 {
146     return j == 4 ? 1e-2 : 1e-2;
147 }
148
149
150 void CV_ProjectPointsTest::fill_array( int /*test_case_idx*/, int /*i*/, int /*j*/, CvMat* arr )
151 {
152     double r[3], theta0, theta1, f;
153     CvMat _r = cvMat( arr->rows, arr->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(arr->type)), r );
154     CvRNG* rng = ts->get_rng();
155
156     r[0] = cvTsRandReal(rng)*CV_PI*2;
157     r[1] = cvTsRandReal(rng)*CV_PI*2;
158     r[2] = cvTsRandReal(rng)*CV_PI*2;
159
160     theta0 = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
161     theta1 = fmod(theta0, CV_PI*2);
162
163     if( theta1 > CV_PI )
164         theta1 = -(CV_PI*2 - theta1);
165
166     f = theta1/(theta0 ? theta0 : 1);
167     r[0] *= f;
168     r[1] *= f;
169     r[2] *= f;
170
171     cvTsConvert( &_r, arr );
172 }
173
174
175 int CV_ProjectPointsTest::prepare_test_case( int test_case_idx )
176 {
177     int code = CvArrTest::prepare_test_case( test_case_idx );
178     return code;
179 }
180
181
182 void CV_ProjectPointsTest::run_func()
183 {
184     CvMat *v2m_jac = 0, *m2v_jac = 0;
185     if( calc_jacobians )
186     {
187         v2m_jac = &test_mat[OUTPUT][1];
188         m2v_jac = &test_mat[OUTPUT][3];
189     }
190
191     cvProjectPoints2( &test_mat[INPUT][0], &test_mat[OUTPUT][0], v2m_jac );
192     cvProjectPoints2( &test_mat[OUTPUT][0], &test_mat[OUTPUT][2], m2v_jac );
193 }
194
195
196 void CV_ProjectPointsTest::prepare_to_validation( int /*test_case_idx*/ )
197 {
198     const CvMat* vec = &test_mat[INPUT][0];
199     CvMat* m = &test_mat[REF_OUTPUT][0];
200     CvMat* vec2 = &test_mat[REF_OUTPUT][2];
201     CvMat* v2m_jac = 0, *m2v_jac = 0;
202     double theta0, theta1;
203
204     if( calc_jacobians )
205     {
206         v2m_jac = &test_mat[REF_OUTPUT][1];
207         m2v_jac = &test_mat[REF_OUTPUT][3];
208     }
209
210
211     cvTsProjectPoints( vec, m, v2m_jac );
212     cvTsProjectPoints( m, vec2, m2v_jac );
213     cvTsCopy( vec, vec2 );
214
215     theta0 = cvNorm( vec2, 0, CV_L2 );
216     theta1 = fmod( theta0, CV_PI*2 );
217
218     if( theta1 > CV_PI )
219         theta1 = -(CV_PI*2 - theta1);
220     cvScale( vec2, vec2, theta1/(theta0 ? theta0 : 1) );
221     
222     if( calc_jacobians )
223     {
224         //cvInvert( v2m_jac, m2v_jac, CV_SVD );
225         if( cvNorm(&test_mat[OUTPUT][3],0,CV_C) < 1000 )
226         {
227             cvTsGEMM( &test_mat[OUTPUT][1], &test_mat[OUTPUT][3],
228                       1, 0, 0, &test_mat[OUTPUT][4],
229                       v2m_jac->rows == 3 ? 0 : CV_GEMM_A_T + CV_GEMM_B_T );
230         }
231         else
232         {
233             cvTsSetIdentity( &test_mat[OUTPUT][4], cvScalarAll(1.) );
234             cvTsCopy( &test_mat[REF_OUTPUT][2], &test_mat[OUTPUT][2] );
235         }
236         cvTsSetIdentity( &test_mat[REF_OUTPUT][4], cvScalarAll(1.) );
237     }
238 }
239
240
241 CV_ProjectPointsTest ProjectPoints_test;
242
243 #endif
244
245
246
247 class CV_CameraCalibrationTest : public CvTest
248 {
249 public:
250     CV_CameraCalibrationTest();
251     ~CV_CameraCalibrationTest();
252     void clear();
253     //int write_default_params(CvFileStorage* fs);
254
255 protected:
256     //int read_params( CvFileStorage* fs );
257     int compare(double* val, double* ref_val, int len,
258                 double eps, const char* param_name);
259
260     void run(int);
261 };
262
263
264 CV_CameraCalibrationTest::CV_CameraCalibrationTest():
265     CvTest( "calibratecamera", "cvCalibrateCamera2" )
266 {
267     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
268 }
269
270
271 CV_CameraCalibrationTest::~CV_CameraCalibrationTest()
272 {
273     clear();
274 }
275
276
277 void CV_CameraCalibrationTest::clear()
278 {
279     CvTest::clear();
280 }
281
282
283 int CV_CameraCalibrationTest::compare(double* val, double* ref_val, int len,
284                                       double eps, const char* param_name )
285 {
286     return cvTsCmpEps2_64f( ts, val, ref_val, len, eps, param_name );
287 }
288
289 void CV_CameraCalibrationTest::run( int start_from )
290 {
291     int code = CvTS::OK;
292     char            filepath[100];
293     char            filename[100];
294     
295     CvSize          imageSize;
296     CvSize          etalonSize;
297     int             numImages;
298     
299     CvPoint2D64d*   imagePoints;
300     CvPoint3D64d*   objectPoints;
301     CvPoint2D64d*   reprojectPoints;
302
303     CvVect64d       transVects;
304     CvMatr64d       rotMatrs;
305
306     CvVect64d       goodTransVects;
307     CvMatr64d       goodRotMatrs;
308
309     double          cameraMatrix[3*3];
310     double          distortion[4];
311
312     double          goodDistortion[4];
313
314     int*            numbers;
315     FILE*           file = 0;
316     FILE*           datafile = 0; 
317     int             i,j;
318     int             currImage;
319     int             currPoint;
320
321     int             calibFlags;
322     char            i_dat_file[100];
323     int             numPoints;
324     int numTests;
325     int currTest;
326
327     imagePoints     = 0;
328     objectPoints    = 0;
329     reprojectPoints = 0;
330     numbers         = 0;
331
332     transVects      = 0;
333     rotMatrs        = 0;
334     goodTransVects  = 0;
335     goodRotMatrs    = 0;
336     int progress = 0;
337     
338     sprintf( filepath, "%scameracalibration/", ts->get_data_path() );
339     sprintf( filename, "%sdatafiles.txt", filepath );
340     datafile = fopen( filename, "r" );
341     if( datafile == 0 ) 
342     {
343         ts->printf( CvTS::LOG, "Could not open file with list of test files: %s\n", filename );
344         code = CvTS::FAIL_MISSING_TEST_DATA;
345         goto _exit_;
346     }
347
348     fscanf(datafile,"%d",&numTests);
349
350     for( currTest = start_from; currTest < numTests; currTest++ )
351     {
352         fscanf(datafile,"%s",i_dat_file);
353         sprintf(filename, "%s%s", filepath, i_dat_file);
354         file = fopen(filename,"r");
355
356         ts->update_context( this, currTest, true );
357
358         if( file == 0 )
359         {
360             ts->printf( CvTS::LOG,
361                 "Can't open current test file: %s\n",filename);
362             if( numTests == 1 )
363             {
364                 code = CvTS::FAIL_MISSING_TEST_DATA;
365                 goto _exit_;
366             }
367             continue; // if there is more than one test, just skip the test
368         }
369
370         fscanf(file,"%d %d\n",&(imageSize.width),&(imageSize.height));
371         if( imageSize.width <= 0 || imageSize.height <= 0 )
372         {
373             ts->printf( CvTS::LOG, "Image size in test file is incorrect\n" );
374             code = CvTS::FAIL_INVALID_TEST_DATA;
375             goto _exit_;
376         }
377
378         /* Read etalon size */
379         fscanf(file,"%d %d\n",&(etalonSize.width),&(etalonSize.height));
380         if( etalonSize.width <= 0 || etalonSize.height <= 0 )
381         {
382             ts->printf( CvTS::LOG, "Pattern size in test file is incorrect\n" );
383             code = CvTS::FAIL_INVALID_TEST_DATA;
384             goto _exit_;
385         }
386
387         numPoints = etalonSize.width * etalonSize.height;
388
389         /* Read number of images */
390         fscanf(file,"%d\n",&numImages);
391         if( numImages <=0 )
392         {
393             ts->printf( CvTS::LOG, "Number of images in test file is incorrect\n");
394             code = CvTS::FAIL_INVALID_TEST_DATA;
395             goto _exit_;
396         }
397
398         /* Need to allocate memory */
399         imagePoints     = (CvPoint2D64d*)cvAlloc( numPoints *
400                                                     numImages * sizeof(CvPoint2D64d));
401         
402         objectPoints    = (CvPoint3D64d*)cvAlloc( numPoints *
403                                                     numImages * sizeof(CvPoint3D64d));
404
405         reprojectPoints = (CvPoint2D64d*)cvAlloc( numPoints *
406                                                     numImages * sizeof(CvPoint2D64d));
407
408         /* Alloc memory for numbers */
409         numbers = (int*)cvAlloc( numImages * sizeof(int));
410
411         /* Fill it by numbers of points of each image*/
412         for( currImage = 0; currImage < numImages; currImage++ )
413         {
414             numbers[currImage] = etalonSize.width * etalonSize.height;
415         }
416
417         /* Allocate memory for translate vectors and rotmatrixs*/
418         transVects     = (CvVect64d)cvAlloc(3 * 1 * numImages * sizeof(double));
419         rotMatrs       = (CvMatr64d)cvAlloc(3 * 3 * numImages * sizeof(double));
420
421         goodTransVects = (CvVect64d)cvAlloc(3 * 1 * numImages * sizeof(double));
422         goodRotMatrs   = (CvMatr64d)cvAlloc(3 * 3 * numImages * sizeof(double));
423
424         /* Read object points */
425         i = 0;/* shift for current point */
426         for( currImage = 0; currImage < numImages; currImage++ )
427         {
428             for( currPoint = 0; currPoint < numPoints; currPoint++ )
429             {
430                 double x,y,z;
431                 fscanf(file,"%lf %lf %lf\n",&x,&y,&z);
432
433                 (objectPoints+i)->x = x;
434                 (objectPoints+i)->y = y;
435                 (objectPoints+i)->z = z;
436                 i++;
437             }
438         }
439
440         /* Read image points */
441         i = 0;/* shift for current point */
442         for( currImage = 0; currImage < numImages; currImage++ )
443         {
444             for( currPoint = 0; currPoint < numPoints; currPoint++ )
445             {
446                 double x,y;
447                 fscanf(file,"%lf %lf\n",&x,&y);
448
449                 (imagePoints+i)->x = x;
450                 (imagePoints+i)->y = y;
451                 i++;
452             }
453         }
454
455         /* Read good data computed before */
456
457         /* Focal lengths */
458         double goodFcx,goodFcy;
459         fscanf(file,"%lf %lf",&goodFcx,&goodFcy);
460
461         /* Principal points */
462         double goodCx,goodCy;
463         fscanf(file,"%lf %lf",&goodCx,&goodCy);
464
465         /* Read distortion */
466
467         fscanf(file,"%lf",goodDistortion+0);
468         fscanf(file,"%lf",goodDistortion+1);
469         fscanf(file,"%lf",goodDistortion+2);
470         fscanf(file,"%lf",goodDistortion+3);
471
472         /* Read good Rot matrixes */
473         for( currImage = 0; currImage < numImages; currImage++ )
474         {
475             for( i = 0; i < 3; i++ )
476                 for( j = 0; j < 3; j++ )
477                     fscanf(file, "%lf", goodRotMatrs + currImage * 9 + j * 3 + i);
478         }
479
480         /* Read good Trans vectors */
481         for( currImage = 0; currImage < numImages; currImage++ )
482         {
483             for( i = 0; i < 3; i++ )
484                 fscanf(file, "%lf", goodTransVects + currImage * 3 + i);
485         }
486         
487         calibFlags = 
488                      //CV_CALIB_FIX_PRINCIPAL_POINT +
489                      //CV_CALIB_ZERO_TANGENT_DIST +
490                      //CV_CALIB_FIX_ASPECT_RATIO +
491                      //CV_CALIB_USE_INTRINSIC_GUESS + 
492                      0;
493         memset( cameraMatrix, 0, 9*sizeof(cameraMatrix[0]) );
494         cameraMatrix[0] = cameraMatrix[4] = 807.;
495         cameraMatrix[2] = (imageSize.width - 1)*0.5;
496         cameraMatrix[5] = (imageSize.height - 1)*0.5;
497         cameraMatrix[8] = 1.;
498
499         /* Now we can calibrate camera */
500         cvCalibrateCamera_64d(  numImages,
501                                 numbers,
502                                 imageSize,
503                                 imagePoints,
504                                 objectPoints,
505                                 distortion,
506                                 cameraMatrix,
507                                 transVects,
508                                 rotMatrs,
509                                 calibFlags );
510
511         /* ---- Reproject points to the image ---- */
512         for( currImage = 0; currImage < numImages; currImage++ )
513         {
514             int numPoints = etalonSize.width * etalonSize.height;
515             cvProjectPointsSimple(  numPoints,
516                                     objectPoints + currImage * numPoints,
517                                     rotMatrs + currImage * 9,
518                                     transVects + currImage * 3,
519                                     cameraMatrix,
520                                     distortion,
521                                     reprojectPoints + currImage * numPoints);
522         }
523
524
525         /* ----- Compute reprojection error ----- */
526         i = 0;
527         double dx,dy;
528         double rx,ry;
529         double meanDx,meanDy;
530         double maxDx = 0.0;
531         double maxDy = 0.0;
532
533         meanDx = 0;
534         meanDy = 0;
535         for( currImage = 0; currImage < numImages; currImage++ )
536         {
537             for( currPoint = 0; currPoint < etalonSize.width * etalonSize.height; currPoint++ )
538             {
539                 rx = reprojectPoints[i].x;
540                 ry = reprojectPoints[i].y;
541                 dx = rx - imagePoints[i].x;
542                 dy = ry - imagePoints[i].y;
543
544                 meanDx += dx;
545                 meanDy += dy;
546
547                 dx = fabs(dx);
548                 dy = fabs(dy);
549
550                 if( dx > maxDx )
551                     maxDx = dx;
552                 
553                 if( dy > maxDy )
554                     maxDy = dy;
555                 i++;
556             }
557         }
558
559         meanDx /= numImages * etalonSize.width * etalonSize.height;
560         meanDy /= numImages * etalonSize.width * etalonSize.height;
561
562         /* ========= Compare parameters ========= */
563
564         /* ----- Compare focal lengths ----- */
565         code = compare(cameraMatrix+0,&goodFcx,1,0.01,"fx");
566         if( code < 0 )
567             goto _exit_;
568
569         code = compare(cameraMatrix+4,&goodFcy,1,0.01,"fy");
570         if( code < 0 )
571             goto _exit_;
572
573         /* ----- Compare principal points ----- */
574         code = compare(cameraMatrix+2,&goodCx,1,0.01,"cx");
575         if( code < 0 )
576             goto _exit_;
577
578         code = compare(cameraMatrix+5,&goodCy,1,0.01,"cy");
579         if( code < 0 )
580             goto _exit_;
581
582         /* ----- Compare distortion ----- */
583         code = compare(distortion,goodDistortion,4,0.01,"[k1,k2,p1,p2]");
584         if( code < 0 )
585             goto _exit_;
586
587         /* ----- Compare rot matrixs ----- */
588         code = compare(rotMatrs,goodRotMatrs, 9*numImages,0.05,"rotation matrices");
589         if( code < 0 )
590             goto _exit_;
591
592         /* ----- Compare rot matrixs ----- */
593         code = compare(transVects,goodTransVects, 3*numImages,0.05,"translation vectors");
594         if( code < 0 )
595             goto _exit_;
596
597         if( maxDx > 1.0 )
598         {
599             ts->printf( CvTS::LOG,
600                       "Error in reprojection maxDx=%f > 1.0\n",maxDx);
601             code = CvTS::FAIL_BAD_ACCURACY; goto _exit_;
602         }
603
604         if( maxDy > 1.0 )
605         {
606             ts->printf( CvTS::LOG,
607                       "Error in reprojection maxDy=%f > 1.0\n",maxDy);
608             code = CvTS::FAIL_BAD_ACCURACY; goto _exit_;
609         }
610
611         progress = update_progress( progress, currTest, numTests, 0 );
612
613         cvFree(&imagePoints);
614         cvFree(&objectPoints);
615         cvFree(&reprojectPoints);
616         cvFree(&numbers);
617
618         cvFree(&transVects);
619         cvFree(&rotMatrs);
620         cvFree(&goodTransVects);
621         cvFree(&goodRotMatrs);
622
623         fclose(file);
624         file = 0;
625     }
626
627 _exit_:
628
629     if( file )
630         fclose(file);
631
632     if( datafile )
633         fclose(datafile);
634
635     /* Free all allocated memory */
636     cvFree(&imagePoints);
637     cvFree(&objectPoints);
638     cvFree(&reprojectPoints);
639     cvFree(&numbers);
640
641     cvFree(&transVects);
642     cvFree(&rotMatrs);
643     cvFree(&goodTransVects);
644     cvFree(&goodRotMatrs);
645
646     if( code < 0 )
647         ts->set_failed_test_info( code );
648 }
649
650 CV_CameraCalibrationTest calibrate_test;