OpenCV与EmguCV中的形态学滤波

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

形态学(morphology)一词通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。而我们图像处理中指的形态学,往往表示的是数学形态学。下面一起来了解数学形态学的概念。

数学形态学是由一组形态学的代数运算子组成的,它的基本运算有4个: 膨胀、腐蚀、开启和闭合, 它们在二值图像灰度图像中各有特点。

简单来讲,形态学操作就是基于形状的一系列图像处理操作。

OpenCV为进行图像的形态学变换提供了快捷、方便的函数。基本的形态学操作有二种,他们是:膨胀与腐蚀(Dilation与Erosion)。

膨胀与腐蚀能实现多种多样的功能:消除噪声、分割(isolate)出独立的图像元素以及在图像中连接(join)相邻的元素。形态学也常被用于寻找图像中的明显的极大值区域或极小值区域以及求出图像的梯度。


①膨胀 dilate

OpenCV中的函数原型如下:

void dilate(  InputArray src,  OutputArray dst,  InputArray kernel,  Point anchor=Point(-1,-1),  int iterations=1,  int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() );  
  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
  • 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的kernel,膨胀操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核。
  • 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于中心。
  • 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1。
  • 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
  • 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。

扫描二维码关注公众号,回复: 131704 查看本文章

我们也可以使用函数getStructuringElement配合这第三个参数的使用从而得到自定义的核。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。

其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:

  • 矩形: MORPH_RECT
  • 交叉形: MORPH_CROSS
  • 椭圆形: MORPH_ELLIPSE

而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。

我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。

eg。

Mat srcImage=imread("M:/图像处理实验/dilate/src.bmp");  
Mat dstImage;  
//自定义核
Mat structuringE = getStructuringElement(MORPH_RECT,Size(5,5),Point(2,2));
dilate( srcImage, dstImage, structuringE, Point(2,2), 1, BORDER_DEFAULT); 
imwrite("M:/图像处理实验/dilate/dst.bmp", dstImage);
EmguCV中的函数原型:
Public Shared Sub Dilate(src As Emgu.CV.IInputArray, dst As Emgu.CV.IOutputArray, element As Emgu.CV.IInputArray, anchor As System.Drawing.Point, iterations As Integer, borderType As Emgu.CV.CvEnum.BorderType, borderValue As Emgu.CV.Structure.MCvScalar)

参数含义与OpenCV中相同

第三个参数可使用如下函数来获取自定义核:

Public Shared Function GetStructuringElement(shape As Emgu.CV.CvEnum.ElementShape, ksize As System.Drawing.Size, anchor As System.Drawing.Point) As Emgu.CV.Mat
eg。

Dim img As Image(Of Gray, Byte) = New Image(Of Gray, Byte)("M:\图像处理实验\dilate\src.bmp")
Dim StructingElement As Emgu.CV.Mat = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, New Size(5, 5), New Point(2, 2))
CvInvoke.Dilate(img, img, StructingElement, New Point(2, 2), 1, Emgu.CV.CvEnum.BorderType.Default, New Emgu.CV.Structure.MCvScalar(0))
img.Save("M:\图像处理实验\dilate\src-result.bmp")
此函数的参数没有默认值,使用起来比较繁琐。也可以如下调用。
Emgu.CV.Image(Of TColor, TDepth).Dilate(iterations As Integer) As Emgu.CV.Image(Of TColor, TDepth)

膨胀是指将图像(或图像中的一部分区域,A)与核B进行卷积。

核可以是任何的形状或大小,它拥有一个单独定义出来的参考点。多数情况下,核是一个小的中间带有参考点的实心正方形或圆盘。核可以视为模板或掩码。

膨胀是求局部最大值的操作。

核B与图像卷积,即计算核B覆盖的区域的像素点最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐增长。这样的增长就是膨胀操作的初衷。

由此可见,膨胀和腐蚀操作是对图像中的高亮区域进行的,也就是图像的白色区域。

腐蚀 erode
OpenCV中的函数原型如下:

void erode( InputArray src,  OutputArray dst,  InputArray kernel,  Point anchor=Point(-1,-1),  int iterations=1,  int borderType=BORDER_CONSTANT,  const Scalar& borderValue=morphologyDefaultBorderValue() );
  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
  • 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的kernel,腐蚀操作的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。详细信息可见上文。
  • 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于单位(element)的中心,我们一般不用管它。
  • 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1。
  • 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
  • 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
eg。
Mat srcImage=imread("M:/图像处理实验/erode/src.bmp");  
Mat dstImage;  
Mat structuringE = getStructuringElement(MORPH_RECT,Size(5,5),Point(2,2));
erode( srcImage, dstImage, structuringE, Point(2,2), 1, BORDER_DEFAULT); 
imwrite("M:/图像处理实验/erode/dst.bmp", dstImage);


EmguCV中的函数原型如下:
Public Shared Sub Erode(src As Emgu.CV.IInputArray, dst As Emgu.CV.IOutputArray, element As Emgu.CV.IInputArray, anchor As System.Drawing.Point, iterations As Integer, borderType As Emgu.CV.CvEnum.BorderType, borderValue As Emgu.CV.Structure.MCvScalar)
函数参数含义与OpenCV相同
eg。
Dim img As Image(Of Gray, Byte) = New Image(Of Gray, Byte)("M:\图像处理实验\erode\src.bmp")        
Dim StructingElement As Emgu.CV.Mat = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, New Size(5, 5), New Point(2, 2))
CvInvoke.Erode(img, img, StructingElement, New Point(2, 2), 1, Emgu.CV.CvEnum.BorderType.Default, New Emgu.CV.Structure.MCvScalar(0))
img.Save("M:\图像处理实验\erode\src-result.bmp")


腐蚀和膨胀是一对相反的操作,所以腐蚀就是求局部最小值的操作。

我们一般都会把腐蚀和膨胀对应起来学习理解。



③ 开运算

开运算,其实就是先腐蚀后膨胀的过程。

开运算可以用来消除小物体,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积。



④闭运算

闭运算,就是先膨胀后腐蚀的过程。

闭运算可以用来排除小型黑洞。

eg。(VB.NET、EmguCV)

Dim img As Image(Of Gray, Byte) = New Image(Of Gray, Byte)("M:\图像处理实验\二维码\二维码.bmp")
Dim StructingElement As Emgu.CV.Mat = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, New Size(5, 5), New Point(2, 2))
'先膨胀        
CvInvoke.Dilate(img, img, StructingElement, New Point(2, 2), 1, Emgu.CV.CvEnum.BorderType.Default, New Emgu.CV.Structure.MCvScalar(0))
'再腐蚀
CvInvoke.Erode(img, img, StructingElement, New Point(2, 2), 1, Emgu.CV.CvEnum.BorderType.Default, New Emgu.CV.Structure.MCvScalar(0))
img.Save("M:\图像处理实验\result\result.bmp")
原图像与进行了闭运算后的输出结果比较:

本文中的OpenCv与EmguCV均用的是3.0以上的版本。

参考文献:

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

冈萨雷斯 · 《数字图像处理》 · 电子工业出版社 · 2011

猜你喜欢

转载自blog.csdn.net/u013162930/article/details/51775789