The flood fill operation fills the connected components with a given color. Starting from a seed point, the neighboring pixels are colored with a uniform color. The neighboring pixels can be within a specified range of the current pixel. The flood fill function is int floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(),int flags=4)
. The parameters loDiff
and upDiff
represent the range to check for every neighboring pixel (note that 3-channel difference thresholds can be specified). The parameter newVal
is the color to apply to the pixels that are in range. The lower part of the parameter flags
contains the pixel's connectivity value to use (4
or 8
). The upper part defines the mode of the operation.
Depending on this mode, the flood fill function will color a neighboring pixel in the input image if it is within the specified range (given by loDiff
and upDiff
) of either the current pixel or if the neighboring pixel is within the specified range of the original seed's value. The function can also be called with a mask image as the second parameter. If specified, the flood-filling operation will not go across non-zero pixels in the mask. Note that the mask should be a single-channel 8-bit image that is 2 pixels wider and 2 pixels taller than the input image.
The upper bit of flags
can be 0 or a combination of the following:
In OpenCV's flood fill example ([opencv_source_code]/samples/cpp/ffilldemo.cpp
), the mask is used only as an output parameter. In our floodFill
example, shown as the following code, we will use it as an input parameter in order to constrain the filling. The idea is to use the output of an edge detector as a mask. This should stop the filling process at the edges:
#include "opencv2/opencv.hpp" #include <iostream> using namespace std; using namespace cv; Mat image, image1, image_orig; int loDiff = 20, upDiff = 30; int loCanny=10, upCanny=150; void onMouse( int event, int x, int y, int, void* ) { if( event != CV_EVENT_LBUTTONDOWN ) return; Point seed = Point(x,y); int flags = 4 + CV_FLOODFILL_FIXED_RANGE; int b = (unsigned)theRNG() & 255; int g = (unsigned)theRNG() & 255; int r = (unsigned)theRNG() & 255; Rect ccomp; Scalar newVal = Scalar(b, g, r); Mat dst = image; // flood fill floodFill(dst, seed, newVal, &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); imshow("image", dst); // Using Canny edges as mask Mat mask; Canny(image_orig, mask, loCanny, upCanny); imshow("Canny edges", mask); copyMakeBorder(mask, mask, 1, 1, 1, 1, cv::BORDER_REPLICATE); Mat dst1 = image1; floodFill(dst1, mask, seed, newVal, &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); imshow("FF with Canny", dst1); moveWindow("Canny edges", image.cols,0); moveWindow("FF with Canny", 2*image.cols,0); } int main(int argc, char *argv[]) { // Read original image and clone it to contain results image = imread("lena.jpg", CV_LOAD_IMAGE_COLOR ); image_orig=image.clone(); image1=image.clone(); namedWindow( "image", WINDOW_AUTOSIZE ); imshow("image", image); createTrackbar( "lo_diff", "image", &loDiff, 255, 0 ); createTrackbar( "up_diff", "image", &upDiff, 255, 0 ); createTrackbar( "lo_Canny", "image", &loCanny, 255, 0 ); createTrackbar( "up_Canny", "image", &upCanny, 255, 0 ); setMouseCallback( "image", onMouse, 0 ); moveWindow("image", 0,0); cout << "Press any key to exit... "; waitKey(); // Wait for key press return 0; }
The preceding example reads and displays a color image and then creates four trackbars. The first two trackbars control loDiff
and upDiffvalues
for the floodFill
function. The other two trackbars control the lower and upper threshold parameters for the Canny edge detector. In this example, the user can click anywhere on the input image. The click position will be used as a seed point to perform a flood fill operation. Actually, upon each click, two calls are made to the floodFill
function. The first one simply fills a region using a random color. The second one uses a mask created from the output of the Canny edge detector. Note that the copyMakeBorder
function is necessary to form a 1-pixel wide border around the mask. The following screenshot shows the output of this example:
Note that the output that uses Canny edges (right) has filled in less pixels than the standard operation (left).