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 "test_precomp.hpp" 43 #include "opencv2/calib3d/calib3d_c.h" 44 45 #include <limits> 46 47 using namespace std; 48 using namespace cv; 49 50 #if 0 51 class CV_ProjectPointsTest : public cvtest::ArrayTest 52 { 53 public: 54 CV_ProjectPointsTest(); 55 56 protected: 57 int read_params( CvFileStorage* fs ); 58 void fill_array( int test_case_idx, int i, int j, Mat& arr ); 59 int prepare_test_case( int test_case_idx ); 60 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 61 double get_success_error_level( int test_case_idx, int i, int j ); 62 void run_func(); 63 void prepare_to_validation( int ); 64 65 bool calc_jacobians; 66 }; 67 68 69 CV_ProjectPointsTest::CV_ProjectPointsTest() 70 : cvtest::ArrayTest( "3d-ProjectPoints", "cvProjectPoints2", "" ) 71 { 72 test_array[INPUT].push_back(NULL); // rotation vector 73 test_array[OUTPUT].push_back(NULL); // rotation matrix 74 test_array[OUTPUT].push_back(NULL); // jacobian (J) 75 test_array[OUTPUT].push_back(NULL); // rotation vector (backward transform result) 76 test_array[OUTPUT].push_back(NULL); // inverse transform jacobian (J1) 77 test_array[OUTPUT].push_back(NULL); // J*J1 (or J1*J) == I(3x3) 78 test_array[REF_OUTPUT].push_back(NULL); 79 test_array[REF_OUTPUT].push_back(NULL); 80 test_array[REF_OUTPUT].push_back(NULL); 81 test_array[REF_OUTPUT].push_back(NULL); 82 test_array[REF_OUTPUT].push_back(NULL); 83 84 element_wise_relative_error = false; 85 calc_jacobians = false; 86 } 87 88 89 int CV_ProjectPointsTest::read_params( CvFileStorage* fs ) 90 { 91 int code = cvtest::ArrayTest::read_params( fs ); 92 return code; 93 } 94 95 96 void CV_ProjectPointsTest::get_test_array_types_and_sizes( 97 int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 98 { 99 RNG& rng = ts->get_rng(); 100 int depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F; 101 int i, code; 102 103 code = cvtest::randInt(rng) % 3; 104 types[INPUT][0] = CV_MAKETYPE(depth, 1); 105 106 if( code == 0 ) 107 { 108 sizes[INPUT][0] = cvSize(1,1); 109 types[INPUT][0] = CV_MAKETYPE(depth, 3); 110 } 111 else if( code == 1 ) 112 sizes[INPUT][0] = cvSize(3,1); 113 else 114 sizes[INPUT][0] = cvSize(1,3); 115 116 sizes[OUTPUT][0] = cvSize(3, 3); 117 types[OUTPUT][0] = CV_MAKETYPE(depth, 1); 118 119 types[OUTPUT][1] = CV_MAKETYPE(depth, 1); 120 121 if( cvtest::randInt(rng) % 2 ) 122 sizes[OUTPUT][1] = cvSize(3,9); 123 else 124 sizes[OUTPUT][1] = cvSize(9,3); 125 126 types[OUTPUT][2] = types[INPUT][0]; 127 sizes[OUTPUT][2] = sizes[INPUT][0]; 128 129 types[OUTPUT][3] = types[OUTPUT][1]; 130 sizes[OUTPUT][3] = cvSize(sizes[OUTPUT][1].height, sizes[OUTPUT][1].width); 131 132 types[OUTPUT][4] = types[OUTPUT][1]; 133 sizes[OUTPUT][4] = cvSize(3,3); 134 135 calc_jacobians = 1;//cvtest::randInt(rng) % 3 != 0; 136 if( !calc_jacobians ) 137 sizes[OUTPUT][1] = sizes[OUTPUT][3] = sizes[OUTPUT][4] = cvSize(0,0); 138 139 for( i = 0; i < 5; i++ ) 140 { 141 types[REF_OUTPUT][i] = types[OUTPUT][i]; 142 sizes[REF_OUTPUT][i] = sizes[OUTPUT][i]; 143 } 144 } 145 146 147 double CV_ProjectPointsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j ) 148 { 149 return j == 4 ? 1e-2 : 1e-2; 150 } 151 152 153 void CV_ProjectPointsTest::fill_array( int /*test_case_idx*/, int /*i*/, int /*j*/, CvMat* arr ) 154 { 155 double r[3], theta0, theta1, f; 156 CvMat _r = cvMat( arr->rows, arr->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(arr->type)), r ); 157 RNG& rng = ts->get_rng(); 158 159 r[0] = cvtest::randReal(rng)*CV_PI*2; 160 r[1] = cvtest::randReal(rng)*CV_PI*2; 161 r[2] = cvtest::randReal(rng)*CV_PI*2; 162 163 theta0 = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]); 164 theta1 = fmod(theta0, CV_PI*2); 165 166 if( theta1 > CV_PI ) 167 theta1 = -(CV_PI*2 - theta1); 168 169 f = theta1/(theta0 ? theta0 : 1); 170 r[0] *= f; 171 r[1] *= f; 172 r[2] *= f; 173 174 cvTsConvert( &_r, arr ); 175 } 176 177 178 int CV_ProjectPointsTest::prepare_test_case( int test_case_idx ) 179 { 180 int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); 181 return code; 182 } 183 184 185 void CV_ProjectPointsTest::run_func() 186 { 187 CvMat *v2m_jac = 0, *m2v_jac = 0; 188 if( calc_jacobians ) 189 { 190 v2m_jac = &test_mat[OUTPUT][1]; 191 m2v_jac = &test_mat[OUTPUT][3]; 192 } 193 194 cvProjectPoints2( &test_mat[INPUT][0], &test_mat[OUTPUT][0], v2m_jac ); 195 cvProjectPoints2( &test_mat[OUTPUT][0], &test_mat[OUTPUT][2], m2v_jac ); 196 } 197 198 199 void CV_ProjectPointsTest::prepare_to_validation( int /*test_case_idx*/ ) 200 { 201 const CvMat* vec = &test_mat[INPUT][0]; 202 CvMat* m = &test_mat[REF_OUTPUT][0]; 203 CvMat* vec2 = &test_mat[REF_OUTPUT][2]; 204 CvMat* v2m_jac = 0, *m2v_jac = 0; 205 double theta0, theta1; 206 207 if( calc_jacobians ) 208 { 209 v2m_jac = &test_mat[REF_OUTPUT][1]; 210 m2v_jac = &test_mat[REF_OUTPUT][3]; 211 } 212 213 214 cvTsProjectPoints( vec, m, v2m_jac ); 215 cvTsProjectPoints( m, vec2, m2v_jac ); 216 cvTsCopy( vec, vec2 ); 217 218 theta0 = cvtest::norm( cvarrtomat(vec2), 0, CV_L2 ); 219 theta1 = fmod( theta0, CV_PI*2 ); 220 221 if( theta1 > CV_PI ) 222 theta1 = -(CV_PI*2 - theta1); 223 cvScale( vec2, vec2, theta1/(theta0 ? theta0 : 1) ); 224 225 if( calc_jacobians ) 226 { 227 //cvInvert( v2m_jac, m2v_jac, CV_SVD ); 228 if( cvtest::norm(cvarrtomat(&test_mat[OUTPUT][3]), 0, CV_C) < 1000 ) 229 { 230 cvTsGEMM( &test_mat[OUTPUT][1], &test_mat[OUTPUT][3], 231 1, 0, 0, &test_mat[OUTPUT][4], 232 v2m_jac->rows == 3 ? 0 : CV_GEMM_A_T + CV_GEMM_B_T ); 233 } 234 else 235 { 236 cvTsSetIdentity( &test_mat[OUTPUT][4], cvScalarAll(1.) ); 237 cvTsCopy( &test_mat[REF_OUTPUT][2], &test_mat[OUTPUT][2] ); 238 } 239 cvTsSetIdentity( &test_mat[REF_OUTPUT][4], cvScalarAll(1.) ); 240 } 241 } 242 243 244 CV_ProjectPointsTest ProjectPoints_test; 245 246 #endif 247 248 // --------------------------------- CV_CameraCalibrationTest -------------------------------------------- 249 250 class CV_CameraCalibrationTest : public cvtest::BaseTest 251 { 252 public: 253 CV_CameraCalibrationTest(); 254 ~CV_CameraCalibrationTest(); 255 void clear(); 256 protected: 257 int compare(double* val, double* refVal, int len, 258 double eps, const char* paramName); 259 virtual void calibrate( int imageCount, int* pointCounts, 260 CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, 261 double* distortionCoeffs, double* cameraMatrix, double* translationVectors, 262 double* rotationMatrices, int flags ) = 0; 263 virtual void project( int pointCount, CvPoint3D64f* objectPoints, 264 double* rotationMatrix, double* translationVector, 265 double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ) = 0; 266 267 void run(int); 268 }; 269 270 CV_CameraCalibrationTest::CV_CameraCalibrationTest() 271 { 272 } 273 274 CV_CameraCalibrationTest::~CV_CameraCalibrationTest() 275 { 276 clear(); 277 } 278 279 void CV_CameraCalibrationTest::clear() 280 { 281 cvtest::BaseTest::clear(); 282 } 283 284 int CV_CameraCalibrationTest::compare(double* val, double* ref_val, int len, 285 double eps, const char* param_name ) 286 { 287 return cvtest::cmpEps2_64f( ts, val, ref_val, len, eps, param_name ); 288 } 289 290 void CV_CameraCalibrationTest::run( int start_from ) 291 { 292 int code = cvtest::TS::OK; 293 cv::String filepath; 294 cv::String filename; 295 296 CvSize imageSize; 297 CvSize etalonSize; 298 int numImages; 299 300 CvPoint2D64f* imagePoints; 301 CvPoint3D64f* objectPoints; 302 CvPoint2D64f* reprojectPoints; 303 304 double* transVects; 305 double* rotMatrs; 306 307 double* goodTransVects; 308 double* goodRotMatrs; 309 310 double cameraMatrix[3*3]; 311 double distortion[5]={0,0,0,0,0}; 312 313 double goodDistortion[4]; 314 315 int* numbers; 316 FILE* file = 0; 317 FILE* datafile = 0; 318 int i,j; 319 int currImage; 320 int currPoint; 321 322 int calibFlags; 323 char i_dat_file[100]; 324 int numPoints; 325 int numTests; 326 int currTest; 327 328 imagePoints = 0; 329 objectPoints = 0; 330 reprojectPoints = 0; 331 numbers = 0; 332 333 transVects = 0; 334 rotMatrs = 0; 335 goodTransVects = 0; 336 goodRotMatrs = 0; 337 int progress = 0; 338 int values_read = -1; 339 340 filepath = cv::format("%scv/cameracalibration/", ts->get_data_path().c_str() ); 341 filename = cv::format("%sdatafiles.txt", filepath.c_str() ); 342 datafile = fopen( filename.c_str(), "r" ); 343 if( datafile == 0 ) 344 { 345 ts->printf( cvtest::TS::LOG, "Could not open file with list of test files: %s\n", filename.c_str() ); 346 code = cvtest::TS::FAIL_MISSING_TEST_DATA; 347 goto _exit_; 348 } 349 350 values_read = fscanf(datafile,"%d",&numTests); 351 CV_Assert(values_read == 1); 352 353 for( currTest = start_from; currTest < numTests; currTest++ ) 354 { 355 values_read = fscanf(datafile,"%s",i_dat_file); 356 CV_Assert(values_read == 1); 357 filename = cv::format("%s%s", filepath.c_str(), i_dat_file); 358 file = fopen(filename.c_str(),"r"); 359 360 ts->update_context( this, currTest, true ); 361 362 if( file == 0 ) 363 { 364 ts->printf( cvtest::TS::LOG, 365 "Can't open current test file: %s\n",filename.c_str()); 366 if( numTests == 1 ) 367 { 368 code = cvtest::TS::FAIL_MISSING_TEST_DATA; 369 goto _exit_; 370 } 371 continue; // if there is more than one test, just skip the test 372 } 373 374 values_read = fscanf(file,"%d %d\n",&(imageSize.width),&(imageSize.height)); 375 CV_Assert(values_read == 2); 376 if( imageSize.width <= 0 || imageSize.height <= 0 ) 377 { 378 ts->printf( cvtest::TS::LOG, "Image size in test file is incorrect\n" ); 379 code = cvtest::TS::FAIL_INVALID_TEST_DATA; 380 goto _exit_; 381 } 382 383 /* Read etalon size */ 384 values_read = fscanf(file,"%d %d\n",&(etalonSize.width),&(etalonSize.height)); 385 CV_Assert(values_read == 2); 386 if( etalonSize.width <= 0 || etalonSize.height <= 0 ) 387 { 388 ts->printf( cvtest::TS::LOG, "Pattern size in test file is incorrect\n" ); 389 code = cvtest::TS::FAIL_INVALID_TEST_DATA; 390 goto _exit_; 391 } 392 393 numPoints = etalonSize.width * etalonSize.height; 394 395 /* Read number of images */ 396 values_read = fscanf(file,"%d\n",&numImages); 397 CV_Assert(values_read == 1); 398 if( numImages <=0 ) 399 { 400 ts->printf( cvtest::TS::LOG, "Number of images in test file is incorrect\n"); 401 code = cvtest::TS::FAIL_INVALID_TEST_DATA; 402 goto _exit_; 403 } 404 405 /* Need to allocate memory */ 406 imagePoints = (CvPoint2D64f*)cvAlloc( numPoints * 407 numImages * sizeof(CvPoint2D64f)); 408 409 objectPoints = (CvPoint3D64f*)cvAlloc( numPoints * 410 numImages * sizeof(CvPoint3D64f)); 411 412 reprojectPoints = (CvPoint2D64f*)cvAlloc( numPoints * 413 numImages * sizeof(CvPoint2D64f)); 414 415 /* Alloc memory for numbers */ 416 numbers = (int*)cvAlloc( numImages * sizeof(int)); 417 418 /* Fill it by numbers of points of each image*/ 419 for( currImage = 0; currImage < numImages; currImage++ ) 420 { 421 numbers[currImage] = etalonSize.width * etalonSize.height; 422 } 423 424 /* Allocate memory for translate vectors and rotmatrixs*/ 425 transVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double)); 426 rotMatrs = (double*)cvAlloc(3 * 3 * numImages * sizeof(double)); 427 428 goodTransVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double)); 429 goodRotMatrs = (double*)cvAlloc(3 * 3 * numImages * sizeof(double)); 430 431 /* Read object points */ 432 i = 0;/* shift for current point */ 433 for( currImage = 0; currImage < numImages; currImage++ ) 434 { 435 for( currPoint = 0; currPoint < numPoints; currPoint++ ) 436 { 437 double x,y,z; 438 values_read = fscanf(file,"%lf %lf %lf\n",&x,&y,&z); 439 CV_Assert(values_read == 3); 440 441 (objectPoints+i)->x = x; 442 (objectPoints+i)->y = y; 443 (objectPoints+i)->z = z; 444 i++; 445 } 446 } 447 448 /* Read image points */ 449 i = 0;/* shift for current point */ 450 for( currImage = 0; currImage < numImages; currImage++ ) 451 { 452 for( currPoint = 0; currPoint < numPoints; currPoint++ ) 453 { 454 double x,y; 455 values_read = fscanf(file,"%lf %lf\n",&x,&y); 456 CV_Assert(values_read == 2); 457 458 (imagePoints+i)->x = x; 459 (imagePoints+i)->y = y; 460 i++; 461 } 462 } 463 464 /* Read good data computed before */ 465 466 /* Focal lengths */ 467 double goodFcx,goodFcy; 468 values_read = fscanf(file,"%lf %lf",&goodFcx,&goodFcy); 469 CV_Assert(values_read == 2); 470 471 /* Principal points */ 472 double goodCx,goodCy; 473 values_read = fscanf(file,"%lf %lf",&goodCx,&goodCy); 474 CV_Assert(values_read == 2); 475 476 /* Read distortion */ 477 478 values_read = fscanf(file,"%lf",goodDistortion+0); CV_Assert(values_read == 1); 479 values_read = fscanf(file,"%lf",goodDistortion+1); CV_Assert(values_read == 1); 480 values_read = fscanf(file,"%lf",goodDistortion+2); CV_Assert(values_read == 1); 481 values_read = fscanf(file,"%lf",goodDistortion+3); CV_Assert(values_read == 1); 482 483 /* Read good Rot matrices */ 484 for( currImage = 0; currImage < numImages; currImage++ ) 485 { 486 for( i = 0; i < 3; i++ ) 487 for( j = 0; j < 3; j++ ) 488 { 489 values_read = fscanf(file, "%lf", goodRotMatrs + currImage * 9 + j * 3 + i); 490 CV_Assert(values_read == 1); 491 } 492 } 493 494 /* Read good Trans vectors */ 495 for( currImage = 0; currImage < numImages; currImage++ ) 496 { 497 for( i = 0; i < 3; i++ ) 498 { 499 values_read = fscanf(file, "%lf", goodTransVects + currImage * 3 + i); 500 CV_Assert(values_read == 1); 501 } 502 } 503 504 calibFlags = 0 505 // + CV_CALIB_FIX_PRINCIPAL_POINT 506 // + CV_CALIB_ZERO_TANGENT_DIST 507 // + CV_CALIB_FIX_ASPECT_RATIO 508 // + CV_CALIB_USE_INTRINSIC_GUESS 509 + CV_CALIB_FIX_K3 510 + CV_CALIB_FIX_K4+CV_CALIB_FIX_K5 511 + CV_CALIB_FIX_K6 512 ; 513 memset( cameraMatrix, 0, 9*sizeof(cameraMatrix[0]) ); 514 cameraMatrix[0] = cameraMatrix[4] = 807.; 515 cameraMatrix[2] = (imageSize.width - 1)*0.5; 516 cameraMatrix[5] = (imageSize.height - 1)*0.5; 517 cameraMatrix[8] = 1.; 518 519 /* Now we can calibrate camera */ 520 calibrate( numImages, 521 numbers, 522 imageSize, 523 imagePoints, 524 objectPoints, 525 distortion, 526 cameraMatrix, 527 transVects, 528 rotMatrs, 529 calibFlags ); 530 531 /* ---- Reproject points to the image ---- */ 532 for( currImage = 0; currImage < numImages; currImage++ ) 533 { 534 int nPoints = etalonSize.width * etalonSize.height; 535 project( nPoints, 536 objectPoints + currImage * nPoints, 537 rotMatrs + currImage * 9, 538 transVects + currImage * 3, 539 cameraMatrix, 540 distortion, 541 reprojectPoints + currImage * nPoints); 542 } 543 544 /* ----- Compute reprojection error ----- */ 545 i = 0; 546 double dx,dy; 547 double rx,ry; 548 double meanDx,meanDy; 549 double maxDx = 0.0; 550 double maxDy = 0.0; 551 552 meanDx = 0; 553 meanDy = 0; 554 for( currImage = 0; currImage < numImages; currImage++ ) 555 { 556 for( currPoint = 0; currPoint < etalonSize.width * etalonSize.height; currPoint++ ) 557 { 558 rx = reprojectPoints[i].x; 559 ry = reprojectPoints[i].y; 560 dx = rx - imagePoints[i].x; 561 dy = ry - imagePoints[i].y; 562 563 meanDx += dx; 564 meanDy += dy; 565 566 dx = fabs(dx); 567 dy = fabs(dy); 568 569 if( dx > maxDx ) 570 maxDx = dx; 571 572 if( dy > maxDy ) 573 maxDy = dy; 574 i++; 575 } 576 } 577 578 meanDx /= numImages * etalonSize.width * etalonSize.height; 579 meanDy /= numImages * etalonSize.width * etalonSize.height; 580 581 /* ========= Compare parameters ========= */ 582 583 /* ----- Compare focal lengths ----- */ 584 code = compare(cameraMatrix+0,&goodFcx,1,0.1,"fx"); 585 if( code < 0 ) 586 goto _exit_; 587 588 code = compare(cameraMatrix+4,&goodFcy,1,0.1,"fy"); 589 if( code < 0 ) 590 goto _exit_; 591 592 /* ----- Compare principal points ----- */ 593 code = compare(cameraMatrix+2,&goodCx,1,0.1,"cx"); 594 if( code < 0 ) 595 goto _exit_; 596 597 code = compare(cameraMatrix+5,&goodCy,1,0.1,"cy"); 598 if( code < 0 ) 599 goto _exit_; 600 601 /* ----- Compare distortion ----- */ 602 code = compare(distortion,goodDistortion,4,0.1,"[k1,k2,p1,p2]"); 603 if( code < 0 ) 604 goto _exit_; 605 606 /* ----- Compare rot matrixs ----- */ 607 code = compare(rotMatrs,goodRotMatrs, 9*numImages,0.05,"rotation matrices"); 608 if( code < 0 ) 609 goto _exit_; 610 611 /* ----- Compare rot matrixs ----- */ 612 code = compare(transVects,goodTransVects, 3*numImages,0.1,"translation vectors"); 613 if( code < 0 ) 614 goto _exit_; 615 616 if( maxDx > 1.0 ) 617 { 618 ts->printf( cvtest::TS::LOG, 619 "Error in reprojection maxDx=%f > 1.0\n",maxDx); 620 code = cvtest::TS::FAIL_BAD_ACCURACY; goto _exit_; 621 } 622 623 if( maxDy > 1.0 ) 624 { 625 ts->printf( cvtest::TS::LOG, 626 "Error in reprojection maxDy=%f > 1.0\n",maxDy); 627 code = cvtest::TS::FAIL_BAD_ACCURACY; goto _exit_; 628 } 629 630 progress = update_progress( progress, currTest, numTests, 0 ); 631 632 cvFree(&imagePoints); 633 cvFree(&objectPoints); 634 cvFree(&reprojectPoints); 635 cvFree(&numbers); 636 637 cvFree(&transVects); 638 cvFree(&rotMatrs); 639 cvFree(&goodTransVects); 640 cvFree(&goodRotMatrs); 641 642 fclose(file); 643 file = 0; 644 } 645 646 _exit_: 647 648 if( file ) 649 fclose(file); 650 651 if( datafile ) 652 fclose(datafile); 653 654 /* Free all allocated memory */ 655 cvFree(&imagePoints); 656 cvFree(&objectPoints); 657 cvFree(&reprojectPoints); 658 cvFree(&numbers); 659 660 cvFree(&transVects); 661 cvFree(&rotMatrs); 662 cvFree(&goodTransVects); 663 cvFree(&goodRotMatrs); 664 665 if( code < 0 ) 666 ts->set_failed_test_info( code ); 667 } 668 669 // --------------------------------- CV_CameraCalibrationTest_C -------------------------------------------- 670 671 class CV_CameraCalibrationTest_C : public CV_CameraCalibrationTest 672 { 673 public: 674 CV_CameraCalibrationTest_C(){} 675 protected: 676 virtual void calibrate( int imageCount, int* pointCounts, 677 CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, 678 double* distortionCoeffs, double* cameraMatrix, double* translationVectors, 679 double* rotationMatrices, int flags ); 680 virtual void project( int pointCount, CvPoint3D64f* objectPoints, 681 double* rotationMatrix, double* translationVector, 682 double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ); 683 }; 684 685 void CV_CameraCalibrationTest_C::calibrate( int imageCount, int* pointCounts, 686 CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, 687 double* distortionCoeffs, double* cameraMatrix, double* translationVectors, 688 double* rotationMatrices, int flags ) 689 { 690 int i, total = 0; 691 for( i = 0; i < imageCount; i++ ) 692 total += pointCounts[i]; 693 694 CvMat _objectPoints = cvMat(1, total, CV_64FC3, objectPoints); 695 CvMat _imagePoints = cvMat(1, total, CV_64FC2, imagePoints); 696 CvMat _pointCounts = cvMat(1, imageCount, CV_32S, pointCounts); 697 CvMat _cameraMatrix = cvMat(3, 3, CV_64F, cameraMatrix); 698 CvMat _distCoeffs = cvMat(4, 1, CV_64F, distortionCoeffs); 699 CvMat _rotationMatrices = cvMat(imageCount, 9, CV_64F, rotationMatrices); 700 CvMat _translationVectors = cvMat(imageCount, 3, CV_64F, translationVectors); 701 702 cvCalibrateCamera2(&_objectPoints, &_imagePoints, &_pointCounts, imageSize, 703 &_cameraMatrix, &_distCoeffs, &_rotationMatrices, &_translationVectors, 704 flags); 705 } 706 707 void CV_CameraCalibrationTest_C::project( int pointCount, CvPoint3D64f* objectPoints, 708 double* rotationMatrix, double* translationVector, 709 double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ) 710 { 711 CvMat _objectPoints = cvMat(1, pointCount, CV_64FC3, objectPoints); 712 CvMat _imagePoints = cvMat(1, pointCount, CV_64FC2, imagePoints); 713 CvMat _cameraMatrix = cvMat(3, 3, CV_64F, cameraMatrix); 714 CvMat _distCoeffs = cvMat(4, 1, CV_64F, distortion); 715 CvMat _rotationMatrix = cvMat(3, 3, CV_64F, rotationMatrix); 716 CvMat _translationVector = cvMat(1, 3, CV_64F, translationVector); 717 718 cvProjectPoints2(&_objectPoints, &_rotationMatrix, &_translationVector, &_cameraMatrix, &_distCoeffs, &_imagePoints); 719 } 720 721 // --------------------------------- CV_CameraCalibrationTest_CPP -------------------------------------------- 722 723 class CV_CameraCalibrationTest_CPP : public CV_CameraCalibrationTest 724 { 725 public: 726 CV_CameraCalibrationTest_CPP(){} 727 protected: 728 virtual void calibrate( int imageCount, int* pointCounts, 729 CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, 730 double* distortionCoeffs, double* cameraMatrix, double* translationVectors, 731 double* rotationMatrices, int flags ); 732 virtual void project( int pointCount, CvPoint3D64f* objectPoints, 733 double* rotationMatrix, double* translationVector, 734 double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ); 735 }; 736 737 void CV_CameraCalibrationTest_CPP::calibrate( int imageCount, int* pointCounts, 738 CvSize _imageSize, CvPoint2D64f* _imagePoints, CvPoint3D64f* _objectPoints, 739 double* _distortionCoeffs, double* _cameraMatrix, double* translationVectors, 740 double* rotationMatrices, int flags ) 741 { 742 vector<vector<Point3f> > objectPoints( imageCount ); 743 vector<vector<Point2f> > imagePoints( imageCount ); 744 Size imageSize = _imageSize; 745 Mat cameraMatrix, distCoeffs(1,4,CV_64F,Scalar::all(0)); 746 vector<Mat> rvecs, tvecs; 747 748 CvPoint3D64f* op = _objectPoints; 749 CvPoint2D64f* ip = _imagePoints; 750 vector<vector<Point3f> >::iterator objectPointsIt = objectPoints.begin(); 751 vector<vector<Point2f> >::iterator imagePointsIt = imagePoints.begin(); 752 for( int i = 0; i < imageCount; ++objectPointsIt, ++imagePointsIt, i++ ) 753 { 754 int num = pointCounts[i]; 755 objectPointsIt->resize( num ); 756 imagePointsIt->resize( num ); 757 vector<Point3f>::iterator oIt = objectPointsIt->begin(); 758 vector<Point2f>::iterator iIt = imagePointsIt->begin(); 759 for( int j = 0; j < num; ++oIt, ++iIt, j++, op++, ip++) 760 { 761 oIt->x = (float)op->x, oIt->y = (float)op->y, oIt->z = (float)op->z; 762 iIt->x = (float)ip->x, iIt->y = (float)ip->y; 763 } 764 } 765 766 calibrateCamera( objectPoints, 767 imagePoints, 768 imageSize, 769 cameraMatrix, 770 distCoeffs, 771 rvecs, 772 tvecs, 773 flags ); 774 775 assert( cameraMatrix.type() == CV_64FC1 ); 776 memcpy( _cameraMatrix, cameraMatrix.ptr(), 9*sizeof(double) ); 777 778 assert( cameraMatrix.type() == CV_64FC1 ); 779 memcpy( _distortionCoeffs, distCoeffs.ptr(), 4*sizeof(double) ); 780 781 vector<Mat>::iterator rvecsIt = rvecs.begin(); 782 vector<Mat>::iterator tvecsIt = tvecs.begin(); 783 double *rm = rotationMatrices, 784 *tm = translationVectors; 785 assert( rvecsIt->type() == CV_64FC1 ); 786 assert( tvecsIt->type() == CV_64FC1 ); 787 for( int i = 0; i < imageCount; ++rvecsIt, ++tvecsIt, i++, rm+=9, tm+=3 ) 788 { 789 Mat r9( 3, 3, CV_64FC1 ); 790 Rodrigues( *rvecsIt, r9 ); 791 memcpy( rm, r9.ptr(), 9*sizeof(double) ); 792 memcpy( tm, tvecsIt->ptr(), 3*sizeof(double) ); 793 } 794 } 795 796 void CV_CameraCalibrationTest_CPP::project( int pointCount, CvPoint3D64f* _objectPoints, 797 double* rotationMatrix, double* translationVector, 798 double* _cameraMatrix, double* distortion, CvPoint2D64f* _imagePoints ) 799 { 800 Mat objectPoints( pointCount, 3, CV_64FC1, _objectPoints ); 801 Mat rmat( 3, 3, CV_64FC1, rotationMatrix ), 802 rvec( 1, 3, CV_64FC1 ), 803 tvec( 1, 3, CV_64FC1, translationVector ); 804 Mat cameraMatrix( 3, 3, CV_64FC1, _cameraMatrix ); 805 Mat distCoeffs( 1, 4, CV_64FC1, distortion ); 806 vector<Point2f> imagePoints; 807 Rodrigues( rmat, rvec ); 808 809 objectPoints.convertTo( objectPoints, CV_32FC1 ); 810 projectPoints( objectPoints, rvec, tvec, 811 cameraMatrix, distCoeffs, imagePoints ); 812 vector<Point2f>::const_iterator it = imagePoints.begin(); 813 for( int i = 0; it != imagePoints.end(); ++it, i++ ) 814 { 815 _imagePoints[i] = cvPoint2D64f( it->x, it->y ); 816 } 817 } 818 819 820 //----------------------------------------- CV_CalibrationMatrixValuesTest -------------------------------- 821 822 class CV_CalibrationMatrixValuesTest : public cvtest::BaseTest 823 { 824 public: 825 CV_CalibrationMatrixValuesTest() {} 826 protected: 827 void run(int); 828 virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize, 829 double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength, 830 Point2d& principalPoint, double& aspectRatio ) = 0; 831 }; 832 833 void CV_CalibrationMatrixValuesTest::run(int) 834 { 835 int code = cvtest::TS::OK; 836 const double fcMinVal = 1e-5; 837 const double fcMaxVal = 1000; 838 const double apertureMaxVal = 0.01; 839 840 RNG rng = ts->get_rng(); 841 842 double fx, fy, cx, cy, nx, ny; 843 Mat cameraMatrix( 3, 3, CV_64FC1 ); 844 cameraMatrix.setTo( Scalar(0) ); 845 fx = cameraMatrix.at<double>(0,0) = rng.uniform( fcMinVal, fcMaxVal ); 846 fy = cameraMatrix.at<double>(1,1) = rng.uniform( fcMinVal, fcMaxVal ); 847 cx = cameraMatrix.at<double>(0,2) = rng.uniform( fcMinVal, fcMaxVal ); 848 cy = cameraMatrix.at<double>(1,2) = rng.uniform( fcMinVal, fcMaxVal ); 849 cameraMatrix.at<double>(2,2) = 1; 850 851 Size imageSize( 600, 400 ); 852 853 double apertureWidth = (double)rng * apertureMaxVal, 854 apertureHeight = (double)rng * apertureMaxVal; 855 856 double fovx, fovy, focalLength, aspectRatio, 857 goodFovx, goodFovy, goodFocalLength, goodAspectRatio; 858 Point2d principalPoint, goodPrincipalPoint; 859 860 861 calibMatrixValues( cameraMatrix, imageSize, apertureWidth, apertureHeight, 862 fovx, fovy, focalLength, principalPoint, aspectRatio ); 863 864 // calculate calibration matrix values 865 goodAspectRatio = fy / fx; 866 867 if( apertureWidth != 0.0 && apertureHeight != 0.0 ) 868 { 869 nx = imageSize.width / apertureWidth; 870 ny = imageSize.height / apertureHeight; 871 } 872 else 873 { 874 nx = 1.0; 875 ny = goodAspectRatio; 876 } 877 878 goodFovx = 2 * atan( imageSize.width / (2 * fx)) * 180.0 / CV_PI; 879 goodFovy = 2 * atan( imageSize.height / (2 * fy)) * 180.0 / CV_PI; 880 881 goodFocalLength = fx / nx; 882 883 goodPrincipalPoint.x = cx / nx; 884 goodPrincipalPoint.y = cy / ny; 885 886 // check results 887 if( fabs(fovx - goodFovx) > FLT_EPSILON ) 888 { 889 ts->printf( cvtest::TS::LOG, "bad fovx (real=%f, good = %f\n", fovx, goodFovx ); 890 code = cvtest::TS::FAIL_BAD_ACCURACY; 891 goto _exit_; 892 } 893 if( fabs(fovy - goodFovy) > FLT_EPSILON ) 894 { 895 ts->printf( cvtest::TS::LOG, "bad fovy (real=%f, good = %f\n", fovy, goodFovy ); 896 code = cvtest::TS::FAIL_BAD_ACCURACY; 897 goto _exit_; 898 } 899 if( fabs(focalLength - goodFocalLength) > FLT_EPSILON ) 900 { 901 ts->printf( cvtest::TS::LOG, "bad focalLength (real=%f, good = %f\n", focalLength, goodFocalLength ); 902 code = cvtest::TS::FAIL_BAD_ACCURACY; 903 goto _exit_; 904 } 905 if( fabs(aspectRatio - goodAspectRatio) > FLT_EPSILON ) 906 { 907 ts->printf( cvtest::TS::LOG, "bad aspectRatio (real=%f, good = %f\n", aspectRatio, goodAspectRatio ); 908 code = cvtest::TS::FAIL_BAD_ACCURACY; 909 goto _exit_; 910 } 911 if( norm( principalPoint - goodPrincipalPoint ) > FLT_EPSILON ) 912 { 913 ts->printf( cvtest::TS::LOG, "bad principalPoint\n" ); 914 code = cvtest::TS::FAIL_BAD_ACCURACY; 915 goto _exit_; 916 } 917 918 _exit_: 919 RNG& _rng = ts->get_rng(); 920 _rng = rng; 921 ts->set_failed_test_info( code ); 922 } 923 924 //----------------------------------------- CV_CalibrationMatrixValuesTest_C -------------------------------- 925 926 class CV_CalibrationMatrixValuesTest_C : public CV_CalibrationMatrixValuesTest 927 { 928 public: 929 CV_CalibrationMatrixValuesTest_C(){} 930 protected: 931 virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize, 932 double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength, 933 Point2d& principalPoint, double& aspectRatio ); 934 }; 935 936 void CV_CalibrationMatrixValuesTest_C::calibMatrixValues( const Mat& _cameraMatrix, Size imageSize, 937 double apertureWidth, double apertureHeight, 938 double& fovx, double& fovy, double& focalLength, 939 Point2d& principalPoint, double& aspectRatio ) 940 { 941 CvMat cameraMatrix = _cameraMatrix; 942 CvPoint2D64f pp; 943 cvCalibrationMatrixValues( &cameraMatrix, imageSize, apertureWidth, apertureHeight, 944 &fovx, &fovy, &focalLength, &pp, &aspectRatio ); 945 principalPoint.x = pp.x; 946 principalPoint.y = pp.y; 947 } 948 949 950 //----------------------------------------- CV_CalibrationMatrixValuesTest_CPP -------------------------------- 951 952 class CV_CalibrationMatrixValuesTest_CPP : public CV_CalibrationMatrixValuesTest 953 { 954 public: 955 CV_CalibrationMatrixValuesTest_CPP() {} 956 protected: 957 virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize, 958 double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength, 959 Point2d& principalPoint, double& aspectRatio ); 960 }; 961 962 void CV_CalibrationMatrixValuesTest_CPP::calibMatrixValues( const Mat& cameraMatrix, Size imageSize, 963 double apertureWidth, double apertureHeight, 964 double& fovx, double& fovy, double& focalLength, 965 Point2d& principalPoint, double& aspectRatio ) 966 { 967 calibrationMatrixValues( cameraMatrix, imageSize, apertureWidth, apertureHeight, 968 fovx, fovy, focalLength, principalPoint, aspectRatio ); 969 } 970 971 972 //----------------------------------------- CV_ProjectPointsTest -------------------------------- 973 void calcdfdx( const vector<vector<Point2f> >& leftF, const vector<vector<Point2f> >& rightF, double eps, Mat& dfdx ) 974 { 975 const int fdim = 2; 976 CV_Assert( !leftF.empty() && !rightF.empty() && !leftF[0].empty() && !rightF[0].empty() ); 977 CV_Assert( leftF[0].size() == rightF[0].size() ); 978 CV_Assert( fabs(eps) > std::numeric_limits<double>::epsilon() ); 979 int fcount = (int)leftF[0].size(), xdim = (int)leftF.size(); 980 981 dfdx.create( fcount*fdim, xdim, CV_64FC1 ); 982 983 vector<vector<Point2f> >::const_iterator arrLeftIt = leftF.begin(); 984 vector<vector<Point2f> >::const_iterator arrRightIt = rightF.begin(); 985 for( int xi = 0; xi < xdim; xi++, ++arrLeftIt, ++arrRightIt ) 986 { 987 CV_Assert( (int)arrLeftIt->size() == fcount ); 988 CV_Assert( (int)arrRightIt->size() == fcount ); 989 vector<Point2f>::const_iterator lIt = arrLeftIt->begin(); 990 vector<Point2f>::const_iterator rIt = arrRightIt->begin(); 991 for( int fi = 0; fi < dfdx.rows; fi+=fdim, ++lIt, ++rIt ) 992 { 993 dfdx.at<double>(fi, xi ) = 0.5 * ((double)(rIt->x - lIt->x)) / eps; 994 dfdx.at<double>(fi+1, xi ) = 0.5 * ((double)(rIt->y - lIt->y)) / eps; 995 } 996 } 997 } 998 999 class CV_ProjectPointsTest : public cvtest::BaseTest 1000 { 1001 public: 1002 CV_ProjectPointsTest() {} 1003 protected: 1004 void run(int); 1005 virtual void project( const Mat& objectPoints, 1006 const Mat& rvec, const Mat& tvec, 1007 const Mat& cameraMatrix, 1008 const Mat& distCoeffs, 1009 vector<Point2f>& imagePoints, 1010 Mat& dpdrot, Mat& dpdt, Mat& dpdf, 1011 Mat& dpdc, Mat& dpddist, 1012 double aspectRatio=0 ) = 0; 1013 }; 1014 1015 void CV_ProjectPointsTest::run(int) 1016 { 1017 //typedef float matType; 1018 1019 int code = cvtest::TS::OK; 1020 const int pointCount = 100; 1021 1022 const float zMinVal = 10.0f, zMaxVal = 100.0f, 1023 rMinVal = -0.3f, rMaxVal = 0.3f, 1024 tMinVal = -2.0f, tMaxVal = 2.0f; 1025 1026 const float imgPointErr = 1e-3f, 1027 dEps = 1e-3f; 1028 1029 double err; 1030 1031 Size imgSize( 600, 800 ); 1032 Mat_<float> objPoints( pointCount, 3), rvec( 1, 3), rmat, tvec( 1, 3 ), cameraMatrix( 3, 3 ), distCoeffs( 1, 4 ), 1033 leftRvec, rightRvec, leftTvec, rightTvec, leftCameraMatrix, rightCameraMatrix, leftDistCoeffs, rightDistCoeffs; 1034 1035 RNG rng = ts->get_rng(); 1036 1037 // generate data 1038 cameraMatrix << 300.f, 0.f, imgSize.width/2.f, 1039 0.f, 300.f, imgSize.height/2.f, 1040 0.f, 0.f, 1.f; 1041 distCoeffs << 0.1, 0.01, 0.001, 0.001; 1042 1043 rvec(0,0) = rng.uniform( rMinVal, rMaxVal ); 1044 rvec(0,1) = rng.uniform( rMinVal, rMaxVal ); 1045 rvec(0,2) = rng.uniform( rMinVal, rMaxVal ); 1046 Rodrigues( rvec, rmat ); 1047 1048 tvec(0,0) = rng.uniform( tMinVal, tMaxVal ); 1049 tvec(0,1) = rng.uniform( tMinVal, tMaxVal ); 1050 tvec(0,2) = rng.uniform( tMinVal, tMaxVal ); 1051 1052 for( int y = 0; y < objPoints.rows; y++ ) 1053 { 1054 Mat point(1, 3, CV_32FC1, objPoints.ptr(y) ); 1055 float z = rng.uniform( zMinVal, zMaxVal ); 1056 point.at<float>(0,2) = z; 1057 point.at<float>(0,0) = (rng.uniform(2.f,(float)(imgSize.width-2)) - cameraMatrix(0,2)) / cameraMatrix(0,0) * z; 1058 point.at<float>(0,1) = (rng.uniform(2.f,(float)(imgSize.height-2)) - cameraMatrix(1,2)) / cameraMatrix(1,1) * z; 1059 point = (point - tvec) * rmat; 1060 } 1061 1062 vector<Point2f> imgPoints; 1063 vector<vector<Point2f> > leftImgPoints; 1064 vector<vector<Point2f> > rightImgPoints; 1065 Mat dpdrot, dpdt, dpdf, dpdc, dpddist, 1066 valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist; 1067 1068 project( objPoints, rvec, tvec, cameraMatrix, distCoeffs, 1069 imgPoints, dpdrot, dpdt, dpdf, dpdc, dpddist, 0 ); 1070 1071 // calculate and check image points 1072 assert( (int)imgPoints.size() == pointCount ); 1073 vector<Point2f>::const_iterator it = imgPoints.begin(); 1074 for( int i = 0; i < pointCount; i++, ++it ) 1075 { 1076 Point3d p( objPoints(i,0), objPoints(i,1), objPoints(i,2) ); 1077 double z = p.x*rmat(2,0) + p.y*rmat(2,1) + p.z*rmat(2,2) + tvec(0,2), 1078 x = (p.x*rmat(0,0) + p.y*rmat(0,1) + p.z*rmat(0,2) + tvec(0,0)) / z, 1079 y = (p.x*rmat(1,0) + p.y*rmat(1,1) + p.z*rmat(1,2) + tvec(0,1)) / z, 1080 r2 = x*x + y*y, 1081 r4 = r2*r2; 1082 Point2f validImgPoint; 1083 double a1 = 2*x*y, 1084 a2 = r2 + 2*x*x, 1085 a3 = r2 + 2*y*y, 1086 cdist = 1+distCoeffs(0,0)*r2+distCoeffs(0,1)*r4; 1087 validImgPoint.x = static_cast<float>((double)cameraMatrix(0,0)*(x*cdist + (double)distCoeffs(0,2)*a1 + (double)distCoeffs(0,3)*a2) 1088 + (double)cameraMatrix(0,2)); 1089 validImgPoint.y = static_cast<float>((double)cameraMatrix(1,1)*(y*cdist + (double)distCoeffs(0,2)*a3 + distCoeffs(0,3)*a1) 1090 + (double)cameraMatrix(1,2)); 1091 1092 if( fabs(it->x - validImgPoint.x) > imgPointErr || 1093 fabs(it->y - validImgPoint.y) > imgPointErr ) 1094 { 1095 ts->printf( cvtest::TS::LOG, "bad image point\n" ); 1096 code = cvtest::TS::FAIL_BAD_ACCURACY; 1097 goto _exit_; 1098 } 1099 } 1100 1101 // check derivatives 1102 // 1. rotation 1103 leftImgPoints.resize(3); 1104 rightImgPoints.resize(3); 1105 for( int i = 0; i < 3; i++ ) 1106 { 1107 rvec.copyTo( leftRvec ); leftRvec(0,i) -= dEps; 1108 project( objPoints, leftRvec, tvec, cameraMatrix, distCoeffs, 1109 leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1110 rvec.copyTo( rightRvec ); rightRvec(0,i) += dEps; 1111 project( objPoints, rightRvec, tvec, cameraMatrix, distCoeffs, 1112 rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1113 } 1114 calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdrot ); 1115 err = cvtest::norm( dpdrot, valDpdrot, NORM_INF ); 1116 if( err > 3 ) 1117 { 1118 ts->printf( cvtest::TS::LOG, "bad dpdrot: too big difference = %g\n", err ); 1119 code = cvtest::TS::FAIL_BAD_ACCURACY; 1120 } 1121 1122 // 2. translation 1123 for( int i = 0; i < 3; i++ ) 1124 { 1125 tvec.copyTo( leftTvec ); leftTvec(0,i) -= dEps; 1126 project( objPoints, rvec, leftTvec, cameraMatrix, distCoeffs, 1127 leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1128 tvec.copyTo( rightTvec ); rightTvec(0,i) += dEps; 1129 project( objPoints, rvec, rightTvec, cameraMatrix, distCoeffs, 1130 rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1131 } 1132 calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdt ); 1133 if( cvtest::norm( dpdt, valDpdt, NORM_INF ) > 0.2 ) 1134 { 1135 ts->printf( cvtest::TS::LOG, "bad dpdtvec\n" ); 1136 code = cvtest::TS::FAIL_BAD_ACCURACY; 1137 } 1138 1139 // 3. camera matrix 1140 // 3.1. focus 1141 leftImgPoints.resize(2); 1142 rightImgPoints.resize(2); 1143 cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(0,0) -= dEps; 1144 project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs, 1145 leftImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1146 cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(1,1) -= dEps; 1147 project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs, 1148 leftImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1149 cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(0,0) += dEps; 1150 project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs, 1151 rightImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1152 cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(1,1) += dEps; 1153 project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs, 1154 rightImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1155 calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdf ); 1156 if ( cvtest::norm( dpdf, valDpdf, NORM_L2 ) > 0.2 ) 1157 { 1158 ts->printf( cvtest::TS::LOG, "bad dpdf\n" ); 1159 code = cvtest::TS::FAIL_BAD_ACCURACY; 1160 } 1161 // 3.2. principal point 1162 leftImgPoints.resize(2); 1163 rightImgPoints.resize(2); 1164 cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(0,2) -= dEps; 1165 project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs, 1166 leftImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1167 cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(1,2) -= dEps; 1168 project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs, 1169 leftImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1170 cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(0,2) += dEps; 1171 project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs, 1172 rightImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1173 cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(1,2) += dEps; 1174 project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs, 1175 rightImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1176 calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdc ); 1177 if ( cvtest::norm( dpdc, valDpdc, NORM_L2 ) > 0.2 ) 1178 { 1179 ts->printf( cvtest::TS::LOG, "bad dpdc\n" ); 1180 code = cvtest::TS::FAIL_BAD_ACCURACY; 1181 } 1182 1183 // 4. distortion 1184 leftImgPoints.resize(distCoeffs.cols); 1185 rightImgPoints.resize(distCoeffs.cols); 1186 for( int i = 0; i < distCoeffs.cols; i++ ) 1187 { 1188 distCoeffs.copyTo( leftDistCoeffs ); leftDistCoeffs(0,i) -= dEps; 1189 project( objPoints, rvec, tvec, cameraMatrix, leftDistCoeffs, 1190 leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1191 distCoeffs.copyTo( rightDistCoeffs ); rightDistCoeffs(0,i) += dEps; 1192 project( objPoints, rvec, tvec, cameraMatrix, rightDistCoeffs, 1193 rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 ); 1194 } 1195 calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpddist ); 1196 if( cvtest::norm( dpddist, valDpddist, NORM_L2 ) > 0.3 ) 1197 { 1198 ts->printf( cvtest::TS::LOG, "bad dpddist\n" ); 1199 code = cvtest::TS::FAIL_BAD_ACCURACY; 1200 } 1201 1202 _exit_: 1203 RNG& _rng = ts->get_rng(); 1204 _rng = rng; 1205 ts->set_failed_test_info( code ); 1206 } 1207 1208 //----------------------------------------- CV_ProjectPointsTest_C -------------------------------- 1209 class CV_ProjectPointsTest_C : public CV_ProjectPointsTest 1210 { 1211 public: 1212 CV_ProjectPointsTest_C() {} 1213 protected: 1214 virtual void project( const Mat& objectPoints, 1215 const Mat& rvec, const Mat& tvec, 1216 const Mat& cameraMatrix, 1217 const Mat& distCoeffs, 1218 vector<Point2f>& imagePoints, 1219 Mat& dpdrot, Mat& dpdt, Mat& dpdf, 1220 Mat& dpdc, Mat& dpddist, 1221 double aspectRatio=0 ); 1222 }; 1223 1224 void CV_ProjectPointsTest_C::project( const Mat& opoints, const Mat& rvec, const Mat& tvec, 1225 const Mat& cameraMatrix, const Mat& distCoeffs, vector<Point2f>& ipoints, 1226 Mat& dpdrot, Mat& dpdt, Mat& dpdf, Mat& dpdc, Mat& dpddist, double aspectRatio) 1227 { 1228 int npoints = opoints.cols*opoints.rows*opoints.channels()/3; 1229 ipoints.resize(npoints); 1230 dpdrot.create(npoints*2, 3, CV_64F); 1231 dpdt.create(npoints*2, 3, CV_64F); 1232 dpdf.create(npoints*2, 2, CV_64F); 1233 dpdc.create(npoints*2, 2, CV_64F); 1234 dpddist.create(npoints*2, distCoeffs.rows + distCoeffs.cols - 1, CV_64F); 1235 CvMat _objectPoints = opoints, _imagePoints = Mat(ipoints); 1236 CvMat _rvec = rvec, _tvec = tvec, _cameraMatrix = cameraMatrix, _distCoeffs = distCoeffs; 1237 CvMat _dpdrot = dpdrot, _dpdt = dpdt, _dpdf = dpdf, _dpdc = dpdc, _dpddist = dpddist; 1238 1239 cvProjectPoints2( &_objectPoints, &_rvec, &_tvec, &_cameraMatrix, &_distCoeffs, 1240 &_imagePoints, &_dpdrot, &_dpdt, &_dpdf, &_dpdc, &_dpddist, aspectRatio ); 1241 } 1242 1243 1244 //----------------------------------------- CV_ProjectPointsTest_CPP -------------------------------- 1245 class CV_ProjectPointsTest_CPP : public CV_ProjectPointsTest 1246 { 1247 public: 1248 CV_ProjectPointsTest_CPP() {} 1249 protected: 1250 virtual void project( const Mat& objectPoints, 1251 const Mat& rvec, const Mat& tvec, 1252 const Mat& cameraMatrix, 1253 const Mat& distCoeffs, 1254 vector<Point2f>& imagePoints, 1255 Mat& dpdrot, Mat& dpdt, Mat& dpdf, 1256 Mat& dpdc, Mat& dpddist, 1257 double aspectRatio=0 ); 1258 }; 1259 1260 void CV_ProjectPointsTest_CPP::project( const Mat& objectPoints, const Mat& rvec, const Mat& tvec, 1261 const Mat& cameraMatrix, const Mat& distCoeffs, vector<Point2f>& imagePoints, 1262 Mat& dpdrot, Mat& dpdt, Mat& dpdf, Mat& dpdc, Mat& dpddist, double aspectRatio) 1263 { 1264 Mat J; 1265 projectPoints( objectPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints, J, aspectRatio); 1266 J.colRange(0, 3).copyTo(dpdrot); 1267 J.colRange(3, 6).copyTo(dpdt); 1268 J.colRange(6, 8).copyTo(dpdf); 1269 J.colRange(8, 10).copyTo(dpdc); 1270 J.colRange(10, J.cols).copyTo(dpddist); 1271 } 1272 1273 ///////////////////////////////// Stereo Calibration ///////////////////////////////////// 1274 1275 class CV_StereoCalibrationTest : public cvtest::BaseTest 1276 { 1277 public: 1278 CV_StereoCalibrationTest(); 1279 ~CV_StereoCalibrationTest(); 1280 void clear(); 1281 protected: 1282 bool checkPandROI( int test_case_idx, 1283 const Mat& M, const Mat& D, const Mat& R, 1284 const Mat& P, Size imgsize, Rect roi ); 1285 1286 // covers of tested functions 1287 virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints, 1288 const vector<vector<Point2f> >& imagePoints1, 1289 const vector<vector<Point2f> >& imagePoints2, 1290 Mat& cameraMatrix1, Mat& distCoeffs1, 1291 Mat& cameraMatrix2, Mat& distCoeffs2, 1292 Size imageSize, Mat& R, Mat& T, 1293 Mat& E, Mat& F, TermCriteria criteria, int flags ) = 0; 1294 virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1, 1295 const Mat& cameraMatrix2, const Mat& distCoeffs2, 1296 Size imageSize, const Mat& R, const Mat& T, 1297 Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q, 1298 double alpha, Size newImageSize, 1299 Rect* validPixROI1, Rect* validPixROI2, int flags ) = 0; 1300 virtual bool rectifyUncalibrated( const Mat& points1, 1301 const Mat& points2, const Mat& F, Size imgSize, 1302 Mat& H1, Mat& H2, double threshold=5 ) = 0; 1303 virtual void triangulate( const Mat& P1, const Mat& P2, 1304 const Mat &points1, const Mat &points2, 1305 Mat &points4D ) = 0; 1306 virtual void correct( const Mat& F, 1307 const Mat &points1, const Mat &points2, 1308 Mat &newPoints1, Mat &newPoints2 ) = 0; 1309 1310 void run(int); 1311 }; 1312 1313 1314 CV_StereoCalibrationTest::CV_StereoCalibrationTest() 1315 { 1316 } 1317 1318 1319 CV_StereoCalibrationTest::~CV_StereoCalibrationTest() 1320 { 1321 clear(); 1322 } 1323 1324 void CV_StereoCalibrationTest::clear() 1325 { 1326 cvtest::BaseTest::clear(); 1327 } 1328 1329 bool CV_StereoCalibrationTest::checkPandROI( int test_case_idx, const Mat& M, const Mat& D, const Mat& R, 1330 const Mat& P, Size imgsize, Rect roi ) 1331 { 1332 const double eps = 0.05; 1333 const int N = 21; 1334 int x, y, k; 1335 vector<Point2f> pts, upts; 1336 1337 // step 1. check that all the original points belong to the destination image 1338 for( y = 0; y < N; y++ ) 1339 for( x = 0; x < N; x++ ) 1340 pts.push_back(Point2f((float)x*imgsize.width/(N-1), (float)y*imgsize.height/(N-1))); 1341 1342 undistortPoints(Mat(pts), upts, M, D, R, P ); 1343 for( k = 0; k < N*N; k++ ) 1344 if( upts[k].x < -imgsize.width*eps || upts[k].x > imgsize.width*(1+eps) || 1345 upts[k].y < -imgsize.height*eps || upts[k].y > imgsize.height*(1+eps) ) 1346 { 1347 ts->printf(cvtest::TS::LOG, "Test #%d. The point (%g, %g) was mapped to (%g, %g) which is out of image\n", 1348 test_case_idx, pts[k].x, pts[k].y, upts[k].x, upts[k].y); 1349 return false; 1350 } 1351 1352 // step 2. check that all the points inside ROI belong to the original source image 1353 Mat temp(imgsize, CV_8U), utemp, map1, map2; 1354 temp = Scalar::all(1); 1355 initUndistortRectifyMap(M, D, R, P, imgsize, CV_16SC2, map1, map2); 1356 remap(temp, utemp, map1, map2, INTER_LINEAR); 1357 1358 if(roi.x < 0 || roi.y < 0 || roi.x + roi.width > imgsize.width || roi.y + roi.height > imgsize.height) 1359 { 1360 ts->printf(cvtest::TS::LOG, "Test #%d. The ROI=(%d, %d, %d, %d) is outside of the imge rectangle\n", 1361 test_case_idx, roi.x, roi.y, roi.width, roi.height); 1362 return false; 1363 } 1364 double s = sum(utemp(roi))[0]; 1365 if( s > roi.area() || roi.area() - s > roi.area()*(1-eps) ) 1366 { 1367 ts->printf(cvtest::TS::LOG, "Test #%d. The ratio of black pixels inside the valid ROI (~%g%%) is too large\n", 1368 test_case_idx, s*100./roi.area()); 1369 return false; 1370 } 1371 1372 return true; 1373 } 1374 1375 void CV_StereoCalibrationTest::run( int ) 1376 { 1377 const int ntests = 1; 1378 const double maxReprojErr = 2; 1379 const double maxScanlineDistErr_c = 3; 1380 const double maxScanlineDistErr_uc = 4; 1381 FILE* f = 0; 1382 1383 for(int testcase = 1; testcase <= ntests; testcase++) 1384 { 1385 cv::String filepath; 1386 char buf[1000]; 1387 filepath = cv::format("%scv/stereo/case%d/stereo_calib.txt", ts->get_data_path().c_str(), testcase ); 1388 f = fopen(filepath.c_str(), "rt"); 1389 Size patternSize; 1390 vector<string> imglist; 1391 1392 if( !f || !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &patternSize.width, &patternSize.height) != 2 ) 1393 { 1394 ts->printf( cvtest::TS::LOG, "The file %s can not be opened or has invalid content\n", filepath.c_str() ); 1395 ts->set_failed_test_info( f ? cvtest::TS::FAIL_INVALID_TEST_DATA : cvtest::TS::FAIL_MISSING_TEST_DATA ); 1396 fclose(f); 1397 return; 1398 } 1399 1400 for(;;) 1401 { 1402 if( !fgets( buf, sizeof(buf)-3, f )) 1403 break; 1404 size_t len = strlen(buf); 1405 while( len > 0 && isspace(buf[len-1])) 1406 buf[--len] = '\0'; 1407 if( buf[0] == '#') 1408 continue; 1409 filepath = cv::format("%scv/stereo/case%d/%s", ts->get_data_path().c_str(), testcase, buf ); 1410 imglist.push_back(string(filepath)); 1411 } 1412 fclose(f); 1413 1414 if( imglist.size() == 0 || imglist.size() % 2 != 0 ) 1415 { 1416 ts->printf( cvtest::TS::LOG, "The number of images is 0 or an odd number in the case #%d\n", testcase ); 1417 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); 1418 return; 1419 } 1420 1421 int nframes = (int)(imglist.size()/2); 1422 int npoints = patternSize.width*patternSize.height; 1423 vector<vector<Point3f> > objpt(nframes); 1424 vector<vector<Point2f> > imgpt1(nframes); 1425 vector<vector<Point2f> > imgpt2(nframes); 1426 Size imgsize; 1427 int total = 0; 1428 1429 for( int i = 0; i < nframes; i++ ) 1430 { 1431 Mat left = imread(imglist[i*2]); 1432 Mat right = imread(imglist[i*2+1]); 1433 if(left.empty() || right.empty()) 1434 { 1435 ts->printf( cvtest::TS::LOG, "Can not load images %s and %s, testcase %d\n", 1436 imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase ); 1437 ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA ); 1438 return; 1439 } 1440 imgsize = left.size(); 1441 bool found1 = findChessboardCorners(left, patternSize, imgpt1[i]); 1442 bool found2 = findChessboardCorners(right, patternSize, imgpt2[i]); 1443 if(!found1 || !found2) 1444 { 1445 ts->printf( cvtest::TS::LOG, "The function could not detect boards on the images %s and %s, testcase %d\n", 1446 imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase ); 1447 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 1448 return; 1449 } 1450 total += (int)imgpt1[i].size(); 1451 for( int j = 0; j < npoints; j++ ) 1452 objpt[i].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f)); 1453 } 1454 1455 // rectify (calibrated) 1456 Mat M1 = Mat::eye(3,3,CV_64F), M2 = Mat::eye(3,3,CV_64F), D1(5,1,CV_64F), D2(5,1,CV_64F), R, T, E, F; 1457 M1.at<double>(0,2) = M2.at<double>(0,2)=(imgsize.width-1)*0.5; 1458 M1.at<double>(1,2) = M2.at<double>(1,2)=(imgsize.height-1)*0.5; 1459 D1 = Scalar::all(0); 1460 D2 = Scalar::all(0); 1461 double err = calibrateStereoCamera(objpt, imgpt1, imgpt2, M1, D1, M2, D2, imgsize, R, T, E, F, 1462 TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6), 1463 CV_CALIB_SAME_FOCAL_LENGTH 1464 //+ CV_CALIB_FIX_ASPECT_RATIO 1465 + CV_CALIB_FIX_PRINCIPAL_POINT 1466 + CV_CALIB_ZERO_TANGENT_DIST 1467 + CV_CALIB_FIX_K3 1468 + CV_CALIB_FIX_K4 + CV_CALIB_FIX_K5 //+ CV_CALIB_FIX_K6 1469 ); 1470 err /= nframes*npoints; 1471 if( err > maxReprojErr ) 1472 { 1473 ts->printf( cvtest::TS::LOG, "The average reprojection error is too big (=%g), testcase %d\n", err, testcase); 1474 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 1475 return; 1476 } 1477 1478 Mat R1, R2, P1, P2, Q; 1479 Rect roi1, roi2; 1480 rectify(M1, D1, M2, D2, imgsize, R, T, R1, R2, P1, P2, Q, 1, imgsize, &roi1, &roi2, 0); 1481 Mat eye33 = Mat::eye(3,3,CV_64F); 1482 Mat R1t = R1.t(), R2t = R2.t(); 1483 1484 if( cvtest::norm(R1t*R1 - eye33, NORM_L2) > 0.01 || 1485 cvtest::norm(R2t*R2 - eye33, NORM_L2) > 0.01 || 1486 abs(determinant(F)) > 0.01) 1487 { 1488 ts->printf( cvtest::TS::LOG, "The computed (by rectify) R1 and R2 are not orthogonal," 1489 "or the computed (by calibrate) F is not singular, testcase %d\n", testcase); 1490 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 1491 return; 1492 } 1493 1494 if(!checkPandROI(testcase, M1, D1, R1, P1, imgsize, roi1)) 1495 { 1496 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); 1497 return; 1498 } 1499 1500 if(!checkPandROI(testcase, M2, D2, R2, P2, imgsize, roi2)) 1501 { 1502 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); 1503 return; 1504 } 1505 1506 //check that Tx after rectification is equal to distance between cameras 1507 double tx = fabs(P2.at<double>(0, 3) / P2.at<double>(0, 0)); 1508 if (fabs(tx - cvtest::norm(T, NORM_L2)) > 1e-5) 1509 { 1510 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); 1511 return; 1512 } 1513 1514 //check that Q reprojects points before the camera 1515 double testPoint[4] = {0.0, 0.0, 100.0, 1.0}; 1516 Mat reprojectedTestPoint = Q * Mat_<double>(4, 1, testPoint); 1517 CV_Assert(reprojectedTestPoint.type() == CV_64FC1); 1518 if( reprojectedTestPoint.at<double>(2) / reprojectedTestPoint.at<double>(3) < 0 ) 1519 { 1520 ts->printf( cvtest::TS::LOG, "A point after rectification is reprojected behind the camera, testcase %d\n", testcase); 1521 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 1522 } 1523 1524 //check that Q reprojects the same points as reconstructed by triangulation 1525 const float minCoord = -300.0f; 1526 const float maxCoord = 300.0f; 1527 const float minDisparity = 0.1f; 1528 const float maxDisparity = 600.0f; 1529 const int pointsCount = 500; 1530 const float requiredAccuracy = 1e-3f; 1531 RNG& rng = ts->get_rng(); 1532 1533 Mat projectedPoints_1(2, pointsCount, CV_32FC1); 1534 Mat projectedPoints_2(2, pointsCount, CV_32FC1); 1535 Mat disparities(1, pointsCount, CV_32FC1); 1536 1537 rng.fill(projectedPoints_1, RNG::UNIFORM, minCoord, maxCoord); 1538 rng.fill(disparities, RNG::UNIFORM, minDisparity, maxDisparity); 1539 projectedPoints_2.row(0) = projectedPoints_1.row(0) - disparities; 1540 Mat ys_2 = projectedPoints_2.row(1); 1541 projectedPoints_1.row(1).copyTo(ys_2); 1542 1543 Mat points4d; 1544 triangulate(P1, P2, projectedPoints_1, projectedPoints_2, points4d); 1545 Mat homogeneousPoints4d = points4d.t(); 1546 const int dimension = 4; 1547 homogeneousPoints4d = homogeneousPoints4d.reshape(dimension); 1548 Mat triangulatedPoints; 1549 convertPointsFromHomogeneous(homogeneousPoints4d, triangulatedPoints); 1550 1551 Mat sparsePoints; 1552 sparsePoints.push_back(projectedPoints_1); 1553 sparsePoints.push_back(disparities); 1554 sparsePoints = sparsePoints.t(); 1555 sparsePoints = sparsePoints.reshape(3); 1556 Mat reprojectedPoints; 1557 perspectiveTransform(sparsePoints, reprojectedPoints, Q); 1558 1559 if (cvtest::norm(triangulatedPoints, reprojectedPoints, NORM_L2) / sqrt((double)pointsCount) > requiredAccuracy) 1560 { 1561 ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different, testcase %d\n", testcase); 1562 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 1563 } 1564 1565 //check correctMatches 1566 const float constraintAccuracy = 1e-5f; 1567 Mat newPoints1, newPoints2; 1568 Mat points1 = projectedPoints_1.t(); 1569 points1 = points1.reshape(2, 1); 1570 Mat points2 = projectedPoints_2.t(); 1571 points2 = points2.reshape(2, 1); 1572 correctMatches(F, points1, points2, newPoints1, newPoints2); 1573 Mat newHomogeneousPoints1, newHomogeneousPoints2; 1574 convertPointsToHomogeneous(newPoints1, newHomogeneousPoints1); 1575 convertPointsToHomogeneous(newPoints2, newHomogeneousPoints2); 1576 newHomogeneousPoints1 = newHomogeneousPoints1.reshape(1); 1577 newHomogeneousPoints2 = newHomogeneousPoints2.reshape(1); 1578 Mat typedF; 1579 F.convertTo(typedF, newHomogeneousPoints1.type()); 1580 for (int i = 0; i < newHomogeneousPoints1.rows; ++i) 1581 { 1582 Mat error = newHomogeneousPoints2.row(i) * typedF * newHomogeneousPoints1.row(i).t(); 1583 CV_Assert(error.rows == 1 && error.cols == 1); 1584 if (cvtest::norm(error, NORM_L2) > constraintAccuracy) 1585 { 1586 ts->printf( cvtest::TS::LOG, "Epipolar constraint is violated after correctMatches, testcase %d\n", testcase); 1587 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 1588 } 1589 } 1590 1591 // rectifyUncalibrated 1592 CV_Assert( imgpt1.size() == imgpt2.size() ); 1593 Mat _imgpt1( total, 1, CV_32FC2 ), _imgpt2( total, 1, CV_32FC2 ); 1594 vector<vector<Point2f> >::const_iterator iit1 = imgpt1.begin(); 1595 vector<vector<Point2f> >::const_iterator iit2 = imgpt2.begin(); 1596 for( int pi = 0; iit1 != imgpt1.end(); ++iit1, ++iit2 ) 1597 { 1598 vector<Point2f>::const_iterator pit1 = iit1->begin(); 1599 vector<Point2f>::const_iterator pit2 = iit2->begin(); 1600 CV_Assert( iit1->size() == iit2->size() ); 1601 for( ; pit1 != iit1->end(); ++pit1, ++pit2, pi++ ) 1602 { 1603 _imgpt1.at<Point2f>(pi,0) = Point2f( pit1->x, pit1->y ); 1604 _imgpt2.at<Point2f>(pi,0) = Point2f( pit2->x, pit2->y ); 1605 } 1606 } 1607 1608 Mat _M1, _M2, _D1, _D2; 1609 vector<Mat> _R1, _R2, _T1, _T2; 1610 calibrateCamera( objpt, imgpt1, imgsize, _M1, _D1, _R1, _T1, 0 ); 1611 calibrateCamera( objpt, imgpt2, imgsize, _M2, _D2, _R2, _T2, 0 ); 1612 undistortPoints( _imgpt1, _imgpt1, _M1, _D1, Mat(), _M1 ); 1613 undistortPoints( _imgpt2, _imgpt2, _M2, _D2, Mat(), _M2 ); 1614 1615 Mat matF, _H1, _H2; 1616 matF = findFundamentalMat( _imgpt1, _imgpt2 ); 1617 rectifyUncalibrated( _imgpt1, _imgpt2, matF, imgsize, _H1, _H2 ); 1618 1619 Mat rectifPoints1, rectifPoints2; 1620 perspectiveTransform( _imgpt1, rectifPoints1, _H1 ); 1621 perspectiveTransform( _imgpt2, rectifPoints2, _H2 ); 1622 1623 bool verticalStereo = abs(P2.at<double>(0,3)) < abs(P2.at<double>(1,3)); 1624 double maxDiff_c = 0, maxDiff_uc = 0; 1625 for( int i = 0, k = 0; i < nframes; i++ ) 1626 { 1627 vector<Point2f> temp[2]; 1628 undistortPoints(Mat(imgpt1[i]), temp[0], M1, D1, R1, P1); 1629 undistortPoints(Mat(imgpt2[i]), temp[1], M2, D2, R2, P2); 1630 1631 for( int j = 0; j < npoints; j++, k++ ) 1632 { 1633 double diff_c = verticalStereo ? abs(temp[0][j].x - temp[1][j].x) : abs(temp[0][j].y - temp[1][j].y); 1634 Point2f d = rectifPoints1.at<Point2f>(k,0) - rectifPoints2.at<Point2f>(k,0); 1635 double diff_uc = verticalStereo ? abs(d.x) : abs(d.y); 1636 maxDiff_c = max(maxDiff_c, diff_c); 1637 maxDiff_uc = max(maxDiff_uc, diff_uc); 1638 if( maxDiff_c > maxScanlineDistErr_c ) 1639 { 1640 ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used calibrated stereo), testcase %d\n", 1641 verticalStereo ? "x" : "y", diff_c, testcase); 1642 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); 1643 return; 1644 } 1645 if( maxDiff_uc > maxScanlineDistErr_uc ) 1646 { 1647 ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used uncalibrated stereo), testcase %d\n", 1648 verticalStereo ? "x" : "y", diff_uc, testcase); 1649 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); 1650 return; 1651 } 1652 } 1653 } 1654 1655 ts->printf( cvtest::TS::LOG, "Testcase %d. Max distance (calibrated) =%g\n" 1656 "Max distance (uncalibrated) =%g\n", testcase, maxDiff_c, maxDiff_uc ); 1657 } 1658 } 1659 1660 //-------------------------------- CV_StereoCalibrationTest_C ------------------------------ 1661 1662 class CV_StereoCalibrationTest_C : public CV_StereoCalibrationTest 1663 { 1664 public: 1665 CV_StereoCalibrationTest_C() {} 1666 protected: 1667 virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints, 1668 const vector<vector<Point2f> >& imagePoints1, 1669 const vector<vector<Point2f> >& imagePoints2, 1670 Mat& cameraMatrix1, Mat& distCoeffs1, 1671 Mat& cameraMatrix2, Mat& distCoeffs2, 1672 Size imageSize, Mat& R, Mat& T, 1673 Mat& E, Mat& F, TermCriteria criteria, int flags ); 1674 virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1, 1675 const Mat& cameraMatrix2, const Mat& distCoeffs2, 1676 Size imageSize, const Mat& R, const Mat& T, 1677 Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q, 1678 double alpha, Size newImageSize, 1679 Rect* validPixROI1, Rect* validPixROI2, int flags ); 1680 virtual bool rectifyUncalibrated( const Mat& points1, 1681 const Mat& points2, const Mat& F, Size imgSize, 1682 Mat& H1, Mat& H2, double threshold=5 ); 1683 virtual void triangulate( const Mat& P1, const Mat& P2, 1684 const Mat &points1, const Mat &points2, 1685 Mat &points4D ); 1686 virtual void correct( const Mat& F, 1687 const Mat &points1, const Mat &points2, 1688 Mat &newPoints1, Mat &newPoints2 ); 1689 }; 1690 1691 double CV_StereoCalibrationTest_C::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints, 1692 const vector<vector<Point2f> >& imagePoints1, 1693 const vector<vector<Point2f> >& imagePoints2, 1694 Mat& cameraMatrix1, Mat& distCoeffs1, 1695 Mat& cameraMatrix2, Mat& distCoeffs2, 1696 Size imageSize, Mat& R, Mat& T, 1697 Mat& E, Mat& F, TermCriteria criteria, int flags ) 1698 { 1699 cameraMatrix1.create( 3, 3, CV_64F ); 1700 cameraMatrix2.create( 3, 3, CV_64F); 1701 distCoeffs1.create( 1, 5, CV_64F); 1702 distCoeffs2.create( 1, 5, CV_64F); 1703 R.create(3, 3, CV_64F); 1704 T.create(3, 1, CV_64F); 1705 E.create(3, 3, CV_64F); 1706 F.create(3, 3, CV_64F); 1707 1708 int nimages = (int)objectPoints.size(), total = 0; 1709 for( int i = 0; i < nimages; i++ ) 1710 { 1711 total += (int)objectPoints[i].size(); 1712 } 1713 1714 Mat npoints( 1, nimages, CV_32S ), 1715 objPt( 1, total, DataType<Point3f>::type ), 1716 imgPt( 1, total, DataType<Point2f>::type ), 1717 imgPt2( 1, total, DataType<Point2f>::type ); 1718 1719 Point2f* imgPtData2 = imgPt2.ptr<Point2f>(); 1720 Point3f* objPtData = objPt.ptr<Point3f>(); 1721 Point2f* imgPtData = imgPt.ptr<Point2f>(); 1722 for( int i = 0, ni = 0, j = 0; i < nimages; i++, j += ni ) 1723 { 1724 ni = (int)objectPoints[i].size(); 1725 npoints.ptr<int>()[i] = ni; 1726 std::copy(objectPoints[i].begin(), objectPoints[i].end(), objPtData + j); 1727 std::copy(imagePoints1[i].begin(), imagePoints1[i].end(), imgPtData + j); 1728 std::copy(imagePoints2[i].begin(), imagePoints2[i].end(), imgPtData2 + j); 1729 } 1730 CvMat _objPt = objPt, _imgPt = imgPt, _imgPt2 = imgPt2, _npoints = npoints; 1731 CvMat _cameraMatrix1 = cameraMatrix1, _distCoeffs1 = distCoeffs1; 1732 CvMat _cameraMatrix2 = cameraMatrix2, _distCoeffs2 = distCoeffs2; 1733 CvMat matR = R, matT = T, matE = E, matF = F; 1734 1735 return cvStereoCalibrate(&_objPt, &_imgPt, &_imgPt2, &_npoints, &_cameraMatrix1, 1736 &_distCoeffs1, &_cameraMatrix2, &_distCoeffs2, imageSize, 1737 &matR, &matT, &matE, &matF, flags, criteria ); 1738 } 1739 1740 void CV_StereoCalibrationTest_C::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1, 1741 const Mat& cameraMatrix2, const Mat& distCoeffs2, 1742 Size imageSize, const Mat& R, const Mat& T, 1743 Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q, 1744 double alpha, Size newImageSize, 1745 Rect* validPixROI1, Rect* validPixROI2, int flags ) 1746 { 1747 int rtype = CV_64F; 1748 R1.create(3, 3, rtype); 1749 R2.create(3, 3, rtype); 1750 P1.create(3, 4, rtype); 1751 P2.create(3, 4, rtype); 1752 Q.create(4, 4, rtype); 1753 CvMat _cameraMatrix1 = cameraMatrix1, _distCoeffs1 = distCoeffs1; 1754 CvMat _cameraMatrix2 = cameraMatrix2, _distCoeffs2 = distCoeffs2; 1755 CvMat matR = R, matT = T, _R1 = R1, _R2 = R2, _P1 = P1, _P2 = P2, matQ = Q; 1756 cvStereoRectify( &_cameraMatrix1, &_cameraMatrix2, &_distCoeffs1, &_distCoeffs2, 1757 imageSize, &matR, &matT, &_R1, &_R2, &_P1, &_P2, &matQ, flags, 1758 alpha, newImageSize, (CvRect*)validPixROI1, (CvRect*)validPixROI2); 1759 } 1760 1761 bool CV_StereoCalibrationTest_C::rectifyUncalibrated( const Mat& points1, 1762 const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold ) 1763 { 1764 H1.create(3, 3, CV_64F); 1765 H2.create(3, 3, CV_64F); 1766 CvMat _pt1 = points1, _pt2 = points2, matF, *pF=0, _H1 = H1, _H2 = H2; 1767 if( F.size() == Size(3, 3) ) 1768 pF = &(matF = F); 1769 return cvStereoRectifyUncalibrated(&_pt1, &_pt2, pF, imgSize, &_H1, &_H2, threshold) > 0; 1770 } 1771 1772 void CV_StereoCalibrationTest_C::triangulate( const Mat& P1, const Mat& P2, 1773 const Mat &points1, const Mat &points2, 1774 Mat &points4D ) 1775 { 1776 CvMat _P1 = P1, _P2 = P2, _points1 = points1, _points2 = points2; 1777 points4D.create(4, points1.cols, points1.type()); 1778 CvMat _points4D = points4D; 1779 cvTriangulatePoints(&_P1, &_P2, &_points1, &_points2, &_points4D); 1780 } 1781 1782 void CV_StereoCalibrationTest_C::correct( const Mat& F, 1783 const Mat &points1, const Mat &points2, 1784 Mat &newPoints1, Mat &newPoints2 ) 1785 { 1786 CvMat _F = F, _points1 = points1, _points2 = points2; 1787 newPoints1.create(1, points1.cols, points1.type()); 1788 newPoints2.create(1, points2.cols, points2.type()); 1789 CvMat _newPoints1 = newPoints1, _newPoints2 = newPoints2; 1790 cvCorrectMatches(&_F, &_points1, &_points2, &_newPoints1, &_newPoints2); 1791 } 1792 1793 //-------------------------------- CV_StereoCalibrationTest_CPP ------------------------------ 1794 1795 class CV_StereoCalibrationTest_CPP : public CV_StereoCalibrationTest 1796 { 1797 public: 1798 CV_StereoCalibrationTest_CPP() {} 1799 protected: 1800 virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints, 1801 const vector<vector<Point2f> >& imagePoints1, 1802 const vector<vector<Point2f> >& imagePoints2, 1803 Mat& cameraMatrix1, Mat& distCoeffs1, 1804 Mat& cameraMatrix2, Mat& distCoeffs2, 1805 Size imageSize, Mat& R, Mat& T, 1806 Mat& E, Mat& F, TermCriteria criteria, int flags ); 1807 virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1, 1808 const Mat& cameraMatrix2, const Mat& distCoeffs2, 1809 Size imageSize, const Mat& R, const Mat& T, 1810 Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q, 1811 double alpha, Size newImageSize, 1812 Rect* validPixROI1, Rect* validPixROI2, int flags ); 1813 virtual bool rectifyUncalibrated( const Mat& points1, 1814 const Mat& points2, const Mat& F, Size imgSize, 1815 Mat& H1, Mat& H2, double threshold=5 ); 1816 virtual void triangulate( const Mat& P1, const Mat& P2, 1817 const Mat &points1, const Mat &points2, 1818 Mat &points4D ); 1819 virtual void correct( const Mat& F, 1820 const Mat &points1, const Mat &points2, 1821 Mat &newPoints1, Mat &newPoints2 ); 1822 }; 1823 1824 double CV_StereoCalibrationTest_CPP::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints, 1825 const vector<vector<Point2f> >& imagePoints1, 1826 const vector<vector<Point2f> >& imagePoints2, 1827 Mat& cameraMatrix1, Mat& distCoeffs1, 1828 Mat& cameraMatrix2, Mat& distCoeffs2, 1829 Size imageSize, Mat& R, Mat& T, 1830 Mat& E, Mat& F, TermCriteria criteria, int flags ) 1831 { 1832 return stereoCalibrate( objectPoints, imagePoints1, imagePoints2, 1833 cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, 1834 imageSize, R, T, E, F, flags, criteria ); 1835 } 1836 1837 void CV_StereoCalibrationTest_CPP::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1, 1838 const Mat& cameraMatrix2, const Mat& distCoeffs2, 1839 Size imageSize, const Mat& R, const Mat& T, 1840 Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q, 1841 double alpha, Size newImageSize, 1842 Rect* validPixROI1, Rect* validPixROI2, int flags ) 1843 { 1844 stereoRectify( cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, 1845 imageSize, R, T, R1, R2, P1, P2, Q, flags, alpha, newImageSize,validPixROI1, validPixROI2 ); 1846 } 1847 1848 bool CV_StereoCalibrationTest_CPP::rectifyUncalibrated( const Mat& points1, 1849 const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold ) 1850 { 1851 return stereoRectifyUncalibrated( points1, points2, F, imgSize, H1, H2, threshold ); 1852 } 1853 1854 void CV_StereoCalibrationTest_CPP::triangulate( const Mat& P1, const Mat& P2, 1855 const Mat &points1, const Mat &points2, 1856 Mat &points4D ) 1857 { 1858 triangulatePoints(P1, P2, points1, points2, points4D); 1859 } 1860 1861 void CV_StereoCalibrationTest_CPP::correct( const Mat& F, 1862 const Mat &points1, const Mat &points2, 1863 Mat &newPoints1, Mat &newPoints2 ) 1864 { 1865 correctMatches(F, points1, points2, newPoints1, newPoints2); 1866 } 1867 1868 /////////////////////////////////////////////////////////////////////////////////////////////////// 1869 1870 TEST(Calib3d_CalibrateCamera_C, regression) { CV_CameraCalibrationTest_C test; test.safe_run(); } 1871 TEST(Calib3d_CalibrateCamera_CPP, regression) { CV_CameraCalibrationTest_CPP test; test.safe_run(); } 1872 TEST(Calib3d_CalibrationMatrixValues_C, accuracy) { CV_CalibrationMatrixValuesTest_C test; test.safe_run(); } 1873 TEST(Calib3d_CalibrationMatrixValues_CPP, accuracy) { CV_CalibrationMatrixValuesTest_CPP test; test.safe_run(); } 1874 TEST(Calib3d_ProjectPoints_C, accuracy) { CV_ProjectPointsTest_C test; test.safe_run(); } 1875 TEST(Calib3d_ProjectPoints_CPP, regression) { CV_ProjectPointsTest_CPP test; test.safe_run(); } 1876 TEST(Calib3d_StereoCalibrate_C, regression) { CV_StereoCalibrationTest_C test; test.safe_run(); } 1877 TEST(Calib3d_StereoCalibrate_CPP, regression) { CV_StereoCalibrationTest_CPP test; test.safe_run(); } 1878 1879 1880 TEST(Calib3d_Triangulate, accuracy) 1881 { 1882 // the testcase from http://code.opencv.org/issues/4334 1883 { 1884 double P1data[] = { 250, 0, 200, 0, 0, 250, 150, 0, 0, 0, 1, 0 }; 1885 double P2data[] = { 250, 0, 200, -250, 0, 250, 150, 0, 0, 0, 1, 0 }; 1886 Mat P1(3, 4, CV_64F, P1data), P2(3, 4, CV_64F, P2data); 1887 1888 float x1data[] = { 200.f, 0.f }; 1889 float x2data[] = { 170.f, 1.f }; 1890 float Xdata[] = { 0.f, -5.f, 25/3.f }; 1891 Mat x1(2, 1, CV_32F, x1data); 1892 Mat x2(2, 1, CV_32F, x2data); 1893 Mat res0(1, 3, CV_32F, Xdata); 1894 Mat res_, res; 1895 1896 triangulatePoints(P1, P2, x1, x2, res_); 1897 transpose(res_, res_); 1898 convertPointsFromHomogeneous(res_, res); 1899 res = res.reshape(1, 1); 1900 1901 cout << "[1]:" << endl; 1902 cout << "\tres0: " << res0 << endl; 1903 cout << "\tres: " << res << endl; 1904 1905 ASSERT_LE(norm(res, res0, NORM_INF), 1e-1); 1906 } 1907 1908 // another testcase http://code.opencv.org/issues/3461 1909 { 1910 Matx33d K1(6137.147949, 0.000000, 644.974609, 1911 0.000000, 6137.147949, 573.442749, 1912 0.000000, 0.000000, 1.000000); 1913 Matx33d K2(6137.147949, 0.000000, 644.674438, 1914 0.000000, 6137.147949, 573.079834, 1915 0.000000, 0.000000, 1.000000); 1916 1917 Matx34d RT1(1, 0, 0, 0, 1918 0, 1, 0, 0, 1919 0, 0, 1, 0); 1920 1921 Matx34d RT2(0.998297, 0.0064108, -0.0579766, 143.614334, 1922 -0.0065818, 0.999975, -0.00275888, -5.160085, 1923 0.0579574, 0.00313577, 0.998314, 96.066109); 1924 1925 Matx34d P1 = K1*RT1; 1926 Matx34d P2 = K2*RT2; 1927 1928 float x1data[] = { 438.f, 19.f }; 1929 float x2data[] = { 452.363600f, 16.452225f }; 1930 float Xdata[] = { -81.049530f, -215.702804f, 2401.645449f }; 1931 Mat x1(2, 1, CV_32F, x1data); 1932 Mat x2(2, 1, CV_32F, x2data); 1933 Mat res0(1, 3, CV_32F, Xdata); 1934 Mat res_, res; 1935 1936 triangulatePoints(P1, P2, x1, x2, res_); 1937 transpose(res_, res_); 1938 convertPointsFromHomogeneous(res_, res); 1939 res = res.reshape(1, 1); 1940 1941 cout << "[2]:" << endl; 1942 cout << "\tres0: " << res0 << endl; 1943 cout << "\tres: " << res << endl; 1944 1945 ASSERT_LE(norm(res, res0, NORM_INF), 2); 1946 } 1947 } 1948