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() );
我们也可以使用函数getStructuringElement配合这第三个参数的使用从而得到自定义的核。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。
其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:
而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() );
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);
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)
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