2010-05-12 01:44:00 +08:00
|
|
|
/*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.
|
|
|
|
//
|
|
|
|
//
|
2013-02-12 03:49:10 +08:00
|
|
|
// License Agreement
|
2010-05-12 01:44:00 +08:00
|
|
|
// For Open Source Computer Vision Library
|
|
|
|
//
|
|
|
|
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
2013-02-12 03:49:10 +08:00
|
|
|
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
2010-05-12 01:44:00 +08:00
|
|
|
// 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.
|
|
|
|
//
|
2013-02-12 03:49:10 +08:00
|
|
|
// * The name of the copyright holders may not be used to endorse or promote products
|
2010-05-12 01:44:00 +08:00
|
|
|
// 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"
|
|
|
|
|
2014-02-18 16:01:01 +08:00
|
|
|
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
|
2013-10-01 16:58:39 +08:00
|
|
|
# pragma GCC diagnostic ignored "-Warray-bounds"
|
|
|
|
#endif
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
namespace cv
|
|
|
|
{
|
|
|
|
|
|
|
|
struct FFillSegment
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
|
|
|
ushort y;
|
|
|
|
ushort l;
|
|
|
|
ushort r;
|
|
|
|
ushort prevl;
|
|
|
|
ushort prevr;
|
|
|
|
short dir;
|
2013-02-12 03:49:10 +08:00
|
|
|
};
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
UP = 1,
|
|
|
|
DOWN = -1
|
|
|
|
};
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-10-11 17:45:21 +08:00
|
|
|
#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 ) \
|
|
|
|
{ \
|
2013-02-12 03:49:10 +08:00
|
|
|
buffer->resize(buffer->size() * 3/2); \
|
2012-10-11 17:45:21 +08:00
|
|
|
tail = &buffer->front() + (tail - head); \
|
|
|
|
head = &buffer->front(); \
|
|
|
|
buffer_end = head + buffer->size(); \
|
|
|
|
} \
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2012-10-11 17:45:21 +08:00
|
|
|
#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; \
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
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)
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
template<typename _Tp>
|
2010-05-12 01:44:00 +08:00
|
|
|
static void
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR( Mat& image, Point seed,
|
|
|
|
_Tp newVal, ConnectedComp* region, int flags,
|
|
|
|
std::vector<FFillSegment>* buffer )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2014-08-13 19:08:27 +08:00
|
|
|
_Tp* img = image.ptr<_Tp>(seed.y);
|
2013-02-12 03:49:10 +08:00
|
|
|
Size roi = image.size();
|
2010-05-12 01:44:00 +08:00
|
|
|
int i, L, R;
|
|
|
|
int area = 0;
|
|
|
|
int XMin, XMax, YMin = seed.y, YMax = seed.y;
|
|
|
|
int _8_connectivity = (flags & 255) == 8;
|
2013-02-12 03:49:10 +08:00
|
|
|
FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
L = R = XMin = XMax = seed.x;
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
_Tp val0 = img[L];
|
|
|
|
img[L] = newVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( ++R < roi.width && img[R] == val0 )
|
|
|
|
img[R] = newVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( --L >= 0 && img[L] == val0 )
|
|
|
|
img[L] = newVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
XMax = --R;
|
|
|
|
XMin = ++L;
|
2012-10-11 17:45:21 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
for( k = 0; k < 3; k++ )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
|
|
|
dir = data[k][0];
|
|
|
|
|
|
|
|
if( (unsigned)(YC + dir) >= (unsigned)roi.height )
|
|
|
|
continue;
|
|
|
|
|
2014-08-16 04:29:10 +08:00
|
|
|
img = image.ptr<_Tp>(YC + dir);
|
|
|
|
int left = data[k][1];
|
|
|
|
int right = data[k][2];
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
for( i = left; i <= right; i++ )
|
|
|
|
{
|
|
|
|
if( (unsigned)i < (unsigned)roi.width && img[i] == val0 )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
int j = i;
|
|
|
|
img[i] = newVal;
|
|
|
|
while( --j >= 0 && img[j] == val0 )
|
|
|
|
img[j] = newVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( ++i < roi.width && img[i] == val0 )
|
|
|
|
img[i] = newVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( region )
|
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
region->pt = seed;
|
2010-05-12 01:44:00 +08:00
|
|
|
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 *
|
|
|
|
\****************************************************************************************/
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
struct Diff8uC1
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
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;
|
|
|
|
};
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
struct Diff8uC3
|
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
Diff8uC3(Vec3b _lo, Vec3b _up)
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
for( int k = 0; k < 3; k++ )
|
|
|
|
lo[k] = _lo[k], interval[k] = _lo[k] + _up[k];
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2013-02-12 03:49:10 +08:00
|
|
|
bool operator()(const Vec3b* a, const Vec3b* b) const
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
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];
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
unsigned lo[3], interval[3];
|
|
|
|
};
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
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;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
_Tp lo, up;
|
|
|
|
};
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
template<typename _Tp>
|
|
|
|
struct DiffC3
|
|
|
|
{
|
|
|
|
DiffC3(_Tp _lo, _Tp _up) : lo(-_lo), up(_up) {}
|
|
|
|
bool operator()(const _Tp* a, const _Tp* b) const
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
_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];
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
_Tp lo, up;
|
|
|
|
};
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
typedef DiffC1<int> Diff32sC1;
|
2013-02-12 03:49:10 +08:00
|
|
|
typedef DiffC3<Vec3i> Diff32sC3;
|
2012-03-30 01:08:03 +08:00
|
|
|
typedef DiffC1<float> Diff32fC1;
|
2013-02-12 03:49:10 +08:00
|
|
|
typedef DiffC3<Vec3f> Diff32fC3;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
template<typename _Tp, typename _MTp, typename _WTp, class Diff>
|
2010-05-12 01:44:00 +08:00
|
|
|
static void
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFillGrad_CnIR( Mat& image, Mat& msk,
|
|
|
|
Point seed, _Tp newVal, _MTp newMaskVal,
|
|
|
|
Diff diff, ConnectedComp* region, int flags,
|
|
|
|
std::vector<FFillSegment>* buffer )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2022-11-07 19:40:02 +08:00
|
|
|
size_t step = image.step, maskStep = msk.step;
|
2014-08-13 19:08:27 +08:00
|
|
|
uchar* pImage = image.ptr();
|
2012-03-30 01:08:03 +08:00
|
|
|
_Tp* img = (_Tp*)(pImage + step*seed.y);
|
2014-08-13 19:08:27 +08:00
|
|
|
uchar* pMask = msk.ptr() + maskStep + sizeof(_MTp);
|
2013-02-12 03:49:10 +08:00
|
|
|
_MTp* mask = (_MTp*)(pMask + maskStep*seed.y);
|
2010-05-12 01:44:00 +08:00
|
|
|
int i, L, R;
|
|
|
|
int area = 0;
|
|
|
|
int XMin, XMax, YMin = seed.y, YMax = seed.y;
|
|
|
|
int _8_connectivity = (flags & 255) == 8;
|
2013-02-12 03:49:10 +08:00
|
|
|
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();
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
L = R = seed.x;
|
|
|
|
if( mask[L] )
|
|
|
|
return;
|
|
|
|
|
|
|
|
mask[L] = newMaskVal;
|
2012-03-30 01:08:03 +08:00
|
|
|
_Tp val0 = img[L];
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
if( fixedRange )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
while( !mask[R + 1] && diff( img + (R+1), &val0 ))
|
|
|
|
mask[++R] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( !mask[L - 1] && diff( img + (L-1), &val0 ))
|
|
|
|
mask[--L] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
while( !mask[R + 1] && diff( img + (R+1), img + R ))
|
|
|
|
mask[++R] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( !mask[L - 1] && diff( img + (L-1), img + L ))
|
|
|
|
mask[--L] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
XMax = R;
|
|
|
|
XMin = L;
|
2012-10-11 17:45:21 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
ICV_PUSH( seed.y, L, R, R + 1, R, UP );
|
|
|
|
|
|
|
|
while( head != tail )
|
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
int k, YC, PL, PR, dir;
|
2010-05-12 01:44:00 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
for( k = 0; k < 3; k++ )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
dir = data[k][0];
|
|
|
|
img = (_Tp*)(pImage + (YC + dir) * step);
|
|
|
|
_Tp* img1 = (_Tp*)(pImage + YC * step);
|
2013-02-12 03:49:10 +08:00
|
|
|
mask = (_MTp*)(pMask + (YC + dir) * maskStep);
|
2012-03-30 01:08:03 +08:00
|
|
|
int left = data[k][1];
|
|
|
|
int right = data[k][2];
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
if( fixedRange )
|
|
|
|
for( i = left; i <= right; i++ )
|
|
|
|
{
|
|
|
|
if( !mask[i] && diff( img + i, &val0 ))
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
int j = i;
|
|
|
|
mask[i] = newMaskVal;
|
|
|
|
while( !mask[--j] && diff( img + j, &val0 ))
|
|
|
|
mask[j] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( !mask[++i] && diff( img + i, &val0 ))
|
|
|
|
mask[i] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
}
|
|
|
|
else if( !_8_connectivity )
|
|
|
|
for( i = left; i <= right; i++ )
|
|
|
|
{
|
|
|
|
if( !mask[i] && diff( img + i, img1 + i ))
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
int j = i;
|
|
|
|
mask[i] = newMaskVal;
|
|
|
|
while( !mask[--j] && diff( img + j, img + (j+1) ))
|
|
|
|
mask[j] = newMaskVal;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
while( !mask[++i] &&
|
2013-02-12 03:49:10 +08:00
|
|
|
(diff( img + i, img + (i-1) ) ||
|
2012-03-30 01:08:03 +08:00
|
|
|
(diff( img + i, img1 + i) && i <= R)))
|
2010-05-12 01:44:00 +08:00
|
|
|
mask[i] = newMaskVal;
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
for( i = left; i <= right; i++ )
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
_Tp val;
|
|
|
|
|
|
|
|
if( !mask[i] &&
|
2013-02-12 03:49:10 +08:00
|
|
|
(((val = img[i],
|
|
|
|
(unsigned)(idx = i-L-1) <= length) &&
|
|
|
|
diff( &val, img1 + (i-1))) ||
|
2012-03-30 01:08:03 +08:00
|
|
|
((unsigned)(++idx) <= length &&
|
2013-02-12 03:49:10 +08:00
|
|
|
diff( &val, img1 + i )) ||
|
2012-03-30 01:08:03 +08:00
|
|
|
((unsigned)(++idx) <= length &&
|
2013-02-12 03:49:10 +08:00
|
|
|
diff( &val, img1 + (i+1) ))))
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2012-03-30 01:08:03 +08:00
|
|
|
int j = i;
|
|
|
|
mask[i] = newMaskVal;
|
|
|
|
while( !mask[--j] && diff( img + j, img + (j+1) ))
|
|
|
|
mask[j] = newMaskVal;
|
|
|
|
|
|
|
|
while( !mask[++i] &&
|
2013-02-12 03:49:10 +08:00
|
|
|
((val = img[i],
|
|
|
|
diff( &val, img + (i-1) )) ||
|
2012-03-30 01:08:03 +08:00
|
|
|
(((unsigned)(idx = i-L-1) <= length &&
|
2013-02-12 03:49:10 +08:00
|
|
|
diff( &val, img1 + (i-1) ))) ||
|
2012-03-30 01:08:03 +08:00
|
|
|
((unsigned)(++idx) <= length &&
|
2013-02-12 03:49:10 +08:00
|
|
|
diff( &val, img1 + i )) ||
|
2012-03-30 01:08:03 +08:00
|
|
|
((unsigned)(++idx) <= length &&
|
2013-02-12 03:49:10 +08:00
|
|
|
diff( &val, img1 + (i+1) ))))
|
2010-05-12 01:44:00 +08:00
|
|
|
mask[i] = newMaskVal;
|
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
|
|
|
|
img = (_Tp*)(pImage + YC * step);
|
|
|
|
if( fillImage )
|
|
|
|
for( i = L; i <= R; i++ )
|
|
|
|
img[i] = newVal;
|
2013-02-12 03:49:10 +08:00
|
|
|
/*else if( region )
|
|
|
|
for( i = L; i <= R; i++ )
|
|
|
|
sum += img[i];*/
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if( region )
|
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
region->pt = seed;
|
|
|
|
region->label = saturate_cast<int>(newMaskVal);
|
2010-05-12 01:44:00 +08:00
|
|
|
region->area = area;
|
|
|
|
region->rect.x = XMin;
|
|
|
|
region->rect.y = YMin;
|
|
|
|
region->rect.width = XMax - XMin + 1;
|
|
|
|
region->rect.height = YMax - YMin + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
/****************************************************************************************\
|
|
|
|
* External Functions *
|
|
|
|
\****************************************************************************************/
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
|
|
|
|
Point seedPoint, Scalar newVal, Rect* rect,
|
|
|
|
Scalar loDiff, Scalar upDiff, int flags )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2018-09-14 05:35:26 +08:00
|
|
|
CV_INSTRUMENT_REGION();
|
2016-08-18 14:53:00 +08:00
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
ConnectedComp comp;
|
2013-02-25 00:14:01 +08:00
|
|
|
std::vector<FFillSegment> buffer;
|
2012-06-08 01:21:29 +08:00
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
if( rect )
|
|
|
|
*rect = Rect();
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2018-07-24 19:14:13 +08:00
|
|
|
int i;
|
2012-03-31 00:10:52 +08:00
|
|
|
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;
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
struct { Vec3b b; Vec3i i; Vec3f f; } ld_buf, ud_buf;
|
2022-02-08 13:37:04 +08:00
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
Mat img = _image.getMat(), mask;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2022-02-08 13:37:04 +08:00
|
|
|
Size size = img.size();
|
2013-02-12 03:49:10 +08:00
|
|
|
int type = img.type();
|
|
|
|
int depth = img.depth();
|
|
|
|
int cn = img.channels();
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2014-08-13 17:46:43 +08:00
|
|
|
if ( (cn != 1) && (cn != 3) )
|
|
|
|
{
|
|
|
|
CV_Error( CV_StsBadArg, "Number of channels in input image must be 1 or 3" );
|
|
|
|
}
|
|
|
|
|
2018-07-24 19:14:13 +08:00
|
|
|
const int connectivity = flags & 255;
|
|
|
|
if( connectivity != 0 && connectivity != 4 && connectivity != 8 )
|
2010-05-12 01:44:00 +08:00
|
|
|
CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
|
|
|
|
|
2022-02-08 13:37:04 +08:00
|
|
|
if( _mask.empty() )
|
|
|
|
{
|
|
|
|
_mask.create( size.height + 2, size.width + 2, CV_8UC1 );
|
|
|
|
_mask.setTo(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
mask = _mask.getMat();
|
|
|
|
CV_CheckTypeEQ( mask.type(), CV_8U, "" );
|
|
|
|
CV_CheckEQ( mask.rows, size.height + 2, "" );
|
|
|
|
CV_CheckEQ( mask.cols, size.width + 2, "" );
|
|
|
|
|
|
|
|
Mat mask_inner = mask( Rect(1, 1, mask.cols - 2, mask.rows - 2) );
|
|
|
|
copyMakeBorder( mask_inner, mask, 1, 1, 1, 1, BORDER_ISOLATED | BORDER_CONSTANT, Scalar(1) );
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0;
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
for( i = 0; i < cn; i++ )
|
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
if( loDiff[i] < 0 || upDiff[i] < 0 )
|
2010-05-12 01:44:00 +08:00
|
|
|
CV_Error( CV_StsBadArg, "lo_diff and up_diff must be non-negative" );
|
2013-02-12 03:49:10 +08:00
|
|
|
is_simple = is_simple && fabs(loDiff[i]) < DBL_EPSILON && fabs(upDiff[i]) < DBL_EPSILON;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
if( (unsigned)seedPoint.x >= (unsigned)size.width ||
|
|
|
|
(unsigned)seedPoint.y >= (unsigned)size.height )
|
2010-05-12 01:44:00 +08:00
|
|
|
CV_Error( CV_StsOutOfRange, "Seed point is outside of image" );
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
scalarToRawData( newVal, &nv_buf, type, 0);
|
|
|
|
size_t buffer_size = MAX( size.width, size.height ) * 2;
|
2012-10-11 17:45:21 +08:00
|
|
|
buffer.resize( buffer_size );
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
if( is_simple )
|
|
|
|
{
|
2013-02-25 15:08:27 +08:00
|
|
|
size_t elem_size = img.elemSize();
|
2014-08-13 19:08:27 +08:00
|
|
|
const uchar* seed_ptr = img.ptr(seedPoint.y) + elem_size*seedPoint.x;
|
2012-06-08 01:21:29 +08:00
|
|
|
|
2013-02-25 15:08:27 +08:00
|
|
|
size_t k = 0;
|
|
|
|
for(; k < elem_size; k++)
|
|
|
|
if (seed_ptr[k] != nv_buf.b[k])
|
2010-05-12 01:44:00 +08:00
|
|
|
break;
|
2012-06-08 01:21:29 +08:00
|
|
|
|
2013-02-25 15:08:27 +08:00
|
|
|
if( k != elem_size )
|
2012-10-09 18:52:47 +08:00
|
|
|
{
|
|
|
|
if( type == CV_8UC1 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR(img, seedPoint, nv_buf.b[0], &comp, flags, &buffer);
|
2012-10-09 18:52:47 +08:00
|
|
|
else if( type == CV_8UC3 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR(img, seedPoint, Vec3b(nv_buf.b), &comp, flags, &buffer);
|
2012-10-09 18:52:47 +08:00
|
|
|
else if( type == CV_32SC1 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR(img, seedPoint, nv_buf.i[0], &comp, flags, &buffer);
|
2012-10-09 18:52:47 +08:00
|
|
|
else if( type == CV_32FC1 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR(img, seedPoint, nv_buf.f[0], &comp, flags, &buffer);
|
2012-10-09 18:52:47 +08:00
|
|
|
else if( type == CV_32SC3 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR(img, seedPoint, Vec3i(nv_buf.i), &comp, flags, &buffer);
|
2012-10-09 18:52:47 +08:00
|
|
|
else if( type == CV_32FC3 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFill_CnIR(img, seedPoint, Vec3f(nv_buf.f), &comp, flags, &buffer);
|
2012-10-09 18:52:47 +08:00
|
|
|
else
|
|
|
|
CV_Error( CV_StsUnsupportedFormat, "" );
|
2013-02-12 03:49:10 +08:00
|
|
|
if( rect )
|
|
|
|
*rect = comp.rect;
|
|
|
|
return comp.area;
|
2012-10-09 18:52:47 +08:00
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if( depth == CV_8U )
|
|
|
|
for( i = 0; i < cn; i++ )
|
|
|
|
{
|
2023-07-07 00:27:16 +08:00
|
|
|
#if defined(__GNUC__) && (__GNUC__ == 12)
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
|
|
|
#endif
|
2013-02-12 03:49:10 +08:00
|
|
|
ld_buf.b[i] = saturate_cast<uchar>(cvFloor(loDiff[i]));
|
|
|
|
ud_buf.b[i] = saturate_cast<uchar>(cvFloor(upDiff[i]));
|
2023-07-07 00:27:16 +08:00
|
|
|
#if defined(__GNUC__) && (__GNUC__ == 12)
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
else if( depth == CV_32S )
|
|
|
|
for( i = 0; i < cn; i++ )
|
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
ld_buf.i[i] = cvFloor(loDiff[i]);
|
|
|
|
ud_buf.i[i] = cvFloor(upDiff[i]);
|
2012-03-30 01:08:03 +08:00
|
|
|
}
|
|
|
|
else if( depth == CV_32F )
|
2010-05-12 01:44:00 +08:00
|
|
|
for( i = 0; i < cn; i++ )
|
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
ld_buf.f[i] = (float)loDiff[i];
|
|
|
|
ud_buf.f[i] = (float)upDiff[i];
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2012-03-30 01:08:03 +08:00
|
|
|
else
|
|
|
|
CV_Error( CV_StsUnsupportedFormat, "" );
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2016-10-24 22:22:44 +08:00
|
|
|
uchar newMaskVal = (uchar)((flags & 0xff00) == 0 ? 1 : ((flags >> 8) & 255));
|
2013-02-12 03:49:10 +08:00
|
|
|
|
2012-03-30 01:08:03 +08:00
|
|
|
if( type == CV_8UC1 )
|
2013-02-12 03:49:10 +08:00
|
|
|
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);
|
2012-03-30 01:08:03 +08:00
|
|
|
else if( type == CV_8UC3 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFillGrad_CnIR<Vec3b, uchar, Vec3i, Diff8uC3>(
|
|
|
|
img, mask, seedPoint, Vec3b(nv_buf.b), newMaskVal,
|
|
|
|
Diff8uC3(ld_buf.b, ud_buf.b),
|
|
|
|
&comp, flags, &buffer);
|
2012-03-30 01:08:03 +08:00
|
|
|
else if( type == CV_32SC1 )
|
2013-02-12 03:49:10 +08:00
|
|
|
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);
|
2012-03-30 01:08:03 +08:00
|
|
|
else if( type == CV_32SC3 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFillGrad_CnIR<Vec3i, uchar, Vec3i, Diff32sC3>(
|
|
|
|
img, mask, seedPoint, Vec3i(nv_buf.i), newMaskVal,
|
|
|
|
Diff32sC3(ld_buf.i, ud_buf.i),
|
|
|
|
&comp, flags, &buffer);
|
2012-03-30 01:08:03 +08:00
|
|
|
else if( type == CV_32FC1 )
|
2013-02-12 03:49:10 +08:00
|
|
|
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);
|
2012-03-30 01:08:03 +08:00
|
|
|
else if( type == CV_32FC3 )
|
2013-02-12 03:49:10 +08:00
|
|
|
floodFillGrad_CnIR<Vec3f, uchar, Vec3f, Diff32fC3>(
|
|
|
|
img, mask, seedPoint, Vec3f(nv_buf.f), newMaskVal,
|
|
|
|
Diff32fC3(ld_buf.f, ud_buf.f),
|
|
|
|
&comp, flags, &buffer);
|
2012-03-30 01:08:03 +08:00
|
|
|
else
|
|
|
|
CV_Error(CV_StsUnsupportedFormat, "");
|
2013-05-21 18:35:24 +08:00
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
if( rect )
|
|
|
|
*rect = comp.rect;
|
|
|
|
return comp.area;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-17 21:14:45 +08:00
|
|
|
int cv::floodFill( InputOutputArray _image, Point seedPoint,
|
2013-02-12 03:49:10 +08:00
|
|
|
Scalar newVal, Rect* rect,
|
|
|
|
Scalar loDiff, Scalar upDiff, int flags )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2018-09-14 05:35:26 +08:00
|
|
|
CV_INSTRUMENT_REGION();
|
2016-08-18 14:53:00 +08:00
|
|
|
|
2022-02-08 13:37:04 +08:00
|
|
|
Mat mask;
|
|
|
|
return floodFill(_image, mask, seedPoint, newVal, rect, loDiff, upDiff, flags);
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2013-02-12 03:49:10 +08:00
|
|
|
|
|
|
|
CV_IMPL void
|
|
|
|
cvFloodFill( CvArr* arr, CvPoint seed_point,
|
|
|
|
CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
|
|
|
|
CvConnectedComp* comp, int flags, CvArr* maskarr )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2013-02-12 03:49:10 +08:00
|
|
|
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;
|
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* End of file. */
|