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, Intel Corporation, all rights reserved. 14 // Copyright (C) 2013, OpenCV Foundation, 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 "precomp.hpp" 44 45 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) 46 # pragma GCC diagnostic ignored "-Warray-bounds" 47 #endif 48 49 namespace cv 50 { 51 52 struct FFillSegment 53 { 54 ushort y; 55 ushort l; 56 ushort r; 57 ushort prevl; 58 ushort prevr; 59 short dir; 60 }; 61 62 enum 63 { 64 UP = 1, 65 DOWN = -1 66 }; 67 68 #define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR ) \ 69 { \ 70 tail->y = (ushort)(Y); \ 71 tail->l = (ushort)(L); \ 72 tail->r = (ushort)(R); \ 73 tail->prevl = (ushort)(PREV_L); \ 74 tail->prevr = (ushort)(PREV_R); \ 75 tail->dir = (short)(DIR); \ 76 if( ++tail == buffer_end ) \ 77 { \ 78 buffer->resize(buffer->size() * 3/2); \ 79 tail = &buffer->front() + (tail - head); \ 80 head = &buffer->front(); \ 81 buffer_end = head + buffer->size(); \ 82 } \ 83 } 84 85 #define ICV_POP( Y, L, R, PREV_L, PREV_R, DIR ) \ 86 { \ 87 --tail; \ 88 Y = tail->y; \ 89 L = tail->l; \ 90 R = tail->r; \ 91 PREV_L = tail->prevl; \ 92 PREV_R = tail->prevr; \ 93 DIR = tail->dir; \ 94 } 95 96 struct ConnectedComp 97 { 98 ConnectedComp(); 99 Rect rect; 100 Point pt; 101 int threshold; 102 int label; 103 int area; 104 int harea; 105 int carea; 106 int perimeter; 107 int nholes; 108 int ninflections; 109 double mx; 110 double my; 111 Scalar avg; 112 Scalar sdv; 113 }; 114 115 ConnectedComp::ConnectedComp() 116 { 117 rect = Rect(0, 0, 0, 0); 118 pt = Point(-1, -1); 119 threshold = -1; 120 label = -1; 121 area = harea = carea = perimeter = nholes = ninflections = 0; 122 mx = my = 0; 123 avg = sdv = Scalar::all(0); 124 } 125 126 // Simple Floodfill (repainting single-color connected component) 127 128 template<typename _Tp> 129 static void 130 floodFill_CnIR( Mat& image, Point seed, 131 _Tp newVal, ConnectedComp* region, int flags, 132 std::vector<FFillSegment>* buffer ) 133 { 134 _Tp* img = image.ptr<_Tp>(seed.y); 135 Size roi = image.size(); 136 int i, L, R; 137 int area = 0; 138 int XMin, XMax, YMin = seed.y, YMax = seed.y; 139 int _8_connectivity = (flags & 255) == 8; 140 FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front(); 141 142 L = R = XMin = XMax = seed.x; 143 144 _Tp val0 = img[L]; 145 img[L] = newVal; 146 147 while( ++R < roi.width && img[R] == val0 ) 148 img[R] = newVal; 149 150 while( --L >= 0 && img[L] == val0 ) 151 img[L] = newVal; 152 153 XMax = --R; 154 XMin = ++L; 155 156 ICV_PUSH( seed.y, L, R, R + 1, R, UP ); 157 158 while( head != tail ) 159 { 160 int k, YC, PL, PR, dir; 161 ICV_POP( YC, L, R, PL, PR, dir ); 162 163 int data[][3] = 164 { 165 {-dir, L - _8_connectivity, R + _8_connectivity}, 166 {dir, L - _8_connectivity, PL - 1}, 167 {dir, PR + 1, R + _8_connectivity} 168 }; 169 170 if( region ) 171 { 172 area += R - L + 1; 173 174 if( XMax < R ) XMax = R; 175 if( XMin > L ) XMin = L; 176 if( YMax < YC ) YMax = YC; 177 if( YMin > YC ) YMin = YC; 178 } 179 180 for( k = 0; k < 3; k++ ) 181 { 182 dir = data[k][0]; 183 184 if( (unsigned)(YC + dir) >= (unsigned)roi.height ) 185 continue; 186 187 img = image.ptr<_Tp>(YC + dir); 188 int left = data[k][1]; 189 int right = data[k][2]; 190 191 for( i = left; i <= right; i++ ) 192 { 193 if( (unsigned)i < (unsigned)roi.width && img[i] == val0 ) 194 { 195 int j = i; 196 img[i] = newVal; 197 while( --j >= 0 && img[j] == val0 ) 198 img[j] = newVal; 199 200 while( ++i < roi.width && img[i] == val0 ) 201 img[i] = newVal; 202 203 ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); 204 } 205 } 206 } 207 } 208 209 if( region ) 210 { 211 region->pt = seed; 212 region->area = area; 213 region->rect.x = XMin; 214 region->rect.y = YMin; 215 region->rect.width = XMax - XMin + 1; 216 region->rect.height = YMax - YMin + 1; 217 } 218 } 219 220 /****************************************************************************************\ 221 * Gradient Floodfill * 222 \****************************************************************************************/ 223 224 struct Diff8uC1 225 { 226 Diff8uC1(uchar _lo, uchar _up) : lo(_lo), interval(_lo + _up) {} 227 bool operator()(const uchar* a, const uchar* b) const 228 { return (unsigned)(a[0] - b[0] + lo) <= interval; } 229 unsigned lo, interval; 230 }; 231 232 struct Diff8uC3 233 { 234 Diff8uC3(Vec3b _lo, Vec3b _up) 235 { 236 for( int k = 0; k < 3; k++ ) 237 lo[k] = _lo[k], interval[k] = _lo[k] + _up[k]; 238 } 239 bool operator()(const Vec3b* a, const Vec3b* b) const 240 { 241 return (unsigned)(a[0][0] - b[0][0] + lo[0]) <= interval[0] && 242 (unsigned)(a[0][1] - b[0][1] + lo[1]) <= interval[1] && 243 (unsigned)(a[0][2] - b[0][2] + lo[2]) <= interval[2]; 244 } 245 unsigned lo[3], interval[3]; 246 }; 247 248 template<typename _Tp> 249 struct DiffC1 250 { 251 DiffC1(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {} 252 bool operator()(const _Tp* a, const _Tp* b) const 253 { 254 _Tp d = a[0] - b[0]; 255 return lo <= d && d <= up; 256 } 257 _Tp lo, up; 258 }; 259 260 template<typename _Tp> 261 struct DiffC3 262 { 263 DiffC3(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {} 264 bool operator()(const _Tp* a, const _Tp* b) const 265 { 266 _Tp d = *a - *b; 267 return lo[0] <= d[0] && d[0] <= up[0] && 268 lo[1] <= d[1] && d[1] <= up[1] && 269 lo[2] <= d[2] && d[2] <= up[2]; 270 } 271 _Tp lo, up; 272 }; 273 274 typedef DiffC1<int> Diff32sC1; 275 typedef DiffC3<Vec3i> Diff32sC3; 276 typedef DiffC1<float> Diff32fC1; 277 typedef DiffC3<Vec3f> Diff32fC3; 278 279 template<typename _Tp, typename _MTp, typename _WTp, class Diff> 280 static void 281 floodFillGrad_CnIR( Mat& image, Mat& msk, 282 Point seed, _Tp newVal, _MTp newMaskVal, 283 Diff diff, ConnectedComp* region, int flags, 284 std::vector<FFillSegment>* buffer ) 285 { 286 int step = (int)image.step, maskStep = (int)msk.step; 287 uchar* pImage = image.ptr(); 288 _Tp* img = (_Tp*)(pImage + step*seed.y); 289 uchar* pMask = msk.ptr() + maskStep + sizeof(_MTp); 290 _MTp* mask = (_MTp*)(pMask + maskStep*seed.y); 291 int i, L, R; 292 int area = 0; 293 int XMin, XMax, YMin = seed.y, YMax = seed.y; 294 int _8_connectivity = (flags & 255) == 8; 295 int fixedRange = flags & FLOODFILL_FIXED_RANGE; 296 int fillImage = (flags & FLOODFILL_MASK_ONLY) == 0; 297 FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front(); 298 299 L = R = seed.x; 300 if( mask[L] ) 301 return; 302 303 mask[L] = newMaskVal; 304 _Tp val0 = img[L]; 305 306 if( fixedRange ) 307 { 308 while( !mask[R + 1] && diff( img + (R+1), &val0 )) 309 mask[++R] = newMaskVal; 310 311 while( !mask[L - 1] && diff( img + (L-1), &val0 )) 312 mask[--L] = newMaskVal; 313 } 314 else 315 { 316 while( !mask[R + 1] && diff( img + (R+1), img + R )) 317 mask[++R] = newMaskVal; 318 319 while( !mask[L - 1] && diff( img + (L-1), img + L )) 320 mask[--L] = newMaskVal; 321 } 322 323 XMax = R; 324 XMin = L; 325 326 ICV_PUSH( seed.y, L, R, R + 1, R, UP ); 327 328 while( head != tail ) 329 { 330 int k, YC, PL, PR, dir; 331 ICV_POP( YC, L, R, PL, PR, dir ); 332 333 int data[][3] = 334 { 335 {-dir, L - _8_connectivity, R + _8_connectivity}, 336 {dir, L - _8_connectivity, PL - 1}, 337 {dir, PR + 1, R + _8_connectivity} 338 }; 339 340 unsigned length = (unsigned)(R-L); 341 342 if( region ) 343 { 344 area += (int)length + 1; 345 346 if( XMax < R ) XMax = R; 347 if( XMin > L ) XMin = L; 348 if( YMax < YC ) YMax = YC; 349 if( YMin > YC ) YMin = YC; 350 } 351 352 for( k = 0; k < 3; k++ ) 353 { 354 dir = data[k][0]; 355 img = (_Tp*)(pImage + (YC + dir) * step); 356 _Tp* img1 = (_Tp*)(pImage + YC * step); 357 mask = (_MTp*)(pMask + (YC + dir) * maskStep); 358 int left = data[k][1]; 359 int right = data[k][2]; 360 361 if( fixedRange ) 362 for( i = left; i <= right; i++ ) 363 { 364 if( !mask[i] && diff( img + i, &val0 )) 365 { 366 int j = i; 367 mask[i] = newMaskVal; 368 while( !mask[--j] && diff( img + j, &val0 )) 369 mask[j] = newMaskVal; 370 371 while( !mask[++i] && diff( img + i, &val0 )) 372 mask[i] = newMaskVal; 373 374 ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); 375 } 376 } 377 else if( !_8_connectivity ) 378 for( i = left; i <= right; i++ ) 379 { 380 if( !mask[i] && diff( img + i, img1 + i )) 381 { 382 int j = i; 383 mask[i] = newMaskVal; 384 while( !mask[--j] && diff( img + j, img + (j+1) )) 385 mask[j] = newMaskVal; 386 387 while( !mask[++i] && 388 (diff( img + i, img + (i-1) ) || 389 (diff( img + i, img1 + i) && i <= R))) 390 mask[i] = newMaskVal; 391 392 ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); 393 } 394 } 395 else 396 for( i = left; i <= right; i++ ) 397 { 398 int idx; 399 _Tp val; 400 401 if( !mask[i] && 402 (((val = img[i], 403 (unsigned)(idx = i-L-1) <= length) && 404 diff( &val, img1 + (i-1))) || 405 ((unsigned)(++idx) <= length && 406 diff( &val, img1 + i )) || 407 ((unsigned)(++idx) <= length && 408 diff( &val, img1 + (i+1) )))) 409 { 410 int j = i; 411 mask[i] = newMaskVal; 412 while( !mask[--j] && diff( img + j, img + (j+1) )) 413 mask[j] = newMaskVal; 414 415 while( !mask[++i] && 416 ((val = img[i], 417 diff( &val, img + (i-1) )) || 418 (((unsigned)(idx = i-L-1) <= length && 419 diff( &val, img1 + (i-1) ))) || 420 ((unsigned)(++idx) <= length && 421 diff( &val, img1 + i )) || 422 ((unsigned)(++idx) <= length && 423 diff( &val, img1 + (i+1) )))) 424 mask[i] = newMaskVal; 425 426 ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir ); 427 } 428 } 429 } 430 431 img = (_Tp*)(pImage + YC * step); 432 if( fillImage ) 433 for( i = L; i <= R; i++ ) 434 img[i] = newVal; 435 /*else if( region ) 436 for( i = L; i <= R; i++ ) 437 sum += img[i];*/ 438 } 439 440 if( region ) 441 { 442 region->pt = seed; 443 region->label = saturate_cast<int>(newMaskVal); 444 region->area = area; 445 region->rect.x = XMin; 446 region->rect.y = YMin; 447 region->rect.width = XMax - XMin + 1; 448 region->rect.height = YMax - YMin + 1; 449 } 450 } 451 452 } 453 454 /****************************************************************************************\ 455 * External Functions * 456 \****************************************************************************************/ 457 458 int cv::floodFill( InputOutputArray _image, InputOutputArray _mask, 459 Point seedPoint, Scalar newVal, Rect* rect, 460 Scalar loDiff, Scalar upDiff, int flags ) 461 { 462 ConnectedComp comp; 463 std::vector<FFillSegment> buffer; 464 465 if( rect ) 466 *rect = Rect(); 467 468 int i, connectivity = flags & 255; 469 union { 470 uchar b[4]; 471 int i[4]; 472 float f[4]; 473 double _[4]; 474 } nv_buf; 475 nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0; 476 477 struct { Vec3b b; Vec3i i; Vec3f f; } ld_buf, ud_buf; 478 Mat img = _image.getMat(), mask; 479 if( !_mask.empty() ) 480 mask = _mask.getMat(); 481 Size size = img.size(); 482 483 int type = img.type(); 484 int depth = img.depth(); 485 int cn = img.channels(); 486 487 if ( (cn != 1) && (cn != 3) ) 488 { 489 CV_Error( CV_StsBadArg, "Number of channels in input image must be 1 or 3" ); 490 } 491 492 if( connectivity == 0 ) 493 connectivity = 4; 494 else if( connectivity != 4 && connectivity != 8 ) 495 CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" ); 496 497 bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0; 498 499 for( i = 0; i < cn; i++ ) 500 { 501 if( loDiff[i] < 0 || upDiff[i] < 0 ) 502 CV_Error( CV_StsBadArg, "lo_diff and up_diff must be non-negative" ); 503 is_simple = is_simple && fabs(loDiff[i]) < DBL_EPSILON && fabs(upDiff[i]) < DBL_EPSILON; 504 } 505 506 if( (unsigned)seedPoint.x >= (unsigned)size.width || 507 (unsigned)seedPoint.y >= (unsigned)size.height ) 508 CV_Error( CV_StsOutOfRange, "Seed point is outside of image" ); 509 510 scalarToRawData( newVal, &nv_buf, type, 0); 511 size_t buffer_size = MAX( size.width, size.height ) * 2; 512 buffer.resize( buffer_size ); 513 514 if( is_simple ) 515 { 516 size_t elem_size = img.elemSize(); 517 const uchar* seed_ptr = img.ptr(seedPoint.y) + elem_size*seedPoint.x; 518 519 size_t k = 0; 520 for(; k < elem_size; k++) 521 if (seed_ptr[k] != nv_buf.b[k]) 522 break; 523 524 if( k != elem_size ) 525 { 526 if( type == CV_8UC1 ) 527 floodFill_CnIR(img, seedPoint, nv_buf.b[0], &comp, flags, &buffer); 528 else if( type == CV_8UC3 ) 529 floodFill_CnIR(img, seedPoint, Vec3b(nv_buf.b), &comp, flags, &buffer); 530 else if( type == CV_32SC1 ) 531 floodFill_CnIR(img, seedPoint, nv_buf.i[0], &comp, flags, &buffer); 532 else if( type == CV_32FC1 ) 533 floodFill_CnIR(img, seedPoint, nv_buf.f[0], &comp, flags, &buffer); 534 else if( type == CV_32SC3 ) 535 floodFill_CnIR(img, seedPoint, Vec3i(nv_buf.i), &comp, flags, &buffer); 536 else if( type == CV_32FC3 ) 537 floodFill_CnIR(img, seedPoint, Vec3f(nv_buf.f), &comp, flags, &buffer); 538 else 539 CV_Error( CV_StsUnsupportedFormat, "" ); 540 if( rect ) 541 *rect = comp.rect; 542 return comp.area; 543 } 544 } 545 546 if( mask.empty() ) 547 { 548 Mat tempMask( size.height + 2, size.width + 2, CV_8UC1 ); 549 tempMask.setTo(Scalar::all(0)); 550 mask = tempMask; 551 } 552 else 553 { 554 CV_Assert( mask.rows == size.height+2 && mask.cols == size.width+2 ); 555 CV_Assert( mask.type() == CV_8U ); 556 } 557 558 memset( mask.ptr(), 1, mask.cols ); 559 memset( mask.ptr(mask.rows-1), 1, mask.cols ); 560 561 for( i = 1; i <= size.height; i++ ) 562 { 563 mask.at<uchar>(i, 0) = mask.at<uchar>(i, mask.cols-1) = (uchar)1; 564 } 565 566 if( depth == CV_8U ) 567 for( i = 0; i < cn; i++ ) 568 { 569 ld_buf.b[i] = saturate_cast<uchar>(cvFloor(loDiff[i])); 570 ud_buf.b[i] = saturate_cast<uchar>(cvFloor(upDiff[i])); 571 } 572 else if( depth == CV_32S ) 573 for( i = 0; i < cn; i++ ) 574 { 575 ld_buf.i[i] = cvFloor(loDiff[i]); 576 ud_buf.i[i] = cvFloor(upDiff[i]); 577 } 578 else if( depth == CV_32F ) 579 for( i = 0; i < cn; i++ ) 580 { 581 ld_buf.f[i] = (float)loDiff[i]; 582 ud_buf.f[i] = (float)upDiff[i]; 583 } 584 else 585 CV_Error( CV_StsUnsupportedFormat, "" ); 586 587 uchar newMaskVal = (uchar)((flags & ~0xff) == 0 ? 1 : ((flags >> 8) & 255)); 588 589 if( type == CV_8UC1 ) 590 floodFillGrad_CnIR<uchar, uchar, int, Diff8uC1>( 591 img, mask, seedPoint, nv_buf.b[0], newMaskVal, 592 Diff8uC1(ld_buf.b[0], ud_buf.b[0]), 593 &comp, flags, &buffer); 594 else if( type == CV_8UC3 ) 595 floodFillGrad_CnIR<Vec3b, uchar, Vec3i, Diff8uC3>( 596 img, mask, seedPoint, Vec3b(nv_buf.b), newMaskVal, 597 Diff8uC3(ld_buf.b, ud_buf.b), 598 &comp, flags, &buffer); 599 else if( type == CV_32SC1 ) 600 floodFillGrad_CnIR<int, uchar, int, Diff32sC1>( 601 img, mask, seedPoint, nv_buf.i[0], newMaskVal, 602 Diff32sC1(ld_buf.i[0], ud_buf.i[0]), 603 &comp, flags, &buffer); 604 else if( type == CV_32SC3 ) 605 floodFillGrad_CnIR<Vec3i, uchar, Vec3i, Diff32sC3>( 606 img, mask, seedPoint, Vec3i(nv_buf.i), newMaskVal, 607 Diff32sC3(ld_buf.i, ud_buf.i), 608 &comp, flags, &buffer); 609 else if( type == CV_32FC1 ) 610 floodFillGrad_CnIR<float, uchar, float, Diff32fC1>( 611 img, mask, seedPoint, nv_buf.f[0], newMaskVal, 612 Diff32fC1(ld_buf.f[0], ud_buf.f[0]), 613 &comp, flags, &buffer); 614 else if( type == CV_32FC3 ) 615 floodFillGrad_CnIR<Vec3f, uchar, Vec3f, Diff32fC3>( 616 img, mask, seedPoint, Vec3f(nv_buf.f), newMaskVal, 617 Diff32fC3(ld_buf.f, ud_buf.f), 618 &comp, flags, &buffer); 619 else 620 CV_Error(CV_StsUnsupportedFormat, ""); 621 622 if( rect ) 623 *rect = comp.rect; 624 return comp.area; 625 } 626 627 628 int cv::floodFill( InputOutputArray _image, Point seedPoint, 629 Scalar newVal, Rect* rect, 630 Scalar loDiff, Scalar upDiff, int flags ) 631 { 632 return floodFill(_image, Mat(), seedPoint, newVal, rect, loDiff, upDiff, flags); 633 } 634 635 636 CV_IMPL void 637 cvFloodFill( CvArr* arr, CvPoint seed_point, 638 CvScalar newVal, CvScalar lo_diff, CvScalar up_diff, 639 CvConnectedComp* comp, int flags, CvArr* maskarr ) 640 { 641 if( comp ) 642 memset( comp, 0, sizeof(*comp) ); 643 644 cv::Mat img = cv::cvarrToMat(arr), mask = cv::cvarrToMat(maskarr); 645 int area = cv::floodFill(img, mask, seed_point, newVal, 646 comp ? (cv::Rect*)&comp->rect : 0, 647 lo_diff, up_diff, flags ); 648 if( comp ) 649 { 650 comp->area = area; 651 comp->value = newVal; 652 } 653 } 654 655 /* End of file. */ 656