floodfill.cpp 20.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
10
//                           License Agreement
11 12 13
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
15 16 17 18 19 20 21 22 23 24 25 26
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
27
//   * The name of the copyright holders may not be used to endorse or promote products
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

45 46 47 48
namespace cv
{

struct FFillSegment
49 50 51 52 53 54 55
{
    ushort y;
    ushort l;
    ushort r;
    ushort prevl;
    ushort prevr;
    short dir;
56
};
57

58 59 60 61 62
enum
{
    UP = 1,
    DOWN = -1
};
63

Evgeny Talanin's avatar
Evgeny Talanin committed
64 65 66 67 68 69 70 71 72 73
#define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR )  \
{                                                 \
    tail->y = (ushort)(Y);                        \
    tail->l = (ushort)(L);                        \
    tail->r = (ushort)(R);                        \
    tail->prevl = (ushort)(PREV_L);               \
    tail->prevr = (ushort)(PREV_R);               \
    tail->dir = (short)(DIR);                     \
    if( ++tail == buffer_end )                    \
    {                                             \
74
        buffer->resize(buffer->size() * 3/2);     \
Evgeny Talanin's avatar
Evgeny Talanin committed
75 76 77 78
        tail = &buffer->front() + (tail - head);  \
        head = &buffer->front();                  \
        buffer_end = head + buffer->size();       \
    }                                             \
79 80
}

Evgeny Talanin's avatar
Evgeny Talanin committed
81 82 83 84 85 86 87 88 89
#define ICV_POP( Y, L, R, PREV_L, PREV_R, DIR )   \
{                                                 \
    --tail;                                       \
    Y = tail->y;                                  \
    L = tail->l;                                  \
    R = tail->r;                                  \
    PREV_L = tail->prevl;                         \
    PREV_R = tail->prevr;                         \
    DIR = tail->dir;                              \
90 91
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
struct ConnectedComp
{
    ConnectedComp();
    Rect rect;
    Point pt;
    int threshold;
    int label;
    int area;
    int harea;
    int carea;
    int perimeter;
    int nholes;
    int ninflections;
    double mx;
    double my;
    Scalar avg;
    Scalar sdv;
};

ConnectedComp::ConnectedComp()
{
    rect = Rect(0, 0, 0, 0);
    pt = Point(-1, -1);
    threshold = -1;
    label = -1;
    area = harea = carea = perimeter = nholes = ninflections = 0;
    mx = my = 0;
    avg = sdv = Scalar::all(0);
}

// Simple Floodfill (repainting single-color connected component)
123

124
template<typename _Tp>
125
static void
126 127 128
floodFill_CnIR( Mat& image, Point seed,
               _Tp newVal, ConnectedComp* region, int flags,
               std::vector<FFillSegment>* buffer )
129
{
130 131
    _Tp* img = (_Tp*)(image.data + image.step * seed.y);
    Size roi = image.size();
132 133 134 135
    int i, L, R;
    int area = 0;
    int XMin, XMax, YMin = seed.y, YMax = seed.y;
    int _8_connectivity = (flags & 255) == 8;
136
    FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
137 138 139

    L = R = XMin = XMax = seed.x;

140 141
    _Tp val0 = img[L];
    img[L] = newVal;
142

143 144
    while( ++R < roi.width && img[R] == val0 )
        img[R] = newVal;
145

146 147
    while( --L >= 0 && img[L] == val0 )
        img[L] = newVal;
148 149 150

    XMax = --R;
    XMin = ++L;
Evgeny Talanin's avatar
Evgeny Talanin committed
151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    ICV_PUSH( seed.y, L, R, R + 1, R, UP );

    while( head != tail )
    {
        int k, YC, PL, PR, dir;
        ICV_POP( YC, L, R, PL, PR, dir );

        int data[][3] =
        {
            {-dir, L - _8_connectivity, R + _8_connectivity},
            {dir, L - _8_connectivity, PL - 1},
            {dir, PR + 1, R + _8_connectivity}
        };

        if( region )
        {
            area += R - L + 1;

            if( XMax < R ) XMax = R;
            if( XMin > L ) XMin = L;
            if( YMax < YC ) YMax = YC;
            if( YMin > YC ) YMin = YC;
        }

176
        for( k = 0; k < 3; k++ )
177 178
        {
            dir = data[k][0];
179
            img = (_Tp*)(image.data + (YC + dir) * image.step);
180 181 182 183 184 185
            int left = data[k][1];
            int right = data[k][2];

            if( (unsigned)(YC + dir) >= (unsigned)roi.height )
                continue;

186 187 188
            for( i = left; i <= right; i++ )
            {
                if( (unsigned)i < (unsigned)roi.width && img[i] == val0 )
189
                {
190 191 192 193
                    int j = i;
                    img[i] = newVal;
                    while( --j >= 0 && img[j] == val0 )
                        img[j] = newVal;
194

195 196
                    while( ++i < roi.width && img[i] == val0 )
                        img[i] = newVal;
197

198
                    ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
199
                }
200
            }
201 202 203 204 205
        }
    }

    if( region )
    {
206
        region->pt = seed;
207 208 209 210 211 212 213 214 215 216 217 218
        region->area = area;
        region->rect.x = XMin;
        region->rect.y = YMin;
        region->rect.width = XMax - XMin + 1;
        region->rect.height = YMax - YMin + 1;
    }
}

/****************************************************************************************\
*                                   Gradient Floodfill                                   *
\****************************************************************************************/

219
struct Diff8uC1
220
{
221 222 223 224 225
    Diff8uC1(uchar _lo, uchar _up) : lo(_lo), interval(_lo + _up) {}
    bool operator()(const uchar* a, const uchar* b) const
    { return (unsigned)(a[0] - b[0] + lo) <= interval; }
    unsigned lo, interval;
};
226

227 228
struct Diff8uC3
{
229
    Diff8uC3(Vec3b _lo, Vec3b _up)
230
    {
231 232
        for( int k = 0; k < 3; k++ )
            lo[k] = _lo[k], interval[k] = _lo[k] + _up[k];
233
    }
234
    bool operator()(const Vec3b* a, const Vec3b* b) const
235
    {
236 237 238
        return (unsigned)(a[0][0] - b[0][0] + lo[0]) <= interval[0] &&
               (unsigned)(a[0][1] - b[0][1] + lo[1]) <= interval[1] &&
               (unsigned)(a[0][2] - b[0][2] + lo[2]) <= interval[2];
239
    }
240 241
    unsigned lo[3], interval[3];
};
242

243 244 245 246 247 248 249 250
template<typename _Tp>
struct DiffC1
{
    DiffC1(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {}
    bool operator()(const _Tp* a, const _Tp* b) const
    {
        _Tp d = a[0] - b[0];
        return lo <= d && d <= up;
251
    }
252 253
    _Tp lo, up;
};
254

255 256 257 258 259
template<typename _Tp>
struct DiffC3
{
    DiffC3(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {}
    bool operator()(const _Tp* a, const _Tp* b) const
260
    {
261 262 263 264
        _Tp d = *a - *b;
        return lo[0] <= d[0] && d[0] <= up[0] &&
               lo[1] <= d[1] && d[1] <= up[1] &&
               lo[2] <= d[2] && d[2] <= up[2];
265
    }
266 267
    _Tp lo, up;
};
268

269
typedef DiffC1<int> Diff32sC1;
270
typedef DiffC3<Vec3i> Diff32sC3;
271
typedef DiffC1<float> Diff32fC1;
272
typedef DiffC3<Vec3f> Diff32fC3;
273

274
template<typename _Tp, typename _MTp, typename _WTp, class Diff>
275
static void
276 277 278 279
floodFillGrad_CnIR( Mat& image, Mat& msk,
                   Point seed, _Tp newVal, _MTp newMaskVal,
                   Diff diff, ConnectedComp* region, int flags,
                   std::vector<FFillSegment>* buffer )
280
{
281 282
    int step = (int)image.step, maskStep = (int)msk.step;
    uchar* pImage = image.data;
283
    _Tp* img = (_Tp*)(pImage + step*seed.y);
284 285
    uchar* pMask = msk.data + maskStep + sizeof(_MTp);
    _MTp* mask = (_MTp*)(pMask + maskStep*seed.y);
286 287 288 289
    int i, L, R;
    int area = 0;
    int XMin, XMax, YMin = seed.y, YMax = seed.y;
    int _8_connectivity = (flags & 255) == 8;
290 291 292
    int fixedRange = flags & FLOODFILL_FIXED_RANGE;
    int fillImage = (flags & FLOODFILL_MASK_ONLY) == 0;
    FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
293 294 295 296 297 298

    L = R = seed.x;
    if( mask[L] )
        return;

    mask[L] = newMaskVal;
299
    _Tp val0 = img[L];
300

301
    if( fixedRange )
302
    {
303 304
        while( !mask[R + 1] && diff( img + (R+1), &val0 ))
            mask[++R] = newMaskVal;
305

306 307
        while( !mask[L - 1] && diff( img + (L-1), &val0 ))
            mask[--L] = newMaskVal;
308 309 310
    }
    else
    {
311 312
        while( !mask[R + 1] && diff( img + (R+1), img + R ))
            mask[++R] = newMaskVal;
313

314 315
        while( !mask[L - 1] && diff( img + (L-1), img + L ))
            mask[--L] = newMaskVal;
316 317 318 319
    }

    XMax = R;
    XMin = L;
Evgeny Talanin's avatar
Evgeny Talanin committed
320

321 322 323 324
    ICV_PUSH( seed.y, L, R, R + 1, R, UP );

    while( head != tail )
    {
325
        int k, YC, PL, PR, dir;
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
        ICV_POP( YC, L, R, PL, PR, dir );

        int data[][3] =
        {
            {-dir, L - _8_connectivity, R + _8_connectivity},
            {dir, L - _8_connectivity, PL - 1},
            {dir, PR + 1, R + _8_connectivity}
        };

        unsigned length = (unsigned)(R-L);

        if( region )
        {
            area += (int)length + 1;

            if( XMax < R ) XMax = R;
            if( XMin > L ) XMin = L;
            if( YMax < YC ) YMax = YC;
            if( YMin > YC ) YMin = YC;
        }

347
        for( k = 0; k < 3; k++ )
348
        {
349 350 351
            dir = data[k][0];
            img = (_Tp*)(pImage + (YC + dir) * step);
            _Tp* img1 = (_Tp*)(pImage + YC * step);
352
            mask = (_MTp*)(pMask + (YC + dir) * maskStep);
353 354
            int left = data[k][1];
            int right = data[k][2];
355

356 357 358 359
            if( fixedRange )
                for( i = left; i <= right; i++ )
                {
                    if( !mask[i] && diff( img + i, &val0 ))
360
                    {
361 362 363 364
                        int j = i;
                        mask[i] = newMaskVal;
                        while( !mask[--j] && diff( img + j, &val0 ))
                            mask[j] = newMaskVal;
365

366 367
                        while( !mask[++i] && diff( img + i, &val0 ))
                            mask[i] = newMaskVal;
368

369
                        ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
370
                    }
371 372 373 374 375
                }
            else if( !_8_connectivity )
                for( i = left; i <= right; i++ )
                {
                    if( !mask[i] && diff( img + i, img1 + i ))
376
                    {
377 378 379 380
                        int j = i;
                        mask[i] = newMaskVal;
                        while( !mask[--j] && diff( img + j, img + (j+1) ))
                            mask[j] = newMaskVal;
381

382
                        while( !mask[++i] &&
383
                              (diff( img + i, img + (i-1) ) ||
384
                               (diff( img + i, img1 + i) && i <= R)))
385 386
                            mask[i] = newMaskVal;

387
                        ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
388
                    }
389 390 391 392 393 394 395 396
                }
            else
                for( i = left; i <= right; i++ )
                {
                    int idx;
                    _Tp val;

                    if( !mask[i] &&
397 398 399
                       (((val = img[i],
                          (unsigned)(idx = i-L-1) <= length) &&
                         diff( &val, img1 + (i-1))) ||
400
                        ((unsigned)(++idx) <= length &&
401
                         diff( &val, img1 + i )) ||
402
                        ((unsigned)(++idx) <= length &&
403
                         diff( &val, img1 + (i+1) ))))
404
                    {
405 406 407 408 409 410
                        int j = i;
                        mask[i] = newMaskVal;
                        while( !mask[--j] && diff( img + j, img + (j+1) ))
                            mask[j] = newMaskVal;

                        while( !mask[++i] &&
411 412
                              ((val = img[i],
                                diff( &val, img + (i-1) )) ||
413
                               (((unsigned)(idx = i-L-1) <= length &&
414
                                 diff( &val, img1 + (i-1) ))) ||
415
                               ((unsigned)(++idx) <= length &&
416
                                diff( &val, img1 + i )) ||
417
                               ((unsigned)(++idx) <= length &&
418
                                diff( &val, img1 + (i+1) ))))
419 420
                            mask[i] = newMaskVal;

421
                        ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
422 423 424
                    }
                }
        }
425 426 427 428 429

        img = (_Tp*)(pImage + YC * step);
        if( fillImage )
            for( i = L; i <= R; i++ )
                img[i] = newVal;
430 431 432
        /*else if( region )
         for( i = L; i <= R; i++ )
         sum += img[i];*/
433 434 435 436
    }

    if( region )
    {
437 438
        region->pt = seed;
        region->label = saturate_cast<int>(newMaskVal);
439 440 441 442 443 444 445 446
        region->area = area;
        region->rect.x = XMin;
        region->rect.y = YMin;
        region->rect.width = XMax - XMin + 1;
        region->rect.height = YMax - YMin + 1;
    }
}

447
}
448 449 450 451 452

/****************************************************************************************\
*                                    External Functions                                  *
\****************************************************************************************/

453 454 455
int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
                  Point seedPoint, Scalar newVal, Rect* rect,
                  Scalar loDiff, Scalar upDiff, int flags )
456
{
457
    ConnectedComp comp;
458
    std::vector<FFillSegment> buffer;
459

460 461
    if( rect )
        *rect = Rect();
462

463
    int i, connectivity = flags & 255;
464 465 466 467 468 469 470 471
    union {
        uchar b[4];
        int i[4];
        float f[4];
        double _[4];
    } nv_buf;
    nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0;

472 473 474 475 476
    struct { Vec3b b; Vec3i i; Vec3f f; } ld_buf, ud_buf;
    Mat img = _image.getMat(), mask;
    if( !_mask.empty() )
        mask = _mask.getMat();
    Size size = img.size();
477

478 479 480
    int type = img.type();
    int depth = img.depth();
    int cn = img.channels();
481 482 483 484 485 486

    if( connectivity == 0 )
        connectivity = 4;
    else if( connectivity != 4 && connectivity != 8 )
        CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );

487
    bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0;
488 489 490

    for( i = 0; i < cn; i++ )
    {
491
        if( loDiff[i] < 0 || upDiff[i] < 0 )
492
            CV_Error( CV_StsBadArg, "lo_diff and up_diff must be non-negative" );
493
        is_simple = is_simple && fabs(loDiff[i]) < DBL_EPSILON && fabs(upDiff[i]) < DBL_EPSILON;
494 495
    }

496 497
    if( (unsigned)seedPoint.x >= (unsigned)size.width ||
       (unsigned)seedPoint.y >= (unsigned)size.height )
498 499
        CV_Error( CV_StsOutOfRange, "Seed point is outside of image" );

500 501
    scalarToRawData( newVal, &nv_buf, type, 0);
    size_t buffer_size = MAX( size.width, size.height ) * 2;
Evgeny Talanin's avatar
Evgeny Talanin committed
502
    buffer.resize( buffer_size );
503 504 505

    if( is_simple )
    {
Andrey Kamaev's avatar
Andrey Kamaev committed
506
        size_t elem_size = img.elemSize();
507
        const uchar* seed_ptr = img.data + img.step*seedPoint.y + elem_size*seedPoint.x;
508

Andrey Kamaev's avatar
Andrey Kamaev committed
509 510 511
        size_t k = 0;
        for(; k < elem_size; k++)
            if (seed_ptr[k] != nv_buf.b[k])
512
                break;
513

Andrey Kamaev's avatar
Andrey Kamaev committed
514
        if( k != elem_size )
Evgeny Talanin's avatar
Evgeny Talanin committed
515 516
        {
            if( type == CV_8UC1 )
517
                floodFill_CnIR(img, seedPoint, nv_buf.b[0], &comp, flags, &buffer);
Evgeny Talanin's avatar
Evgeny Talanin committed
518
            else if( type == CV_8UC3 )
519
                floodFill_CnIR(img, seedPoint, Vec3b(nv_buf.b), &comp, flags, &buffer);
Evgeny Talanin's avatar
Evgeny Talanin committed
520
            else if( type == CV_32SC1 )
521
                floodFill_CnIR(img, seedPoint, nv_buf.i[0], &comp, flags, &buffer);
Evgeny Talanin's avatar
Evgeny Talanin committed
522
            else if( type == CV_32FC1 )
523
                floodFill_CnIR(img, seedPoint, nv_buf.f[0], &comp, flags, &buffer);
Evgeny Talanin's avatar
Evgeny Talanin committed
524
            else if( type == CV_32SC3 )
525
                floodFill_CnIR(img, seedPoint, Vec3i(nv_buf.i), &comp, flags, &buffer);
Evgeny Talanin's avatar
Evgeny Talanin committed
526
            else if( type == CV_32FC3 )
527
                floodFill_CnIR(img, seedPoint, Vec3f(nv_buf.f), &comp, flags, &buffer);
Evgeny Talanin's avatar
Evgeny Talanin committed
528 529
            else
                CV_Error( CV_StsUnsupportedFormat, "" );
530 531 532
            if( rect )
                *rect = comp.rect;
            return comp.area;
Evgeny Talanin's avatar
Evgeny Talanin committed
533
        }
534 535
    }

536
    if( mask.empty() )
537
    {
538 539
        Mat tempMask( size.height + 2, size.width + 2, CV_8UC1 );
        tempMask.setTo(Scalar::all(0));
540 541 542 543
        mask = tempMask;
    }
    else
    {
544 545
        CV_Assert( mask.rows == size.height+2 && mask.cols == size.width+2 );
        CV_Assert( mask.type() == CV_8U );
546 547
    }

548 549
    memset( mask.data, 1, mask.cols );
    memset( mask.data + mask.step*(mask.rows-1), 1, mask.cols );
550

551
    for( i = 1; i <= size.height; i++ )
552
    {
553
        mask.at<uchar>(i, 0) = mask.at<uchar>(i, mask.cols-1) = (uchar)1;
554 555 556 557 558
    }

    if( depth == CV_8U )
        for( i = 0; i < cn; i++ )
        {
559 560
            ld_buf.b[i] = saturate_cast<uchar>(cvFloor(loDiff[i]));
            ud_buf.b[i] = saturate_cast<uchar>(cvFloor(upDiff[i]));
561
        }
562 563 564
    else if( depth == CV_32S )
        for( i = 0; i < cn; i++ )
        {
565 566
            ld_buf.i[i] = cvFloor(loDiff[i]);
            ud_buf.i[i] = cvFloor(upDiff[i]);
567 568
        }
    else if( depth == CV_32F )
569 570
        for( i = 0; i < cn; i++ )
        {
571 572
            ld_buf.f[i] = (float)loDiff[i];
            ud_buf.f[i] = (float)upDiff[i];
573
        }
574 575
    else
        CV_Error( CV_StsUnsupportedFormat, "" );
576

577 578
    uchar newMaskVal = (uchar)((flags & ~0xff) == 0 ? 1 : ((flags >> 8) & 255));

579
    if( type == CV_8UC1 )
580 581 582 583
        floodFillGrad_CnIR<uchar, uchar, int, Diff8uC1>(
                img, mask, seedPoint, nv_buf.b[0], newMaskVal,
                Diff8uC1(ld_buf.b[0], ud_buf.b[0]),
                &comp, flags, &buffer);
584
    else if( type == CV_8UC3 )
585 586 587 588
        floodFillGrad_CnIR<Vec3b, uchar, Vec3i, Diff8uC3>(
                img, mask, seedPoint, Vec3b(nv_buf.b), newMaskVal,
                Diff8uC3(ld_buf.b, ud_buf.b),
                &comp, flags, &buffer);
589
    else if( type == CV_32SC1 )
590 591 592 593
        floodFillGrad_CnIR<int, uchar, int, Diff32sC1>(
                img, mask, seedPoint, nv_buf.i[0], newMaskVal,
                Diff32sC1(ld_buf.i[0], ud_buf.i[0]),
                &comp, flags, &buffer);
594
    else if( type == CV_32SC3 )
595 596 597 598
        floodFillGrad_CnIR<Vec3i, uchar, Vec3i, Diff32sC3>(
                img, mask, seedPoint, Vec3i(nv_buf.i), newMaskVal,
                Diff32sC3(ld_buf.i, ud_buf.i),
                &comp, flags, &buffer);
599
    else if( type == CV_32FC1 )
600 601 602 603
        floodFillGrad_CnIR<float, uchar, float, Diff32fC1>(
                img, mask, seedPoint, nv_buf.f[0], newMaskVal,
                Diff32fC1(ld_buf.f[0], ud_buf.f[0]),
                &comp, flags, &buffer);
604
    else if( type == CV_32FC3 )
605 606 607 608
        floodFillGrad_CnIR<Vec3f, uchar, Vec3f, Diff32fC3>(
                img, mask, seedPoint, Vec3f(nv_buf.f), newMaskVal,
                Diff32fC3(ld_buf.f, ud_buf.f),
                &comp, flags, &buffer);
609 610
    else
        CV_Error(CV_StsUnsupportedFormat, "");
611

612 613 614
    if( rect )
        *rect = comp.rect;
    return comp.area;
615 616 617
}


618
int cv::floodFill( InputOutputArray _image, Point seedPoint,
619 620
                  Scalar newVal, Rect* rect,
                  Scalar loDiff, Scalar upDiff, int flags )
621
{
622
    return floodFill(_image, Mat(), seedPoint, newVal, rect, loDiff, upDiff, flags);
623 624
}

625 626 627 628 629

CV_IMPL void
cvFloodFill( CvArr* arr, CvPoint seed_point,
             CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
             CvConnectedComp* comp, int flags, CvArr* maskarr )
630
{
631 632 633 634 635 636 637 638 639 640 641 642
    if( comp )
        memset( comp, 0, sizeof(*comp) );

    cv::Mat img = cv::cvarrToMat(arr), mask = cv::cvarrToMat(maskarr);
    int area = cv::floodFill(img, mask, seed_point, newVal,
                             comp ? (cv::Rect*)&comp->rect : 0,
                             lo_diff, up_diff, flags );
    if( comp )
    {
        comp->area = area;
        comp->value = newVal;
    }
643 644 645
}

/* End of file. */