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/video/tracking_c.h"
44
45 using namespace cv;
46 using namespace std;
47
48 class CV_TrackBaseTest : public cvtest::BaseTest
49 {
50 public:
51 CV_TrackBaseTest();
52 virtual ~CV_TrackBaseTest();
53 void clear();
54
55 protected:
56 int read_params( CvFileStorage* fs );
57 void run_func(void);
58 int prepare_test_case( int test_case_idx );
59 int validate_test_results( int test_case_idx );
60 void generate_object();
61
62 int min_log_size, max_log_size;
63 CvMat* img;
64 CvBox2D box0;
65 CvSize img_size;
66 CvTermCriteria criteria;
67 int img_type;
68 };
69
70
CV_TrackBaseTest()71 CV_TrackBaseTest::CV_TrackBaseTest()
72 {
73 img = 0;
74 test_case_count = 100;
75 min_log_size = 5;
76 max_log_size = 8;
77 }
78
79
~CV_TrackBaseTest()80 CV_TrackBaseTest::~CV_TrackBaseTest()
81 {
82 clear();
83 }
84
85
clear()86 void CV_TrackBaseTest::clear()
87 {
88 cvReleaseMat( &img );
89 cvtest::BaseTest::clear();
90 }
91
92
read_params(CvFileStorage * fs)93 int CV_TrackBaseTest::read_params( CvFileStorage* fs )
94 {
95 int code = cvtest::BaseTest::read_params( fs );
96 if( code < 0 )
97 return code;
98
99 test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
100 min_log_size = cvReadInt( find_param( fs, "min_log_size" ), min_log_size );
101 max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size );
102
103 min_log_size = cvtest::clipInt( min_log_size, 1, 10 );
104 max_log_size = cvtest::clipInt( max_log_size, 1, 10 );
105 if( min_log_size > max_log_size )
106 {
107 int t;
108 CV_SWAP( min_log_size, max_log_size, t );
109 }
110
111 return 0;
112 }
113
114
generate_object()115 void CV_TrackBaseTest::generate_object()
116 {
117 int x, y;
118 double cx = box0.center.x;
119 double cy = box0.center.y;
120 double width = box0.size.width*0.5;
121 double height = box0.size.height*0.5;
122 double angle = box0.angle*CV_PI/180.;
123 double a = sin(angle), b = -cos(angle);
124 double inv_ww = 1./(width*width), inv_hh = 1./(height*height);
125
126 img = cvCreateMat( img_size.height, img_size.width, img_type );
127 cvZero( img );
128
129 // use the straightforward algorithm: for every pixel check if it is inside the ellipse
130 for( y = 0; y < img_size.height; y++ )
131 {
132 uchar* ptr = img->data.ptr + img->step*y;
133 float* fl = (float*)ptr;
134 double x_ = (y - cy)*b, y_ = (y - cy)*a;
135
136 for( x = 0; x < img_size.width; x++ )
137 {
138 double x1 = (x - cx)*a - x_;
139 double y1 = (x - cx)*b + y_;
140
141 if( x1*x1*inv_hh + y1*y1*inv_ww <= 1. )
142 {
143 if( img_type == CV_8U )
144 ptr[x] = (uchar)1;
145 else
146 fl[x] = (float)1.f;
147 }
148 }
149 }
150 }
151
152
prepare_test_case(int test_case_idx)153 int CV_TrackBaseTest::prepare_test_case( int test_case_idx )
154 {
155 RNG& rng = ts->get_rng();
156 cvtest::BaseTest::prepare_test_case( test_case_idx );
157 float m;
158
159 clear();
160
161 box0.size.width = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
162 box0.size.height = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
163 box0.angle = (float)(cvtest::randReal(rng)*180.);
164
165 if( box0.size.width > box0.size.height )
166 {
167 float t;
168 CV_SWAP( box0.size.width, box0.size.height, t );
169 }
170
171 m = MAX( box0.size.width, box0.size.height );
172 img_size.width = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
173 img_size.height = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
174 img_type = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U;
175 img_type = CV_8U;
176
177 box0.center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - m));
178 box0.center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - m));
179
180 criteria = cvTermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1 );
181
182 generate_object();
183
184 return 1;
185 }
186
187
run_func(void)188 void CV_TrackBaseTest::run_func(void)
189 {
190 }
191
192
validate_test_results(int)193 int CV_TrackBaseTest::validate_test_results( int /*test_case_idx*/ )
194 {
195 return 0;
196 }
197
198
199
200 ///////////////////////// CamShift //////////////////////////////
201
202 class CV_CamShiftTest : public CV_TrackBaseTest
203 {
204 public:
205 CV_CamShiftTest();
206
207 protected:
208 void run_func(void);
209 int prepare_test_case( int test_case_idx );
210 int validate_test_results( int test_case_idx );
211 void generate_object();
212
213 CvBox2D box;
214 CvRect init_rect;
215 CvConnectedComp comp;
216 int area0;
217 };
218
219
CV_CamShiftTest()220 CV_CamShiftTest::CV_CamShiftTest()
221 {
222 }
223
224
prepare_test_case(int test_case_idx)225 int CV_CamShiftTest::prepare_test_case( int test_case_idx )
226 {
227 RNG& rng = ts->get_rng();
228 double m;
229 int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
230 int i, area;
231
232 if( code <= 0 )
233 return code;
234
235 area0 = cvCountNonZero(img);
236
237 for(i = 0; i < 100; i++)
238 {
239 CvMat temp;
240
241 m = MAX(box0.size.width,box0.size.height)*0.8;
242 init_rect.x = cvFloor(box0.center.x - m*(0.45 + cvtest::randReal(rng)*0.2));
243 init_rect.y = cvFloor(box0.center.y - m*(0.45 + cvtest::randReal(rng)*0.2));
244 init_rect.width = cvCeil(box0.center.x + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.x);
245 init_rect.height = cvCeil(box0.center.y + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.y);
246
247 if( init_rect.x < 0 || init_rect.y < 0 ||
248 init_rect.x + init_rect.width >= img_size.width ||
249 init_rect.y + init_rect.height >= img_size.height )
250 continue;
251
252 cvGetSubRect( img, &temp, init_rect );
253 area = cvCountNonZero( &temp );
254
255 if( area >= 0.1*area0 )
256 break;
257 }
258
259 return i < 100 ? code : 0;
260 }
261
262
run_func(void)263 void CV_CamShiftTest::run_func(void)
264 {
265 cvCamShift( img, init_rect, criteria, &comp, &box );
266 }
267
268
validate_test_results(int)269 int CV_CamShiftTest::validate_test_results( int /*test_case_idx*/ )
270 {
271 int code = cvtest::TS::OK;
272
273 double m = MAX(box0.size.width, box0.size.height), delta;
274 double diff_angle;
275
276 if( cvIsNaN(box.size.width) || cvIsInf(box.size.width) || box.size.width <= 0 ||
277 cvIsNaN(box.size.height) || cvIsInf(box.size.height) || box.size.height <= 0 ||
278 cvIsNaN(box.center.x) || cvIsInf(box.center.x) ||
279 cvIsNaN(box.center.y) || cvIsInf(box.center.y) ||
280 cvIsNaN(box.angle) || cvIsInf(box.angle) || box.angle < -180 || box.angle > 180 ||
281 cvIsNaN(comp.area) || cvIsInf(comp.area) || comp.area <= 0 )
282 {
283 ts->printf( cvtest::TS::LOG, "Invalid CvBox2D or CvConnectedComp was returned by cvCamShift\n" );
284 code = cvtest::TS::FAIL_INVALID_OUTPUT;
285 goto _exit_;
286 }
287
288 box.angle = (float)(180 - box.angle);
289
290 if( fabs(box.size.width - box0.size.width) > box0.size.width*0.2 ||
291 fabs(box.size.height - box0.size.height) > box0.size.height*0.3 )
292 {
293 ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D size (=%.1f x %.1f, should be %.1f x %.1f)\n",
294 box.size.width, box.size.height, box0.size.width, box0.size.height );
295 code = cvtest::TS::FAIL_BAD_ACCURACY;
296 goto _exit_;
297 }
298
299 if( fabs(box.center.x - box0.center.x) > m*0.1 ||
300 fabs(box.center.y - box0.center.y) > m*0.1 )
301 {
302 ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
303 box.center.x, box.center.y, box0.center.x, box0.center.y );
304 code = cvtest::TS::FAIL_BAD_ACCURACY;
305 goto _exit_;
306 }
307
308 if( box.angle < 0 )
309 box.angle += 180;
310
311 diff_angle = fabs(box0.angle - box.angle);
312 diff_angle = MIN( diff_angle, fabs(box0.angle - box.angle + 180));
313
314 if( fabs(diff_angle) > 30 && box0.size.height > box0.size.width*1.2 )
315 {
316 ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D angle (=%1.f, should be %1.f)\n",
317 box.angle, box0.angle );
318 code = cvtest::TS::FAIL_BAD_ACCURACY;
319 goto _exit_;
320 }
321
322 delta = m*0.7;
323
324 if( comp.rect.x < box0.center.x - delta ||
325 comp.rect.y < box0.center.y - delta ||
326 comp.rect.x + comp.rect.width > box0.center.x + delta ||
327 comp.rect.y + comp.rect.height > box0.center.y + delta )
328 {
329 ts->printf( cvtest::TS::LOG,
330 "Incorrect CvConnectedComp ((%d,%d,%d,%d) is not within (%.1f,%.1f,%.1f,%.1f))\n",
331 comp.rect.x, comp.rect.y, comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height,
332 box0.center.x - delta, box0.center.y - delta, box0.center.x + delta, box0.center.y + delta );
333 code = cvtest::TS::FAIL_BAD_ACCURACY;
334 goto _exit_;
335 }
336
337 if( fabs(comp.area - area0) > area0*0.15 )
338 {
339 ts->printf( cvtest::TS::LOG,
340 "Incorrect CvConnectedComp area (=%.1f, should be %d)\n", comp.area, area0 );
341 code = cvtest::TS::FAIL_BAD_ACCURACY;
342 goto _exit_;
343 }
344
345 _exit_:
346
347 if( code < 0 )
348 {
349 #if 0 //defined _DEBUG && defined WIN32
350 IplImage* dst = cvCreateImage( img_size, 8, 3 );
351 cvNamedWindow( "test", 1 );
352 cvCmpS( img, 0, img, CV_CMP_GT );
353 cvCvtColor( img, dst, CV_GRAY2BGR );
354 cvRectangle( dst, cvPoint(init_rect.x, init_rect.y),
355 cvPoint(init_rect.x + init_rect.width, init_rect.y + init_rect.height),
356 CV_RGB(255,0,0), 3, 8, 0 );
357 cvEllipseBox( dst, box, CV_RGB(0,255,0), 3, 8, 0 );
358 cvShowImage( "test", dst );
359 cvReleaseImage( &dst );
360 cvWaitKey();
361 #endif
362 ts->set_failed_test_info( code );
363 }
364 return code;
365 }
366
367
368 ///////////////////////// MeanShift //////////////////////////////
369
370 class CV_MeanShiftTest : public CV_TrackBaseTest
371 {
372 public:
373 CV_MeanShiftTest();
374
375 protected:
376 void run_func(void);
377 int prepare_test_case( int test_case_idx );
378 int validate_test_results( int test_case_idx );
379 void generate_object();
380
381 CvRect init_rect;
382 CvConnectedComp comp;
383 int area0, area;
384 };
385
386
CV_MeanShiftTest()387 CV_MeanShiftTest::CV_MeanShiftTest()
388 {
389 }
390
391
prepare_test_case(int test_case_idx)392 int CV_MeanShiftTest::prepare_test_case( int test_case_idx )
393 {
394 RNG& rng = ts->get_rng();
395 double m;
396 int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
397 int i;
398
399 if( code <= 0 )
400 return code;
401
402 area0 = cvCountNonZero(img);
403
404 for(i = 0; i < 100; i++)
405 {
406 CvMat temp;
407
408 m = (box0.size.width + box0.size.height)*0.5;
409 init_rect.x = cvFloor(box0.center.x - m*(0.4 + cvtest::randReal(rng)*0.2));
410 init_rect.y = cvFloor(box0.center.y - m*(0.4 + cvtest::randReal(rng)*0.2));
411 init_rect.width = cvCeil(box0.center.x + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.x);
412 init_rect.height = cvCeil(box0.center.y + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.y);
413
414 if( init_rect.x < 0 || init_rect.y < 0 ||
415 init_rect.x + init_rect.width >= img_size.width ||
416 init_rect.y + init_rect.height >= img_size.height )
417 continue;
418
419 cvGetSubRect( img, &temp, init_rect );
420 area = cvCountNonZero( &temp );
421
422 if( area >= 0.5*area0 )
423 break;
424 }
425
426 return i < 100 ? code : 0;
427 }
428
429
run_func(void)430 void CV_MeanShiftTest::run_func(void)
431 {
432 cvMeanShift( img, init_rect, criteria, &comp );
433 }
434
435
validate_test_results(int)436 int CV_MeanShiftTest::validate_test_results( int /*test_case_idx*/ )
437 {
438 int code = cvtest::TS::OK;
439 CvPoint2D32f c;
440 double m = MAX(box0.size.width, box0.size.height), delta;
441
442 if( cvIsNaN(comp.area) || cvIsInf(comp.area) || comp.area <= 0 )
443 {
444 ts->printf( cvtest::TS::LOG, "Invalid CvConnectedComp was returned by cvMeanShift\n" );
445 code = cvtest::TS::FAIL_INVALID_OUTPUT;
446 goto _exit_;
447 }
448
449 c.x = (float)(comp.rect.x + comp.rect.width*0.5);
450 c.y = (float)(comp.rect.y + comp.rect.height*0.5);
451
452 if( fabs(c.x - box0.center.x) > m*0.1 ||
453 fabs(c.y - box0.center.y) > m*0.1 )
454 {
455 ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
456 c.x, c.y, box0.center.x, box0.center.y );
457 code = cvtest::TS::FAIL_BAD_ACCURACY;
458 goto _exit_;
459 }
460
461 delta = m*0.7;
462
463 if( comp.rect.x < box0.center.x - delta ||
464 comp.rect.y < box0.center.y - delta ||
465 comp.rect.x + comp.rect.width > box0.center.x + delta ||
466 comp.rect.y + comp.rect.height > box0.center.y + delta )
467 {
468 ts->printf( cvtest::TS::LOG,
469 "Incorrect CvConnectedComp ((%d,%d,%d,%d) is not within (%.1f,%.1f,%.1f,%.1f))\n",
470 comp.rect.x, comp.rect.y, comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height,
471 box0.center.x - delta, box0.center.y - delta, box0.center.x + delta, box0.center.y + delta );
472 code = cvtest::TS::FAIL_BAD_ACCURACY;
473 goto _exit_;
474 }
475
476 if( fabs((double)(comp.area - area0)) > fabs((double)(area - area0)) + area0*0.05 )
477 {
478 ts->printf( cvtest::TS::LOG,
479 "Incorrect CvConnectedComp area (=%.1f, should be %d)\n", comp.area, area0 );
480 code = cvtest::TS::FAIL_BAD_ACCURACY;
481 goto _exit_;
482 }
483
484 _exit_:
485
486 if( code < 0 )
487 {
488 #if 0// defined _DEBUG && defined WIN32
489 IplImage* dst = cvCreateImage( img_size, 8, 3 );
490 cvNamedWindow( "test", 1 );
491 cvCmpS( img, 0, img, CV_CMP_GT );
492 cvCvtColor( img, dst, CV_GRAY2BGR );
493 cvRectangle( dst, cvPoint(init_rect.x, init_rect.y),
494 cvPoint(init_rect.x + init_rect.width, init_rect.y + init_rect.height),
495 CV_RGB(255,0,0), 3, 8, 0 );
496 cvRectangle( dst, cvPoint(comp.rect.x, comp.rect.y),
497 cvPoint(comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height),
498 CV_RGB(0,255,0), 3, 8, 0 );
499 cvShowImage( "test", dst );
500 cvReleaseImage( &dst );
501 cvWaitKey();
502 #endif
503 ts->set_failed_test_info( code );
504 }
505 return code;
506 }
507
508
TEST(Video_CAMShift,accuracy)509 TEST(Video_CAMShift, accuracy) { CV_CamShiftTest test; test.safe_run(); }
TEST(Video_MeanShift,accuracy)510 TEST(Video_MeanShift, accuracy) { CV_MeanShiftTest test; test.safe_run(); }
511
512 /* End of file. */
513