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