OpenCV与EmguCV中的漫水填充

2024-08-30 14:18
文章标签 opencv 填充 emgucv 漫水

本文主要是介绍OpenCV与EmguCV中的漫水填充,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/u013162930/article/details/51792750

漫水填充算法,是根据选定的种子点,用一种自定义的颜色填充种子点的联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果。
漫水填充经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析。
所谓漫水填充,简单来说,就是自动选中了和种子点相连的区域,接着将该区域替换成指定的颜色。
漫水填充也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或者只处理掩码指定的像素点。
在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")


本文中的OpenCv与EmguCV均用的是3.0以上的版本。
参考文献:
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

这篇关于OpenCV与EmguCV中的漫水填充的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121054

相关文章

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

opencv 滚动条

参数介绍:createTrackbar( trackbarname , "hello" , &alpha_slider ,alpha_max ,  on_trackbar )  ;在标签中显示的文字(提示滑动条的用途) TrackbarName创建的滑动条要放置窗体的名字 “hello”滑动条的取值范围从 0 到 alpha_max (最小值只能为 zero).滑动后的值存放在

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

树莓派5_opencv笔记27:Opencv录制视频(无声音)

今日继续学习树莓派5 8G:(Raspberry Pi,简称RPi或RasPi)  本人所用树莓派5 装载的系统与版本如下:  版本可用命令 (lsb_release -a) 查询: Opencv 与 python 版本如下: 今天就水一篇文章,用树莓派摄像头,Opencv录制一段视频保存在指定目录... 文章提供测试代码讲解,整体代码贴出、测试效果图 目录 阶段一:录制一段

Verybot之OpenCV应用三:色标跟踪

下面的这个应用主要完成的是Verybot跟踪色标的功能,识别部分还是居于OpenCV编写,色标跟踪一般需要将图像的颜色模式进行转换,将RGB转换为HSV,因为对HSV格式下的图像进行识别时受光线的影响比较小,但是也有采用RGB模式来进行识别的情况,这种情况一般光线条件比较固定,背景跟识别物在颜色上很容易区分出来。         下面这个程序的流程大致是这样的:

Verybot之OpenCV应用二:霍夫变换查找圆

其实我是想通过这个程序来测试一下,OpenCV在Verybot上跑得怎么样,霍夫变换的原理就不多说了,下面是程序: #include "cv.h"#include "highgui.h"#include "stdio.h"int main(int argc, char** argv){cvNamedWindow("vedio",0);CvCapture* capture;i

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

虚拟机ubuntu配置opencv和opencv_contrib

前期准备  1.下载opencv和opencv_contrib源码 opencv-4.6.0:https://opencv.org/releases/ opencv_contrib-4.6.0:https://github.com/opencv/opencv_contrib 在ubuntu直接下载或者在window上下好传到虚拟机里都可以 自己找个地方把他们解压,个人习惯在home下新建一

渐变颜色填充

GradientFill函数可以对特定的矩形区域或者三角形区域进行渐变颜色的填充。我们先来看看GradientFill函数到底长得什么样子,帅不帅。 [cpp]  view plain copy print ? BOOL GradientFill(     _In_  HDC hdc,     _In_  PTRIVERTEX pVertex,     _In_  ULONG