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 // License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved. 15 // Third party copyrights are property of their respective owners. 16 // 17 // Redistribution and use in source and binary forms, with or without modification, 18 // are permitted provided that the following conditions are met: 19 // 20 // * Redistribution's of source code must retain the above copyright notice, 21 // this list of conditions and the following disclaimer. 22 // 23 // * Redistribution's in binary form must reproduce the above copyright notice, 24 // this list of conditions and the following disclaimer in the documentation 25 // and/or other materials provided with the distribution. 26 // 27 // * The name of the copyright holders may not be used to endorse or promote products 28 // derived from this software without specific prior written permission. 29 // 30 // This software is provided by the copyright holders and contributors "as is" and 31 // any express or implied warranties, including, but not limited to, the implied 32 // warranties of merchantability and fitness for a particular purpose are disclaimed. 33 // In no event shall the Intel Corporation or contributors be liable for any direct, 34 // indirect, incidental, special, exemplary, or consequential damages 35 // (including, but not limited to, procurement of substitute goods or services; 36 // loss of use, data, or profits; or business interruption) however caused 37 // and on any theory of liability, whether in contract, strict liability, 38 // or tort (including negligence or otherwise) arising in any way out of 39 // the use of this software, even if advised of the possibility of such damage. 40 // 41 //M*/ 42 43 #include "test_precomp.hpp" 44 45 using namespace cv; 46 using namespace std; 47 48 class CV_ECC_BaseTest : public cvtest::BaseTest 49 { 50 public: 51 CV_ECC_BaseTest(); 52 53 protected: 54 55 double computeRMS(const Mat& mat1, const Mat& mat2); 56 bool isMapCorrect(const Mat& mat); 57 58 59 double MAX_RMS_ECC;//upper bound for RMS error 60 int ntests;//number of tests per motion type 61 int ECC_iterations;//number of iterations for ECC 62 double ECC_epsilon; //we choose a negative value, so that 63 // ECC_iterations are always executed 64 }; 65 66 CV_ECC_BaseTest::CV_ECC_BaseTest() 67 { 68 MAX_RMS_ECC=0.1; 69 ntests = 3; 70 ECC_iterations = 50; 71 ECC_epsilon = -1; //-> negative value means that ECC_Iterations will be executed 72 } 73 74 75 bool CV_ECC_BaseTest::isMapCorrect(const Mat& map) 76 { 77 bool tr = true; 78 float mapVal; 79 for(int i =0; i<map.rows; i++) 80 for(int j=0; j<map.cols; j++){ 81 mapVal = map.at<float>(i, j); 82 tr = tr & (!cvIsNaN(mapVal) && (fabs(mapVal) < 1e9)); 83 } 84 85 return tr; 86 } 87 88 double CV_ECC_BaseTest::computeRMS(const Mat& mat1, const Mat& mat2){ 89 90 CV_Assert(mat1.rows == mat2.rows); 91 CV_Assert(mat1.cols == mat2.cols); 92 93 Mat errorMat; 94 subtract(mat1, mat2, errorMat); 95 96 return sqrt(errorMat.dot(errorMat)/(mat1.rows*mat1.cols)); 97 } 98 99 100 class CV_ECC_Test_Translation : public CV_ECC_BaseTest 101 { 102 public: 103 CV_ECC_Test_Translation(); 104 protected: 105 void run(int); 106 107 bool testTranslation(int); 108 }; 109 110 CV_ECC_Test_Translation::CV_ECC_Test_Translation(){} 111 112 bool CV_ECC_Test_Translation::testTranslation(int from) 113 { 114 Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0); 115 116 117 if (img.empty()) 118 { 119 ts->printf( ts->LOG, "test image can not be read"); 120 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); 121 return false; 122 } 123 Mat testImg; 124 resize(img, testImg, Size(216, 216)); 125 126 cv::RNG rng = ts->get_rng(); 127 128 int progress=0; 129 130 for (int k=from; k<ntests; k++){ 131 132 ts->update_context( this, k, true ); 133 progress = update_progress(progress, k, ntests, 0); 134 135 Mat translationGround = (Mat_<float>(2,3) << 1, 0, (rng.uniform(10.f, 20.f)), 136 0, 1, (rng.uniform(10.f, 20.f))); 137 138 Mat warpedImage; 139 140 warpAffine(testImg, warpedImage, translationGround, 141 Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP); 142 143 Mat mapTranslation = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0); 144 145 findTransformECC(warpedImage, testImg, mapTranslation, 0, 146 TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon)); 147 148 if (!isMapCorrect(mapTranslation)){ 149 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); 150 return false; 151 } 152 153 if (computeRMS(mapTranslation, translationGround)>MAX_RMS_ECC){ 154 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 155 ts->printf( ts->LOG, "RMS = %f", 156 computeRMS(mapTranslation, translationGround)); 157 return false; 158 } 159 160 } 161 return true; 162 } 163 164 void CV_ECC_Test_Translation::run(int from) 165 { 166 167 if (!testTranslation(from)) 168 return; 169 170 ts->set_failed_test_info(cvtest::TS::OK); 171 } 172 173 174 175 class CV_ECC_Test_Euclidean : public CV_ECC_BaseTest 176 { 177 public: 178 CV_ECC_Test_Euclidean(); 179 protected: 180 void run(int); 181 182 bool testEuclidean(int); 183 }; 184 185 CV_ECC_Test_Euclidean::CV_ECC_Test_Euclidean() { } 186 187 bool CV_ECC_Test_Euclidean::testEuclidean(int from) 188 { 189 Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0); 190 191 192 if (img.empty()) 193 { 194 ts->printf( ts->LOG, "test image can not be read"); 195 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); 196 return false; 197 } 198 Mat testImg; 199 resize(img, testImg, Size(216, 216)); 200 201 cv::RNG rng = ts->get_rng(); 202 203 int progress = 0; 204 for (int k=from; k<ntests; k++){ 205 ts->update_context( this, k, true ); 206 progress = update_progress(progress, k, ntests, 0); 207 208 double angle = CV_PI/30 + CV_PI*rng.uniform((double)-2.f, (double)2.f)/180; 209 210 Mat euclideanGround = (Mat_<float>(2,3) << cos(angle), -sin(angle), (rng.uniform(10.f, 20.f)), 211 sin(angle), cos(angle), (rng.uniform(10.f, 20.f))); 212 213 Mat warpedImage; 214 215 warpAffine(testImg, warpedImage, euclideanGround, 216 Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP); 217 218 Mat mapEuclidean = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0); 219 220 findTransformECC(warpedImage, testImg, mapEuclidean, 1, 221 TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon)); 222 223 if (!isMapCorrect(mapEuclidean)){ 224 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); 225 return false; 226 } 227 228 if (computeRMS(mapEuclidean, euclideanGround)>MAX_RMS_ECC){ 229 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 230 ts->printf( ts->LOG, "RMS = %f", 231 computeRMS(mapEuclidean, euclideanGround)); 232 return false; 233 } 234 235 } 236 return true; 237 } 238 239 240 void CV_ECC_Test_Euclidean::run(int from) 241 { 242 243 if (!testEuclidean(from)) 244 return; 245 246 ts->set_failed_test_info(cvtest::TS::OK); 247 } 248 249 class CV_ECC_Test_Affine : public CV_ECC_BaseTest 250 { 251 public: 252 CV_ECC_Test_Affine(); 253 protected: 254 void run(int); 255 256 bool testAffine(int); 257 }; 258 259 CV_ECC_Test_Affine::CV_ECC_Test_Affine(){} 260 261 262 bool CV_ECC_Test_Affine::testAffine(int from) 263 { 264 Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0); 265 266 if (img.empty()) 267 { 268 ts->printf( ts->LOG, "test image can not be read"); 269 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); 270 return false; 271 } 272 Mat testImg; 273 resize(img, testImg, Size(216, 216)); 274 275 cv::RNG rng = ts->get_rng(); 276 277 int progress = 0; 278 for (int k=from; k<ntests; k++){ 279 ts->update_context( this, k, true ); 280 progress = update_progress(progress, k, ntests, 0); 281 282 283 Mat affineGround = (Mat_<float>(2,3) << (1-rng.uniform(-0.05f, 0.05f)), 284 (rng.uniform(-0.03f, 0.03f)), (rng.uniform(10.f, 20.f)), 285 (rng.uniform(-0.03f, 0.03f)), (1-rng.uniform(-0.05f, 0.05f)), 286 (rng.uniform(10.f, 20.f))); 287 288 Mat warpedImage; 289 290 warpAffine(testImg, warpedImage, affineGround, 291 Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP); 292 293 Mat mapAffine = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0); 294 295 findTransformECC(warpedImage, testImg, mapAffine, 2, 296 TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon)); 297 298 if (!isMapCorrect(mapAffine)){ 299 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); 300 return false; 301 } 302 303 if (computeRMS(mapAffine, affineGround)>MAX_RMS_ECC){ 304 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 305 ts->printf( ts->LOG, "RMS = %f", 306 computeRMS(mapAffine, affineGround)); 307 return false; 308 } 309 310 } 311 312 return true; 313 } 314 315 316 void CV_ECC_Test_Affine::run(int from) 317 { 318 319 if (!testAffine(from)) 320 return; 321 322 ts->set_failed_test_info(cvtest::TS::OK); 323 } 324 325 class CV_ECC_Test_Homography : public CV_ECC_BaseTest 326 { 327 public: 328 CV_ECC_Test_Homography(); 329 protected: 330 void run(int); 331 332 bool testHomography(int); 333 }; 334 335 CV_ECC_Test_Homography::CV_ECC_Test_Homography(){} 336 337 bool CV_ECC_Test_Homography::testHomography(int from) 338 { 339 Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0); 340 341 342 if (img.empty()) 343 { 344 ts->printf( ts->LOG, "test image can not be read"); 345 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); 346 return false; 347 } 348 Mat testImg; 349 resize(img, testImg, Size(216, 216)); 350 351 cv::RNG rng = ts->get_rng(); 352 353 int progress = 0; 354 for (int k=from; k<ntests; k++){ 355 ts->update_context( this, k, true ); 356 progress = update_progress(progress, k, ntests, 0); 357 358 Mat homoGround = (Mat_<float>(3,3) << (1-rng.uniform(-0.05f, 0.05f)), 359 (rng.uniform(-0.03f, 0.03f)), (rng.uniform(10.f, 20.f)), 360 (rng.uniform(-0.03f, 0.03f)), (1-rng.uniform(-0.05f, 0.05f)),(rng.uniform(10.f, 20.f)), 361 (rng.uniform(0.0001f, 0.0003f)), (rng.uniform(0.0001f, 0.0003f)), 1.f); 362 363 Mat warpedImage; 364 365 warpPerspective(testImg, warpedImage, homoGround, 366 Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP); 367 368 Mat mapHomography = Mat::eye(3, 3, CV_32F); 369 370 findTransformECC(warpedImage, testImg, mapHomography, 3, 371 TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon)); 372 373 if (!isMapCorrect(mapHomography)){ 374 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); 375 return false; 376 } 377 378 if (computeRMS(mapHomography, homoGround)>MAX_RMS_ECC){ 379 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 380 ts->printf( ts->LOG, "RMS = %f", 381 computeRMS(mapHomography, homoGround)); 382 return false; 383 } 384 385 } 386 return true; 387 } 388 389 void CV_ECC_Test_Homography::run(int from) 390 { 391 if (!testHomography(from)) 392 return; 393 394 ts->set_failed_test_info(cvtest::TS::OK); 395 } 396 397 class CV_ECC_Test_Mask : public CV_ECC_BaseTest 398 { 399 public: 400 CV_ECC_Test_Mask(); 401 protected: 402 void run(int); 403 404 bool testMask(int); 405 }; 406 407 CV_ECC_Test_Mask::CV_ECC_Test_Mask(){} 408 409 bool CV_ECC_Test_Mask::testMask(int from) 410 { 411 Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0); 412 413 414 if (img.empty()) 415 { 416 ts->printf( ts->LOG, "test image can not be read"); 417 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); 418 return false; 419 } 420 Mat scaledImage; 421 resize(img, scaledImage, Size(216, 216)); 422 423 Mat_<float> testImg; 424 scaledImage.convertTo(testImg, testImg.type()); 425 426 cv::RNG rng = ts->get_rng(); 427 428 int progress=0; 429 430 for (int k=from; k<ntests; k++){ 431 432 ts->update_context( this, k, true ); 433 progress = update_progress(progress, k, ntests, 0); 434 435 Mat translationGround = (Mat_<float>(2,3) << 1, 0, (rng.uniform(10.f, 20.f)), 436 0, 1, (rng.uniform(10.f, 20.f))); 437 438 Mat warpedImage; 439 440 warpAffine(testImg, warpedImage, translationGround, 441 Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP); 442 443 Mat mapTranslation = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0); 444 445 Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols); 446 for (int i=testImg.rows*2/3; i<testImg.rows; i++) { 447 for (int j=testImg.cols*2/3; j<testImg.cols; j++) { 448 testImg(i, j) = 0; 449 mask(i, j) = 0; 450 } 451 } 452 453 findTransformECC(warpedImage, testImg, mapTranslation, 0, 454 TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon), mask); 455 456 if (!isMapCorrect(mapTranslation)){ 457 ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); 458 return false; 459 } 460 461 if (computeRMS(mapTranslation, translationGround)>MAX_RMS_ECC){ 462 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 463 ts->printf( ts->LOG, "RMS = %f", 464 computeRMS(mapTranslation, translationGround)); 465 return false; 466 } 467 468 } 469 return true; 470 } 471 472 void CV_ECC_Test_Mask::run(int from) 473 { 474 if (!testMask(from)) 475 return; 476 477 ts->set_failed_test_info(cvtest::TS::OK); 478 } 479 480 TEST(Video_ECC_Translation, accuracy) { CV_ECC_Test_Translation test; test.safe_run();} 481 TEST(Video_ECC_Euclidean, accuracy) { CV_ECC_Test_Euclidean test; test.safe_run(); } 482 TEST(Video_ECC_Affine, accuracy) { CV_ECC_Test_Affine test; test.safe_run(); } 483 TEST(Video_ECC_Homography, accuracy) { CV_ECC_Test_Homography test; test.safe_run(); } 484 TEST(Video_ECC_Mask, accuracy) { CV_ECC_Test_Mask test; test.safe_run(); } 485