floodFill函数
函数作用:
用指定颜色填充一个连接域
void cvFloodFill( CvArr* image, CvPoint seed_point, CvScalar new_val, CvScalar lo_diff=cvScalarAll(0), CvScalar up_diff=cvScalarAll(0), CvConnectedComp* comp=NULL, int flags=4, CvArr* mask=NULL ); #define CV_FLOODFILL_FIXED_RANGE (1 << 16) #define CV_FLOODFILL_MASK_ONLY (1 << 17)
函数 cvFloodFill 用指定颜色,从种子点开始填充一个连通域。连通性由象素值的接近程度来衡量。在点 (x, y) 的象素被认为是属于重新绘制的区域,如果:
其中 src(x',y') 是象素邻域点的值。也就是说,为了被加入到连通域中,一个象素的彩色/亮度应该足够接近于:
opencv代码:
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace cv; using namespace std; //floodfill() //Fills a connected component with the given color. static void help() { cout << "\nThis program demonstrated the floodFill() function\n" "Call:\n" "./ffilldemo [image_name -- Default: fruits.jpg]\n" << endl; cout << "Hot keys: \n" "\tESC - quit the program\n" "\tc - switch color/grayscale mode\n" "\tm - switch mask mode\n" "\tr - restore the original image\n" "\ts - use null-range floodfill\n" "\tf - use gradient floodfill with fixed(absolute) range\n" "\tg - use gradient floodfill with floating(relative) range\n" "\t4 - use 4-connectivity mode\n" "\t8 - use 8-connectivity mode\n" << endl; } Mat image0, image, gray, mask; int ffillMode = 1; int loDiff = 20, upDiff = 20; int connectivity = 4; int isColor = true; bool useMask = false; int newMaskVal = 255; static void onMouse( int event, int x, int y, int, void* ) { if( event != CV_EVENT_LBUTTONDOWN ) return; Point seed = Point(x,y); int lo = ffillMode == 0 ? 0 : loDiff; int up = ffillMode == 0 ? 0 : upDiff; int flags = connectivity + (newMaskVal << 8) + (ffillMode == 1 ? CV_FLOODFILL_FIXED_RANGE : 0); int b = (unsigned)theRNG() & 255; int g = (unsigned)theRNG() & 255; int r = (unsigned)theRNG() & 255; Rect ccomp; Scalar newVal = isColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114); Mat dst = isColor ? image : gray; int area; if( useMask ) { threshold(mask, mask, 1, 128, CV_THRESH_BINARY); area = floodFill(dst, mask, seed, newVal, &ccomp, Scalar(lo, lo, lo), Scalar(up, up, up), flags); imshow( "mask", mask ); } else { area = floodFill(dst, seed, newVal, &ccomp, Scalar(lo, lo, lo), Scalar(up, up, up), flags); } imshow("image", dst); cout << area << " pixels were repainted\n"; } int main( ) { char* filename="0.png"; image0 = imread(filename, 1); if( image0.empty() ) { cout << "Image empty. Usage: ffilldemo <image_name>\n"; return 0; } help(); image0.copyTo(image); cvtColor(image0, gray, CV_BGR2GRAY); mask.create(image0.rows+2, image0.cols+2, CV_8UC1); namedWindow( "image", 0 ); createTrackbar( "lo_diff", "image", &loDiff, 255, 0 ); createTrackbar( "up_diff", "image", &upDiff, 255, 0 ); setMouseCallback( "image", onMouse, 0 ); for(;;) { imshow("image", isColor ? image : gray); int c = waitKey(0); if( (c & 255) == 27 ) { cout << "Exiting ...\n"; break; } switch( (char)c ) { case 'c': if( isColor ) { cout << "Grayscale mode is set\n"; cvtColor(image0, gray, CV_BGR2GRAY); mask = Scalar::all(0); isColor = false; } else { cout << "Color mode is set\n"; image0.copyTo(image); mask = Scalar::all(0); isColor = true; } break; case 'm': if( useMask ) { destroyWindow( "mask" ); useMask = false; } else { namedWindow( "mask", 0 ); mask = Scalar::all(0); imshow("mask", mask); useMask = true; } break; case 'r': cout << "Original image is restored\n"; image0.copyTo(image); cvtColor(image, gray, CV_BGR2GRAY); mask = Scalar::all(0); break; case 's': cout << "Simple floodfill mode is set\n"; ffillMode = 0; break; case 'f': cout << "Fixed Range floodfill mode is set\n"; ffillMode = 1; break; case 'g': cout << "Gradient (floating range) floodfill mode is set\n"; ffillMode = 2; break; case '4': cout << "4-connectivity mode is set\n"; connectivity = 4; break; case '8': cout << "8-connectivity mode is set\n"; connectivity = 8; break; } } return 0; }