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 44 using namespace cv; 45 using namespace std; 46 47 class CV_FloodFillTest : public cvtest::ArrayTest 48 { 49 public: 50 CV_FloodFillTest(); 51 52 protected: 53 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 54 double get_success_error_level( int test_case_idx, int i, int j ); 55 void run_func(); 56 void prepare_to_validation( int ); 57 58 void fill_array( int test_case_idx, int i, int j, Mat& arr ); 59 60 /*int write_default_params(CvFileStorage* fs); 61 void get_timing_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types 62 CvSize** whole_sizes, bool *are_images ); 63 void print_timing_params( int test_case_idx, char* ptr, int params_left );*/ 64 CvPoint seed_pt; 65 CvScalar new_val; 66 CvScalar l_diff, u_diff; 67 int connectivity; 68 bool use_mask, mask_only; 69 int range_type; 70 int new_mask_val; 71 bool test_cpp; 72 }; 73 74 75 CV_FloodFillTest::CV_FloodFillTest() 76 { 77 test_array[INPUT_OUTPUT].push_back(NULL); 78 test_array[INPUT_OUTPUT].push_back(NULL); 79 test_array[REF_INPUT_OUTPUT].push_back(NULL); 80 test_array[REF_INPUT_OUTPUT].push_back(NULL); 81 test_array[OUTPUT].push_back(NULL); 82 test_array[REF_OUTPUT].push_back(NULL); 83 optional_mask = false; 84 element_wise_relative_error = true; 85 86 test_cpp = false; 87 } 88 89 90 void CV_FloodFillTest::get_test_array_types_and_sizes( int test_case_idx, 91 vector<vector<Size> >& sizes, 92 vector<vector<int> >& types ) 93 { 94 RNG& rng = ts->get_rng(); 95 int depth, cn; 96 int i; 97 double buff[8]; 98 cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 99 100 depth = cvtest::randInt(rng) % 3; 101 depth = depth == 0 ? CV_8U : depth == 1 ? CV_32S : CV_32F; 102 cn = cvtest::randInt(rng) & 1 ? 3 : 1; 103 104 use_mask = (cvtest::randInt(rng) & 1) != 0; 105 connectivity = (cvtest::randInt(rng) & 1) ? 4 : 8; 106 mask_only = use_mask && (cvtest::randInt(rng) & 1) != 0; 107 new_mask_val = cvtest::randInt(rng) & 255; 108 range_type = cvtest::randInt(rng) % 3; 109 110 types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn); 111 types[INPUT_OUTPUT][1] = types[REF_INPUT_OUTPUT][1] = CV_8UC1; 112 types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1; 113 sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(9,1); 114 115 if( !use_mask ) 116 sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(0,0); 117 else 118 { 119 CvSize sz = sizes[INPUT_OUTPUT][0]; 120 sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(sz.width+2,sz.height+2); 121 } 122 123 seed_pt.x = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].width; 124 seed_pt.y = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].height; 125 126 if( range_type == 0 ) 127 l_diff = u_diff = Scalar::all(0.); 128 else 129 { 130 Mat m( 1, 8, CV_16S, buff ); 131 rng.fill( m, RNG::NORMAL, Scalar::all(0), Scalar::all(32) ); 132 for( i = 0; i < 4; i++ ) 133 { 134 l_diff.val[i] = fabs(m.at<short>(i)/16.); 135 u_diff.val[i] = fabs(m.at<short>(i+4)/16.); 136 } 137 } 138 139 new_val = Scalar::all(0.); 140 for( i = 0; i < cn; i++ ) 141 new_val.val[i] = cvtest::randReal(rng)*255; 142 143 test_cpp = (cvtest::randInt(rng) & 256) == 0; 144 } 145 146 147 double CV_FloodFillTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 148 { 149 return i == OUTPUT ? FLT_EPSILON : j == 0 ? FLT_EPSILON : 0; 150 } 151 152 153 void CV_FloodFillTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) 154 { 155 RNG& rng = ts->get_rng(); 156 157 if( i != INPUT && i != INPUT_OUTPUT ) 158 { 159 cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr ); 160 return; 161 } 162 163 if( j == 0 ) 164 { 165 Mat tmp = arr; 166 Scalar m = Scalar::all(128); 167 Scalar s = Scalar::all(10); 168 169 if( arr.depth() == CV_32FC1 ) 170 tmp.create(arr.size(), CV_MAKETYPE(CV_8U, arr.channels())); 171 172 if( range_type == 0 ) 173 s = Scalar::all(2); 174 175 rng.fill(tmp, RNG::NORMAL, m, s ); 176 if( arr.data != tmp.data ) 177 cvtest::convert(tmp, arr, arr.type()); 178 } 179 else 180 { 181 Scalar l = Scalar::all(-2); 182 Scalar u = Scalar::all(2); 183 cvtest::randUni(rng, arr, l, u ); 184 rectangle( arr, Point(0,0), Point(arr.cols-1,arr.rows-1), Scalar::all(1), 1, 8, 0 ); 185 } 186 } 187 188 189 void CV_FloodFillTest::run_func() 190 { 191 int flags = connectivity + (mask_only ? CV_FLOODFILL_MASK_ONLY : 0) + 192 (range_type == 1 ? CV_FLOODFILL_FIXED_RANGE : 0) + (new_mask_val << 8); 193 double* odata = test_mat[OUTPUT][0].ptr<double>(); 194 195 if(!test_cpp) 196 { 197 CvConnectedComp comp; 198 cvFloodFill( test_array[INPUT_OUTPUT][0], seed_pt, new_val, l_diff, u_diff, &comp, 199 flags, test_array[INPUT_OUTPUT][1] ); 200 odata[0] = comp.area; 201 odata[1] = comp.rect.x; 202 odata[2] = comp.rect.y; 203 odata[3] = comp.rect.width; 204 odata[4] = comp.rect.height; 205 odata[5] = comp.value.val[0]; 206 odata[6] = comp.value.val[1]; 207 odata[7] = comp.value.val[2]; 208 odata[8] = comp.value.val[3]; 209 } 210 else 211 { 212 cv::Mat img = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]), 213 mask = test_array[INPUT_OUTPUT][1] ? cv::cvarrToMat(test_array[INPUT_OUTPUT][1]) : cv::Mat(); 214 cv::Rect rect; 215 int area; 216 if( mask.empty() ) 217 area = cv::floodFill( img, seed_pt, new_val, &rect, l_diff, u_diff, flags ); 218 else 219 area = cv::floodFill( img, mask, seed_pt, new_val, &rect, l_diff, u_diff, flags ); 220 odata[0] = area; 221 odata[1] = rect.x; 222 odata[2] = rect.y; 223 odata[3] = rect.width; 224 odata[4] = rect.height; 225 odata[5] = odata[6] = odata[7] = odata[8] = 0; 226 } 227 } 228 229 230 typedef struct ff_offset_pair_t 231 { 232 int mofs, iofs; 233 } 234 ff_offset_pair_t; 235 236 static void 237 cvTsFloodFill( CvMat* _img, CvPoint seed_pt, CvScalar new_val, 238 CvScalar l_diff, CvScalar u_diff, CvMat* _mask, 239 double* comp, int connectivity, int range_type, 240 int new_mask_val, bool mask_only ) 241 { 242 CvMemStorage* st = cvCreateMemStorage(); 243 ff_offset_pair_t p0, p; 244 CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(p0), st ); 245 CvMat* tmp = _img; 246 CvMat* mask; 247 CvRect r = cvRect( 0, 0, -1, -1 ); 248 int area = 0; 249 int i, j; 250 ushort* m; 251 float* img; 252 int mstep, step; 253 int cn = CV_MAT_CN(_img->type); 254 int mdelta[8], idelta[8], ncount; 255 int cols = _img->cols, rows = _img->rows; 256 int u0 = 0, u1 = 0, u2 = 0; 257 double s0 = 0, s1 = 0, s2 = 0; 258 259 if( CV_MAT_DEPTH(_img->type) == CV_8U || CV_MAT_DEPTH(_img->type) == CV_32S ) 260 { 261 tmp = cvCreateMat( rows, cols, CV_MAKETYPE(CV_32F,CV_MAT_CN(_img->type)) ); 262 cvtest::convert(cvarrToMat(_img), cvarrToMat(tmp), -1); 263 } 264 265 mask = cvCreateMat( rows + 2, cols + 2, CV_16UC1 ); 266 267 if( _mask ) 268 cvtest::convert(cvarrToMat(_mask), cvarrToMat(mask), -1); 269 else 270 { 271 Mat m_mask = cvarrToMat(mask); 272 cvtest::set( m_mask, Scalar::all(0), Mat() ); 273 cvRectangle( mask, cvPoint(0,0), cvPoint(mask->cols-1,mask->rows-1), Scalar::all(1.), 1, 8, 0 ); 274 } 275 276 new_mask_val = (new_mask_val != 0 ? new_mask_val : 1) << 8; 277 278 m = (ushort*)(mask->data.ptr + mask->step) + 1; 279 mstep = mask->step / sizeof(m[0]); 280 img = tmp->data.fl; 281 step = tmp->step / sizeof(img[0]); 282 283 p0.mofs = seed_pt.y*mstep + seed_pt.x; 284 p0.iofs = seed_pt.y*step + seed_pt.x*cn; 285 286 if( m[p0.mofs] ) 287 goto _exit_; 288 289 cvSeqPush( seq, &p0 ); 290 m[p0.mofs] = (ushort)new_mask_val; 291 292 if( connectivity == 4 ) 293 { 294 ncount = 4; 295 mdelta[0] = -mstep; idelta[0] = -step; 296 mdelta[1] = -1; idelta[1] = -cn; 297 mdelta[2] = 1; idelta[2] = cn; 298 mdelta[3] = mstep; idelta[3] = step; 299 } 300 else 301 { 302 ncount = 8; 303 mdelta[0] = -mstep-1; mdelta[1] = -mstep; mdelta[2] = -mstep+1; 304 idelta[0] = -step-cn; idelta[1] = -step; idelta[2] = -step+cn; 305 306 mdelta[3] = -1; mdelta[4] = 1; 307 idelta[3] = -cn; idelta[4] = cn; 308 309 mdelta[5] = mstep-1; mdelta[6] = mstep; mdelta[7] = mstep+1; 310 idelta[5] = step-cn; idelta[6] = step; idelta[7] = step+cn; 311 } 312 313 if( cn == 1 ) 314 { 315 float a0 = (float)-l_diff.val[0]; 316 float b0 = (float)u_diff.val[0]; 317 318 s0 = img[p0.iofs]; 319 320 if( range_type < 2 ) 321 { 322 a0 += (float)s0; b0 += (float)s0; 323 } 324 325 while( seq->total ) 326 { 327 cvSeqPop( seq, &p0 ); 328 float a = a0, b = b0; 329 float* ptr = img + p0.iofs; 330 ushort* mptr = m + p0.mofs; 331 332 if( range_type == 2 ) 333 a += ptr[0], b += ptr[0]; 334 335 for( i = 0; i < ncount; i++ ) 336 { 337 int md = mdelta[i], id = idelta[i]; 338 float v; 339 if( !mptr[md] && a <= (v = ptr[id]) && v <= b ) 340 { 341 mptr[md] = (ushort)new_mask_val; 342 p.mofs = p0.mofs + md; 343 p.iofs = p0.iofs + id; 344 cvSeqPush( seq, &p ); 345 } 346 } 347 } 348 } 349 else 350 { 351 float a0 = (float)-l_diff.val[0]; 352 float a1 = (float)-l_diff.val[1]; 353 float a2 = (float)-l_diff.val[2]; 354 float b0 = (float)u_diff.val[0]; 355 float b1 = (float)u_diff.val[1]; 356 float b2 = (float)u_diff.val[2]; 357 358 s0 = img[p0.iofs]; 359 s1 = img[p0.iofs + 1]; 360 s2 = img[p0.iofs + 2]; 361 362 if( range_type < 2 ) 363 { 364 a0 += (float)s0; b0 += (float)s0; 365 a1 += (float)s1; b1 += (float)s1; 366 a2 += (float)s2; b2 += (float)s2; 367 } 368 369 while( seq->total ) 370 { 371 cvSeqPop( seq, &p0 ); 372 float _a0 = a0, _a1 = a1, _a2 = a2; 373 float _b0 = b0, _b1 = b1, _b2 = b2; 374 float* ptr = img + p0.iofs; 375 ushort* mptr = m + p0.mofs; 376 377 if( range_type == 2 ) 378 { 379 _a0 += ptr[0]; _b0 += ptr[0]; 380 _a1 += ptr[1]; _b1 += ptr[1]; 381 _a2 += ptr[2]; _b2 += ptr[2]; 382 } 383 384 for( i = 0; i < ncount; i++ ) 385 { 386 int md = mdelta[i], id = idelta[i]; 387 float v; 388 if( !mptr[md] && 389 _a0 <= (v = ptr[id]) && v <= _b0 && 390 _a1 <= (v = ptr[id+1]) && v <= _b1 && 391 _a2 <= (v = ptr[id+2]) && v <= _b2 ) 392 { 393 mptr[md] = (ushort)new_mask_val; 394 p.mofs = p0.mofs + md; 395 p.iofs = p0.iofs + id; 396 cvSeqPush( seq, &p ); 397 } 398 } 399 } 400 } 401 402 r.x = r.width = seed_pt.x; 403 r.y = r.height = seed_pt.y; 404 405 if( !mask_only ) 406 { 407 s0 = new_val.val[0]; 408 s1 = new_val.val[1]; 409 s2 = new_val.val[2]; 410 411 if( tmp != _img ) 412 { 413 u0 = saturate_cast<uchar>(s0); 414 u1 = saturate_cast<uchar>(s1); 415 u2 = saturate_cast<uchar>(s2); 416 417 s0 = u0; 418 s1 = u1; 419 s2 = u2; 420 } 421 } 422 else 423 s0 = s1 = s2 = 0; 424 425 new_mask_val >>= 8; 426 427 for( i = 0; i < rows; i++ ) 428 { 429 float* ptr = img + i*step; 430 ushort* mptr = m + i*mstep; 431 uchar* dmptr = _mask ? _mask->data.ptr + (i+1)*_mask->step + 1 : 0; 432 double area0 = area; 433 434 for( j = 0; j < cols; j++ ) 435 { 436 if( mptr[j] > 255 ) 437 { 438 if( dmptr ) 439 dmptr[j] = (uchar)new_mask_val; 440 if( !mask_only ) 441 { 442 if( cn == 1 ) 443 ptr[j] = (float)s0; 444 else 445 { 446 ptr[j*3] = (float)s0; 447 ptr[j*3+1] = (float)s1; 448 ptr[j*3+2] = (float)s2; 449 } 450 } 451 else 452 { 453 if( cn == 1 ) 454 s0 += ptr[j]; 455 else 456 { 457 s0 += ptr[j*3]; 458 s1 += ptr[j*3+1]; 459 s2 += ptr[j*3+2]; 460 } 461 } 462 463 area++; 464 if( r.x > j ) 465 r.x = j; 466 if( r.width < j ) 467 r.width = j; 468 } 469 } 470 471 if( area != area0 ) 472 { 473 if( r.y > i ) 474 r.y = i; 475 if( r.height < i ) 476 r.height = i; 477 } 478 } 479 480 _exit_: 481 cvReleaseMat( &mask ); 482 if( tmp != _img ) 483 { 484 if( !mask_only ) 485 cvtest::convert(cvarrToMat(tmp), cvarrToMat(_img), -1); 486 cvReleaseMat( &tmp ); 487 } 488 489 comp[0] = area; 490 comp[1] = r.x; 491 comp[2] = r.y; 492 comp[3] = r.width - r.x + 1; 493 comp[4] = r.height - r.y + 1; 494 #if 0 495 if( mask_only ) 496 { 497 double t = area ? 1./area : 0; 498 s0 *= t; 499 s1 *= t; 500 s2 *= t; 501 } 502 comp[5] = s0; 503 comp[6] = s1; 504 comp[7] = s2; 505 #else 506 comp[5] = new_val.val[0]; 507 comp[6] = new_val.val[1]; 508 comp[7] = new_val.val[2]; 509 #endif 510 comp[8] = 0; 511 } 512 513 514 void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ ) 515 { 516 double* comp = test_mat[REF_OUTPUT][0].ptr<double>(); 517 CvMat _input = test_mat[REF_INPUT_OUTPUT][0]; 518 CvMat _mask = test_mat[REF_INPUT_OUTPUT][1]; 519 cvTsFloodFill( &_input, seed_pt, new_val, l_diff, u_diff, 520 _mask.data.ptr ? &_mask : 0, 521 comp, connectivity, range_type, 522 new_mask_val, mask_only ); 523 if(test_cpp) 524 comp[5] = comp[6] = comp[7] = comp[8] = 0; 525 } 526 527 TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); } 528 529 /* End of file. */ 530