OpenCV与EmguCV中的漫水填充

漫水填充算法,是根据选定的种子点,用一种自定义的颜色填充种子点的联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果。

漫水填充经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析。

所谓漫水填充,简单来说,就是自动选中了和种子点相连的区域,接着将该区域替换成指定的颜色。

漫水填充也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或者只处理掩码指定的像素点。

在OpenCV中,漫水填充是填充算法中最通用的方法。且在OpenCV 2.X中,使用C++重写过的FloodFill函数有两个版本。一个不带掩膜mask的版本,和一个带mask的版本。这个掩膜mask,就是用于进一步控制哪些区域将被填充颜色(比如说当对同一图像进行多次填充时)。这两个版本的FloodFill,都必须在图像中选择一个种子点,然后把临近区域所有相似点填充上同样的颜色,不同的是,不一定将所有的邻近像素点都染上同一颜色,漫水填充操作的结果总是某个连续的区域。当邻近像素点位于给定的范围(从loDiff到upDiff)内或在原始seedPoint像素值范围内时,FloodFill函数就会为这个点涂上颜色。

在OpenCV中,漫水填充算法由floodFill函数实现,其作用是用我们指定的颜色从种子点开始填充一个连接域。连通性由像素值的接近程度来衡量。OpenCV2.X有两个C++重写版本的floodFill。

OpenCV中的函数原型如下:

int floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )
int floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )

两个版本相比,相差的只有第二个参数。

  • 第一个参数,InputOutputArray类型的image, 输入/输出1通道或3通道,8位或浮点图像,具体参数由之后的参数具体指明。
  • 第二个参数, InputOutputArray类型的mask,这是第二个版本的floodFill独享的参数,表示操作掩模,。它应该为单通道、8位、长和宽上都比输入图像 image 大两个像素点的图像。第二个版本的floodFill需要使用以及更新掩膜,所以这个mask参数我们一定要将其准备好并填在此处。漫水填充算法不会填充掩膜mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多次的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。另外需要注意的是,掩膜mask会比需填充的图像大2个像素,所以 mask 中与输入图像(x,y)像素点相对应的点的坐标为(x+1,y+1)。
  • 第三个参数,Point类型的seedPoint,漫水填充算法的起始点。
  • 第四个参数,Scalar类型的newVal,像素点被染色的值,即在重绘区域像素的新值。
  • 第五个参数,Rect*类型的rect,有默认值0,一个可选的参数,用于设置floodFill函数将要重绘区域的最小边界矩形区域。
  • 第六个参数,Scalar类型的loDiff,有默认值Scalar( ),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之负差(lower brightness/color difference)的最大值。
  • 第七个参数,Scalar类型的upDiff,有默认值Scalar( ),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之正差(lower brightness/color difference)的最大值。
  • 第八个参数,int类型的flags,操作标志符,此参数包含三个部分,比较复杂,我们一起详细看看。

a。低八位(第0~7位)用于控制算法的连通性,可取4 (4为缺省值) 或者 8。如果设为4,表示填充算法只考虑当前像素水平方向和垂直方向的相邻点;如果设为 8,除上述相邻点外,还会包含对角线方向的相邻点。

b。中间八位部分,上面关于高八位FLOODFILL_MASK_ONLY标识符中已经说的很明显,需要输入符合要求的掩码。Floodfill的flags参数的中间八位的值就是用于指定填充掩码图像的值的。但如果flags中间八位的值为0,则掩码会用1来填充。

c。高八位部分(16~23位)可以为0 或者如下两种选项标识符的组合:

FLOODFILL_FIXED_RANGE - 如果设置为这个标识符的话,就会考虑当前像素与种子像素之间的差,否则就考虑当前像素与其相邻像素的差。也就是说,这个范围是浮动的。

FLOODFILL_MASK_ONLY - 如果设置为这个标识符的话,函数不会去填充改变原始图像 (也就是忽略第三个参数newVal), 而是去填充掩模图像(mask)。这个标识符只对第二个版本的floodFill有用,因第一个版本里面压根就没有mask参数。

而所有flags可以用or操作符连接起来,即“|”。例如,如果想用8邻域填充,并填充固定像素值范围,填充掩码而不是填充源图像,以及设填充值为47,那么输入的参数是这样:

flags=8 | FLOODFILL_MASK_ONLY | FLOODFILL_FIXED_RANGE | (47<<8)

eg。

Mat srcImage=imread("M:/图像处理实验/floodFill/test_.bmp");
Rect ccomp;
floodFill(srcImage,  Point(1, 1), CV_RGB(205, 205, 205), &ccomp, Scalar(15, 15, 15), Scalar(15, 15, 15), 8 | FLOODFILL_FIXED_RANGE );
imwrite("M:/图像处理实验/floodFill/test_dst.bmp", srcImage);

种子点为(1,1)。下面为原图与漫水填充后的结果对比:

  

eg。

Mat srcImage=imread("M:/图像处理实验/floodFill/云.bmp");
Mat mask;
mask.create(((srcImage).rows + 2), ((srcImage).cols + 2), CV_8UC1);
mask = Scalar::all(0);
Mat ImageROI;
ImageROI = mask(Rect(1, 1, (srcImage).cols, (srcImage).rows));
Mat dstImage;
Mat dstImage_canny;
srcImage.copyTo(dstImage_canny);
cvtColor(dstImage_canny, dstImage_canny, CV_RGB2GRAY);
medianBlur(dstImage_canny, dstImage_canny, 7);
Canny(dstImage_canny, dstImage, 3, 3 * 3, 3);
dstImage.copyTo(ImageROI);
Rect ccomp;
//选择了三个种子点,分别赋予了三种填充颜色。
//第一次调用floodFill时,未添加canny边缘检测后的掩模,所以云的边缘被腐蚀掉了一部分。结果就是部分云消失了。
//后两次调用floodFill时,添加了canny边缘检测后的掩模,云的边缘得到了很好的保留,但是部分颜色变化较大的区域,canny后,检验出了边缘,边缘的原来颜色得到了保留
floodFill(srcImage, Point(223, 184), CV_RGB(88,123,165), &ccomp, Scalar(35, 35, 35), Scalar(30, 30, 30), 8 | FLOODFILL_FIXED_RANGE );
floodFill(srcImage, mask,  Point(48, 507), CV_RGB(108,148,184), &ccomp, Scalar(25, 25, 25), Scalar(15, 15, 15), 8 | FLOODFILL_FIXED_RANGE );
floodFill(srcImage, mask,  Point(609, 582), CV_RGB(137,173,197), &ccomp, Scalar(25, 25, 25), Scalar(15, 15, 15), 8 | FLOODFILL_FIXED_RANGE );
imwrite("M:/图像处理实验/floodFill/云_dst.bmp", srcImage);

下面为原图与漫水填充后的输出结果:

 
canny边缘检测后的输出,也是floodFill函数中的掩模。黑色区域可以被填充,白色部分保留原来的颜色。

EmguCV中的函数原型如下:

Public Shared Function FloodFill(src As Emgu.CV.IInputOutputArray, mask As Emgu.CV.IInputOutputArray, seedPoint As System.Drawing.Point, newVal As Emgu.CV.Structure.MCvScalar, ByRef rect As System.Drawing.Rectangle, loDiff As Emgu.CV.Structure.MCvScalar, upDiff As Emgu.CV.Structure.MCvScalar, Optional connectivity As Emgu.CV.CvEnum.Connectivity = FourConnected, Optional flags As Emgu.CV.CvEnum.FloodFillType = Default) As Integer
  • 第一个参数,Emgu.CV.IInputOutputArray类型的image。
  • 第二个参数, Emgu.CV.IInputOutputArray类型的mask,表示操作掩模,。它应该为单通道、8位、长和宽上都比输入图像 image 大两个像素点的图像。与OpenCV不同,emguCV貌似没有第二个版本的FloodFill函数,emgu提供的FloodFill与OpenCV的第二个函数作用相似。漫水填充算法不会填充掩膜mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多次的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。另外需要注意的是,掩膜mask会比需填充的图像大2个像素,所以 mask 中与输入图像(x,y)像素点相对应的点的坐标为(x+1,y+1)。
  • 第三个参数,Point类型的seedPoint,漫水填充算法的起始点。
  • 第四个参数,Emgu.CV.Structure.MCvScalar类型的newVal,像素点被染色的值,即在重绘区域像素的新值。
  • 第五个参数,Rect*类型的rect,用于设置floodFill函数将要重绘区域的最小边界矩形区域。与OpenCV不同,没有默认值。
  • 第六个参数,Emgu.CV.Structure.MCvScalar类型的loDiff,表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之负差(lower brightness/color difference)的最大值。
  • 第七个参数,Emgu.CV.Structure.MCvScalar类型的upDiff,表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之正差(lower brightness/color difference)的最大值。
  • 第八个参数,Emgu.CV.CvEnum.Connectivity类型的connectivity。控制算法的连通性,可取4 (4为缺省值) 或者 8。如果设为4,表示填充算法只考虑当前像素水平方向和垂直方向的相邻点;如果设为 8,除上述相邻点外,还会包含对角线方向的相邻点。
  • 第九个参数,Emgu.CV.CvEnum.FloodFillType类型的flags。可以为0(0为缺省值) 或者以下两种选项标识符的组合:

                        FLOODFILL_FIXED_RANGE - 如果设置为这个标识符的话,就会考虑当前像素与种子像素之间的差,否则就考虑当前像素与其相邻像素的差。也就是说,这个范围是浮动的。

    FLOODFILL_MASK_ONLY - 如果设置为这个标识符的话,函数不会去填充改变原始图像 (也就是忽略第三个参数newVal), 而是去填充掩模图像(mask)。

eg。

Dim bkGrayWhite As New Gray(255)
Dim bkGrayBlack As New Gray(0)
Dim img As Image(Of Bgr, Byte) = New Image(Of Bgr, Byte)("M:\图像处理实验\FloodFill\云1.bmp")
Dim img_MedianBlur As Image(Of Bgr, Byte) = New Image(Of Bgr, Byte)(img.Width, img.Height)
img.CopyTo(img_MedianBlur)
CvInvoke.MedianBlur(img, img_MedianBlur, 7)
Dim mask As Image(Of Gray, Byte) = New Image(Of Gray, Byte)(img.Width + 2, img.Height + 2, bkGrayBlack)
‘BGR
CvInvoke.FloodFill(img,
                   mask,
                   New System.Drawing.Point(2, 2),
                   New MCvScalar(165, 123, 88),
                   New System.Drawing.Rectangle(0, 0, 0, 0),
                   New MCvScalar(5, 5, 5),
                   New MCvScalar(5, 5, 5),
                   Emgu.CV.CvEnum.Connectivity.EightConnected,
                   Emgu.CV.CvEnum.FloodFillType.FixedRange
                   )
CvInvoke.cvSetImageROI(mask, New System.Drawing.Rectangle(1, 1, img.Width, img.Height))
Dim img_canny As Image(Of Gray, Byte) = New Image(Of Gray, Byte)(img.Width, img.Height, bkGrayBlack)
CvInvoke.Canny(img_MedianBlur, img_canny, 5, 5 * 3)
img_canny.CopyTo(mask)
CvInvoke.cvResetImageROI(mask)
CvInvoke.FloodFill(img,
                   mask,
                   New System.Drawing.Point(668, 570),
                   New MCvScalar(197, 173, 137),
                   New System.Drawing.Rectangle(0, 0, 0, 0),
                   New MCvScalar(25, 25, 25),
                   New MCvScalar(5, 5, 5),
                   Emgu.CV.CvEnum.Connectivity.EightConnected,
                   Emgu.CV.CvEnum.FloodFillType.FixedRange
                   )
img.Save("M:\图像处理实验\FloodFill\云1_result.bmp")

参考文献:

Bradski & Kaebler ·《学习OpenCV(中文版)》· 清华大学出版社 · 2009

http://www.emgu.com/wiki/files/3.0.0-alpha/document/html/1ebdfe41-1e71-9440-a71b-719b64cc39df.htm

http://blog.csdn.net/poem_qianmo/article/details/28261997

时间: 2024-11-20 06:53:43

OpenCV与EmguCV中的漫水填充的相关文章

OpenCV与EmguCV中的空间滤波

图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接响到后续图像处理和分析的有效性和可靠性.(滤波就是要去除没用的信息,保留有用的信息,可能是低频,也可能是高频) 滤波一词借用于频域处理.本意是指信号有各种频率的成分,滤掉不想要的成分,即为滤掉常说的噪声,留下想要的成分,这既是滤波的过程,也是滤波的目的. 滤波分为两种: 空间滤波与频域滤波. 空间滤波是将输入图像与滤波器模板相卷积,将最终计算结果之和作为输出的像素值. 频率域滤

OpenCV与EmguCV中的图像轮廓提取

轮廓是图像中表示边界的一系列点的集合. 虽然边缘检测算法可以根据像素间的差异检查出轮廓边界的像素,但是它并没有把轮廓做为一个整体表示出来.所以下一步工作是把这些边缘检测出来的像素组装成轮廓. openCV中可以用findContours()函数来从二值图像中提取轮廓. openCV中一般用序列来存储轮廓信息.序列中的每一个元素是曲线中一个点的位置. 函数findContours()从二值图像中寻找轮廓.findContours()处理的图像可以是Canny()后得到的有边缘像素的的图像,也可以是

Opencv图像识别从零到精通(24)------漫水填充,种子填充,区域生长、孔洞填充

可以说从这篇文章开始,就结束了图像识别的入门基础,来到了第二阶段的学习.在平时处理二值图像的时候,除了要进行形态学的一些操作,还有有上一节讲到的轮廓连通区域的面积周长标记等,还有一个最常见的就是孔洞的填充,opencv这里成为漫水填充,其实也可以叫种子填充,或者区域生长,基本的原理是一样的,但是应用的时候需要注意一下,种子填充用递归的办法,回溯算法,漫水填充使用堆栈,提高效率,同时还提供了一种方式是扫描行.经常用来填充孔洞,现在来具体看看. 漫水填充:也就是用一定颜色填充联通区域,通过设置可连通

opencv FloodFill(漫水填充)和物体选取

简介 本篇主要是介绍opencv的FloodFill(漫水填充)和基于它实现的物体选取. FloodFill使用 FloodFill函数 C++: int floodFill(InputOutputArray image, InputOutputArray mask, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 ); InputO

opencv —— floodFill 漫水填充,证件照换背景

漫水填充:floodFill 函数 简单来说,漫水填充就是自动选中与种子像素相连的区域,利用指定颜色进行区域颜色填充.Windows 画图工具中的油漆桶功能和 Photoshop 的魔法棒选择工具,都是漫水填充的改进和延伸. //第一个版本 int floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect = 0, Scalar loDiff = Scalar(), Scalar upDiff = S

Opencv3编程入门笔记(4)腐蚀、膨胀、开闭运算、漫水填充、金字塔、阈值化、霍夫变换

19      腐蚀erode.膨胀dilate 腐蚀和膨胀是针对图像中的白色部分(高亮部分)而言的,不是黑色的.除了输入输出图像外,还需传入模板算子element,opencv中有三种可以选择:矩形MORPH_RECT,交叉形MORPH_CROSS,椭圆形MORPH_ELLIPSE.Matlab中会有更多一点的模板. 例如: Mat element = getStructuringElement(MORPH_RECT,Size(15,15)); erode(srcImage,dstImage,

【练习5.6】漫水填充法、阈值化、cvSaveImage保存格式

提纲 题目要求 程序代码 结果图片 题目要求: 从噪声图像中创建一个清晰的掩码.完成练习5后,保留图形中最大的图形区域.在图像的左上角设置一个指针,然后让他遍历图像.当你发现像素值为255的时候,存储其位置,然后对其漫水填充,新颜色值为100,.读出漫水填充法返回的连续区域,记录下其面积.如果图像中有另一个较大的区域,那么用0值对这个相对较小的区域进行颜色填充,然后删除已记录的面积.如果新的区域大于之前的区域,那么以0值填充之前的区域并删除他的位置.最后以颜色值255填充剩余的最大区域,显示结果

浅入浅出EmguCv(一)OpenCv与EmguCv

最近接触计算机视觉方面的东西,于是准备下手学习opencv,从官网下载windows的安装版,配置环境,一系列步骤走完后,准备按照惯例弄个HelloWord.也就是按照网上的教程,打开了那个图像处理领域非常有名的lena图片(据说是个裸女\(^o^)/~). 正当我摩拳擦掌准备开始opencv学习之旅的时候,习惯了GUI的我突然觉得用C++做开发弄界面很麻烦,不如用C#来的方便,于是又发现了一个封装了opencv的.net库,可以被VC++,VC#,VB.net调用,即EmguCV.网上对于Em

利用Opencv在PictureControl中显示照片

利用Opencv在PictureControl中显示IplImage格式的照片. bool MyDlg::IfExistFile(CString strFilePath) { CFile file; if (file.Open(strFilePath,CFile::modeRead)) { file.Close(); return true; } return false; } bool MyDlg::FillBlankToPicCtrl(const int& nID) { CDC *pDC =