fix cv::floodfill() for calling it with an empty mask

pull/21577/head
Suleyman TURKMEN 3 years ago
parent 96e23c2ff6
commit ffee1a4126
  1. 7
      modules/imgproc/include/opencv2/imgproc.hpp
  2. 42
      modules/imgproc/src/floodfill.cpp
  3. 4
      modules/imgproc/test/test_floodfill.cpp

@ -3660,10 +3660,11 @@ a mask and then extract the contour, or copy the region to another image, and so
function unless the #FLOODFILL_MASK_ONLY flag is set in the second variant of the function. See
the details below.
@param mask Operation mask that should be a single-channel 8-bit image, 2 pixels wider and 2 pixels
taller than image. Since this is both an input and output parameter, you must take responsibility
of initializing it. Flood-filling cannot go across non-zero pixels in the input mask. For example,
taller than image. If an empty Mat is passed it will be created automatically. Since this is both an
input and output parameter, you must take responsibility of initializing it.
Flood-filling cannot go across non-zero pixels in the input mask. For example,
an edge detector output can be used as a mask to stop filling at edges. On output, pixels in the
mask corresponding to filled pixels in the image are set to 1 or to the a value specified in flags
mask corresponding to filled pixels in the image are set to 1 or to the specified value in flags
as described below. Additionally, the function fills the border of the mask with ones to simplify
internal processing. It is therefore possible to use the same mask in multiple calls to the function
to make sure the filled areas do not overlap.

@ -477,11 +477,10 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0;
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();
Size size = img.size();
int type = img.type();
int depth = img.depth();
int cn = img.channels();
@ -495,6 +494,20 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
if( connectivity != 0 && connectivity != 4 && connectivity != 8 )
CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
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) );
bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0;
for( i = 0; i < cn; i++ )
@ -544,26 +557,6 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
}
}
if( mask.empty() )
{
Mat tempMask( size.height + 2, size.width + 2, CV_8UC1 );
tempMask.setTo(Scalar::all(0));
mask = tempMask;
}
else
{
CV_Assert( mask.rows == size.height+2 && mask.cols == size.width+2 );
CV_Assert( mask.type() == CV_8U );
}
memset( mask.ptr(), 1, mask.cols );
memset( mask.ptr(mask.rows-1), 1, mask.cols );
for( i = 1; i <= size.height; i++ )
{
mask.at<uchar>(i, 0) = mask.at<uchar>(i, mask.cols-1) = (uchar)1;
}
if( depth == CV_8U )
for( i = 0; i < cn; i++ )
{
@ -632,7 +625,8 @@ int cv::floodFill( InputOutputArray _image, Point seedPoint,
{
CV_INSTRUMENT_REGION();
return floodFill(_image, Mat(), seedPoint, newVal, rect, loDiff, upDiff, flags);
Mat mask;
return floodFill(_image, mask, seedPoint, newVal, rect, loDiff, upDiff, flags);
}

@ -531,11 +531,11 @@ TEST(Imgproc_FloodFill, maskValue)
{
const int n = 50;
Mat img = Mat::zeros(n, n, CV_8U);
Mat mask = Mat::zeros(n + 2, n + 2, CV_8U);
Mat mask;
circle(img, Point(n/2, n/2), 20, Scalar(100), 4);
int flags = 4 + CV_FLOODFILL_MASK_ONLY;
int flags = 4 + FLOODFILL_MASK_ONLY;
floodFill(img, mask, Point(n/2 + 13, n/2), Scalar(100), NULL, Scalar(), Scalar(), flags);
ASSERT_EQ(1, cvtest::norm(mask.rowRange(1, n-1).colRange(1, n-1), NORM_INF));

Loading…
Cancel
Save