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
CV_ECC_BaseTest()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
isMapCorrect(const Mat & map)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
computeRMS(const Mat & mat1,const Mat & mat2)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
CV_ECC_Test_Translation()110 CV_ECC_Test_Translation::CV_ECC_Test_Translation(){}
111
testTranslation(int from)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
run(int from)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
CV_ECC_Test_Euclidean()185 CV_ECC_Test_Euclidean::CV_ECC_Test_Euclidean() { }
186
testEuclidean(int from)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
run(int from)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
CV_ECC_Test_Affine()259 CV_ECC_Test_Affine::CV_ECC_Test_Affine(){}
260
261
testAffine(int from)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
run(int from)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
CV_ECC_Test_Homography()335 CV_ECC_Test_Homography::CV_ECC_Test_Homography(){}
336
testHomography(int from)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
run(int from)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
CV_ECC_Test_Mask()407 CV_ECC_Test_Mask::CV_ECC_Test_Mask(){}
408
testMask(int from)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
run(int from)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
TEST(Video_ECC_Translation,accuracy)480 TEST(Video_ECC_Translation, accuracy) { CV_ECC_Test_Translation test; test.safe_run();}
TEST(Video_ECC_Euclidean,accuracy)481 TEST(Video_ECC_Euclidean, accuracy) { CV_ECC_Test_Euclidean test; test.safe_run(); }
TEST(Video_ECC_Affine,accuracy)482 TEST(Video_ECC_Affine, accuracy) { CV_ECC_Test_Affine test; test.safe_run(); }
TEST(Video_ECC_Homography,accuracy)483 TEST(Video_ECC_Homography, accuracy) { CV_ECC_Test_Homography test; test.safe_run(); }
TEST(Video_ECC_Mask,accuracy)484 TEST(Video_ECC_Mask, accuracy) { CV_ECC_Test_Mask test; test.safe_run(); }
485