图像二值形态学——腐蚀和膨胀的C语言实现数学形态学是法国和德国科学家在研究岩石结构时建立的一门科学。形态学的用途主要是获取物体拓扑和结构信息,通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。在图像处理中的应用主要是:利用形态学的基本运算,对图像进行观察和处理,从而达到改善图像质量的目的;描述和定义图像的各种几何参数和特征,如面积、周长、连通度、颗粒度、骨架和方向性等。关于形态学的具体描述和数学形式化的定义可以从文章底部的参考资料中获得。最近的实验中需要对二值图像进行减噪处理,图像形态学中的腐蚀和膨胀能很好的解决此问题。如果在腐蚀和膨胀操作前,对灰度图像做一次滤波,减噪效果将更明显。腐蚀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。膨胀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。腐蚀的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点;膨胀的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的空洞。开运算是先腐蚀后膨胀的过程,可以消除图像上细小的噪声,并平滑物体边界。闭运算时先膨胀后腐蚀的过程,可以填充物体内细小的空洞,并平滑物体边界。以下是一段在OpenCV中实现的C语言程序,分别是图像腐蚀和膨胀函数,输入的参数依次为:当前二值图像数据指针、图像宽度、图像高度。通过这两个函数的组合使用(开闭运算),可以对图像进行有效减噪。一、图像腐蚀膨胀细化的基本原理1.图像细化的基本原理⑴图像形态学处理的概念数字图像处理中的形态学处理是指将数字形态学作为工具从图像中提取对于表达和描绘区域形状有用处的图像分量,比如边界、骨架以及凸壳,还包括用于预处理或后处理的形态学过滤、细化和修剪等。图像形态学处理中我们感兴趣的主要是二值图像。在二值图像中,所有黑色像素的集合是图像完整的形态学描述,二值图像的各个分量是Z2的元素。假定二值图像A和形态学处理的结构元素B是定义在笛卡儿网格上的集合,网格中值为1的点是集合的元素,当结构元素的原点移到点(x,y)时,记为Sxy,为简单起见,结构元素为3x3,且全都为1,在这种限制下,决定输出结果的是逻辑运算。⑵二值图像的逻辑运算逻辑运算尽管本质上很简单,但对于实现以形态学为基础额图像处理算法是一种有力的补充手段。在图像处理中用到的主要逻辑运算是:与、或和非(求补),它们可以互相组合形成其他逻辑运算。⑶膨胀和腐蚀膨胀和腐蚀这两种操作是形态学处理的基础,许多形态学算法都是以这两种运算为基础的。①膨胀是以得到B的相对与它自身原点的映像并且由z对映像进行移位为基础的。A被B膨胀是所有位移z的集合,这样,和A至少有一个元素是重叠的。我们可以把上式改写为:结构元素B可以看作一个卷积模板,区别在于膨胀是以集合运算为基础的,卷积是以算术运算为基础的,但两者的处理过程是相似的。⑴用结构元素B,扫描图像A的每一个像素⑵用结构元素与其覆盖的二值图像做“与”操作⑶如果都为0,结果图像的该像素为0。否则为1②腐蚀对Z中的集合A和B,B对A进行腐蚀的整个过程如下:⑴用结构元素B,扫描图像A的每一个像素⑵用结构元素与其覆盖的二值图像做“与”操作⑶如果都为1,结果图像的该像素为1。否则为0腐蚀处理的结果是使原来的二值图像减小一圈。⑷击中(匹配)或击不中变换假设集合A是由3个子集X,Y和Z组成的集合,击中(匹配)的目的是要在A中找到X的位置,我们设X被包围在一个小窗口W中,与W有关的X的局部背景定义为集合的差(W-X),则X在A内能得到精确拟合位置集合是由X对A的腐蚀后由(W-X)对A的补集Ac腐蚀的交集,这个交集就是我们要找的位置,我们用集合B来表示由X和X的背景构成的集合,我们可以令B=(B1,B2),这里B1=X,B2=(W-X),则在A中对B进行匹配可以表示为:A⊙B我们称为形态学上的击中或击不中变换。⑸开闭操作开操作是先腐蚀、后膨胀处理。闭操作是先膨胀、后腐蚀处理。(6)细化图像细化一般作为一种图像预处理技术出现,目的是提取源图像的骨架,即是将原图像中线条宽度大于1个像素的线条细化成只有一个像素宽,形成“骨架”,形成骨架后能比较容易的分析图像,如提取图像的特征。细化基本思想是“层层剥夺”,即从线条边缘开始一层一层向里剥夺,直到线条剩下一个像素的为止。图像细化大大地压缩了原始图像地数据量,并保持其形状的基本拓扑结构不变,从而为文字识别中的特征抽取等应用奠定了基础。细化算法应满足以下条件:①将条形区域变成一条薄线;②薄线应位与原条形区域的中心;③薄线应保持原图像的拓扑特性。细化分成串行细化和并行细化,串行细化即是一边检测满足细化条件的点,一边删除细化点;并行细化即是检测细化点的时候不进行点的删除只进行标记,而在检测完整幅图像后一次性去除要细化的点。常用的图像细化算法有hilditch算法,pavlidis算法和rosenfeld算法等。注:进行细化算法前要先对图像进行二值化,即图像中只包含“黑”和“白”两种颜色。具体详细的图像形态学资料参考:二、OpenCv形态学操作相关函数1、MorphologyEx高级形态学变换voidcvMorphologyEx(constCvArr*src,CvArr*dst,CvArr*temp,IplConvKernel*element,intoperation,intiterations=1);src输入图像.dst输出图像.temp临时图像,某些情况下需要element结构元素operation形态操作的类型:CV_MOP_OPEN-开运算CV_MOP_CLOSE-闭运算CV_MOP_GRADIENT-形态梯度CV_MOP_TOPHAT-顶帽CV_MOP_BLACKHAT-黑帽iterations膨胀和腐蚀次数.函数cvMorphologyEx在膨胀和腐蚀基本操作的基础上,完成一些高级的形态变换:开运算dst=open(src,element)=dilate(erode(src,element),element)闭运算dst=close(src,element)=erode(dilate(src,element),element)形态梯度dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)顶帽dst=tophat(src,element)=src-open(src,element)黑帽dst=blackhat(src,element)=close(src,element)-src临时图像temp在形态梯度以及对“顶帽”和“黑帽”操作时的in-place模式下需要。2、Dilate使用任意结构元素膨胀图像voidcvDilate(constCvArr*src,CvArr*dst,IplConvKernel*element=NULL,intiterations=1);src输入图像.dst输出图像.element用于膨胀的结构元素。若为NULL,则使用3×3长方形的结构元素iterations膨胀的次数函数cvDilate对输入图像使用指定的结构元进行膨胀,该结构决定每个具有最小值象素点的邻域形状:dst=dilate(src,element):dst(x,y)=max((x',y')inelement))src(x+x',y+y')函数支持(in-place)模式。膨胀可以重复进行(iterations)次.对彩色图像,每个彩色通道单独处理。3、Erode使用任意结构元素腐蚀图像voidcvErode(constCvArr*src,CvArr*dst,IplConvKernel*element=NULL,intiterations=1);src输入图像.dst输出图像.element用于腐蚀的结构元素。若为NULL,则使用3×3长方形的结构元素iterations腐蚀的次数函数cvErode对输入图像使用指定的结构元素进行腐蚀,该结构元素决定每个具有最小值象素点的邻域形状:dst=erode(src,element):dst(x,y)=min((x',y')inelement))src(x+x',y+y')函数可能是本地操作,不需另外开辟存储空间的意思。腐蚀可以重复进行(iterations)次.对彩色图像,每个彩色通道单独处理。注:CreateStructuringElementEx创建结构元素;ReleaseStructuringElement删除结构元素。三、OpenCv形态学实例代码:1、腐蚀、膨胀、开运算、闭运算内容参考:*******************************数学形态运算,最常见的基本运算有七种,分别为:腐蚀、膨胀、开运算、闭运算、击中、细化和粗化,它们是全部形态学的基础。********************************/#includecv.h#includehighgui.h#includestdlib.h#includestdio.hIplImage*src=0;IplImage*dst=0;IplConvKernel*element=0;//声明一个结构元素intelement_shape=CV_SHAPE_RECT;//长方形形状的元素intmax_iters=10;intopen_close_pos=0;interode_dilate_pos=0;voidOpenClose(intpos){intn=open_close_pos-max_iters;intan=n0?n:-n;element=cvCreateStructuringElementEx(an*2+1,an*2+1,an,an,element_shape,0);//创建结构元素if(n0){cvErode(src,dst,element,1);//腐蚀图像cvDilate(dst,dst,element,1);//膨胀图像}else{cvDilate(dst,dst,element,1);//膨胀图像cvErode(src,dst,element,1);//腐蚀图像}cvReleaseStructuringElement(&element);cvShowImage(Open/Close,dst);}voidErodeDilate(intpos){intn=erode_dilate_pos-max_iters;intan=n0?n:-n;element=cvCreateStructuringElementEx(an*2+1,an*2+1,an,an,element_shape,0);if(n0){cvErode(src,dst,element,1);}else{cvDilate(src,dst,element,1);}cvReleaseStructuringElement(&element);cvShowImage(Erode/Dilate,dst);}intmain(intargc,char**argv){char*filename=argc==2?argv[1]:(char*)lena.jpg;if((src=cvLoadImage(filename,1))==0)return-1;dst=cvCloneImage(src);cvNamedWindow(Open/Close,1);cvNamedWindow(Erode/Dilate,1);open_close_pos=ero