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 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 80 CV_TrackBaseTest::~CV_TrackBaseTest() 81 { 82 clear(); 83 } 84 85 86 void CV_TrackBaseTest::clear() 87 { 88 cvReleaseMat( &img ); 89 cvtest::BaseTest::clear(); 90 } 91 92 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 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 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 188 void CV_TrackBaseTest::run_func(void) 189 { 190 } 191 192 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 220 CV_CamShiftTest::CV_CamShiftTest() 221 { 222 } 223 224 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 263 void CV_CamShiftTest::run_func(void) 264 { 265 cvCamShift( img, init_rect, criteria, &comp, &box ); 266 } 267 268 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 387 CV_MeanShiftTest::CV_MeanShiftTest() 388 { 389 } 390 391 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 430 void CV_MeanShiftTest::run_func(void) 431 { 432 cvMeanShift( img, init_rect, criteria, &comp ); 433 } 434 435 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 509 TEST(Video_CAMShift, accuracy) { CV_CamShiftTest test; test.safe_run(); } 510 TEST(Video_MeanShift, accuracy) { CV_MeanShiftTest test; test.safe_run(); } 511 512 /* End of file. */ 513