3d空洞填充 图像处理_python 图像空洞填充 - CSDN
  • 深度图是一种由灰度值介于0到255的像素所构成的...因为深度图可以一个像素对应一个像素(Pixel-by-Pixel)方式被它的原始2D影像参考来制作栩栩如生的3D立体影像,所以目前它已非常普遍地被使用在制作裸眼3D显示器(或裸

    深度图是一种由灰度值介于0到255的像素所构成的影像。 灰度值为0的像素代表这个3D像素是位于最远的地方;而灰阶值为255的像素代表这个3D像素是位于最近的地方。在深度图里,每一个像素将定义其所对应的2D像素在Z-轴的位置。因为深度图可以一个像素对应一个像素(Pixel-by-Pixel)方式被它的原始2D影像参考来制作栩栩如生的3D立体影像,所以目前它已非常普遍地被使用在制作裸眼3D显示器(或裸眼3D广告机)所需要的多视角3D内容;也是制作多视角3D内容的主流技术。

    有了深度图,就相当于2D图像有了第三维的信息描述(深度信息),我们便可以利用算法来对2D图像虚拟出多个不同视角来。简单理解,一张平面图我们远看会变小,走近了看又会变大。人向左边移动,图像在我们视野中的位置又会相对右移。因此,对于不同的视角来说,目标图像只是相当于进行了平移及一系列简单的变换。然而,目标场景并不仅仅处在同一深度,反应在深度图中就是深度图中各个像素对应的值并不完全不同,因此,在视角前后左右变换时,不同深度的图像平移变换的量是不同的,离视角越近的场景变换越小。这样一来,当我们视角变化时,远处的物体难免会被较近处的物体所遮挡。虚拟视角的时候,这些像素点的信息就丢失了(从2D图上我们并不知道被遮挡的后边到底是什么),因此,需要我们对这些被遮挡的空洞进行填充。这里,使用了两种填充算法作为比较:镜面反射与梯度方向填充:


    使用算法通过一个视角产生的另一个虚拟视角后存在空洞:



    一、镜面反射

    对每行像素进行单独处理,如果存在需要填补遮挡像素,则以连续空洞的最右侧 x 值为对称轴,将右侧信息镜像填充空洞。OpenCV代码如下:

    //镜面反射填充空洞
    int mirrorFill(char* imagePath)
    {
    	IplImage* pImg;
    
    	int i,j,k;  //循环变量  遍历图像的高、宽、通道
    	int flag=0;  //连续黑点数
    	int m,n; //临时变量
    
    	pImg=cvLoadImage(imagePath);
    
    	uchar* data=(uchar*)pImg->imageData;  //获取图像数据
    
    	cvNamedWindow("Image1",CV_WINDOW_AUTOSIZE);
    	cvShowImage("Image1",pImg);
    	cvWaitKey(0);
    
    	for (i=0;i<pImg->height;i++)
    		for (j=0;j<pImg->width;j++)
    		{
    			flag=1;
    			for (k=0;k<pImg->nChannels;k++)
    				if (data[i*pImg->widthStep+j*pImg->nChannels+k]!=0) 
    				{ 
    					flag=0;
    					break;
    				}
    				if (flag>0) 
    				{
    					for (m=j+1; m<=pImg->width; m++)
    						if ((data[i*pImg->widthStep+m*pImg->nChannels+0]!=0)||
    							(data[i*pImg->widthStep+m*pImg->nChannels+1]!=0)||
    							(data[i*pImg->widthStep+m*pImg->nChannels+2]!=0))
    							break;
    						else flag++;
    						for (m=0;m<flag;m++)
    							for (k=0;k<pImg->nChannels;k++)
    								data[i*pImg->widthStep+(j+m)*pImg->nChannels+k]=
    								data[i*pImg->widthStep+(j-m+flag*2-1)*pImg->nChannels+k];
    				}
    		}
    
    		cvNamedWindow("Image2",CV_WINDOW_AUTOSIZE);
    		cvShowImage("Image2",pImg);
    		cvSaveImage("copy5.bmp",pImg);
    
    		printf("%d  %d  %d\n",pImg->width,pImg->height,pImg->nChannels);
    		cvWaitKey(0);
    
    		cvDestroyWindow("Image");
    		cvReleaseImage(&pImg);
    
    		return 0;
    }
    


    效果图:



    存在问题:镜像填充方法只能对简单的空洞进行填补,对于一些较复杂的则无法较好恢复。并且,如果对于一行像素连续的N个空洞信息如果右侧相邻的非空洞像素个数小于N,则无法完全填充空洞处。

    二、梯度方向填充:

    考虑到图像本身的梯度信息,按照不同的梯度方向来选取不同的像素点进行填充能使得空洞处所填充的像素与图像本身在纹理方面表现出更高的一致性,从而填补后更平滑,更符合场景本身的特征。填充方法简述如下:

    先将RGB图像转换为灰度图,然后计算出灰度图中每个像素点的 x 方向与 y 方向的梯度(一阶导)。然后对图像从左上向右下进行填充,对于待填充的空洞点用梯度较大的方向进行填充(x 或 y)。比如,一个像素点的 x 梯度大于 y 方向的梯度,则用该点 x 方向(左边)的点进行填充,否则用 y 方向的点进行填充。 参考代码如下:

    //对图像进行空洞填充(n次迭代扫描)
    void Darkness_Filling(IplImage* src,IplImage* src_gray,IplImage* dst)
    {
    	int i,j,count=0;
    	char* ptr1;
    	char* ptr2;
    	char* ptr3;
    	char* ptr_gray;
    
    
    	//x和y方向的梯度
    	IplImage* gradient_x = cvCreateImage(cvSize(src_gray->width,src_gray->height),IPL_DEPTH_16S,1);
    	IplImage* gradient_y = cvCreateImage(cvSize(src_gray->width,src_gray->height),IPL_DEPTH_16S,1);
    
    	char* gradientx;
    	char* gradienty;
    	char* tempx;
    	char* tempy;
    
    
    	//计算x和y方向的梯度图
    	cvSobel(src_gray,gradient_x,1,0,3);
    	cvSobel(src_gray,gradient_y,0,1,3);
    
    
    	for(i = 0;i < src_gray->height;i++)
    	{
    		//指向源图像src数据的指针
    		ptr1 = src->imageData + i * src->widthStep;
    		ptr2 = src->imageData + i * src->widthStep;
    		ptr3 = src_gray->imageData + i * src_gray->widthStep;
    		ptr_gray=src_gray->imageData + i * src_gray->widthStep;
    
    		//计算x和y方向上的对应点的梯度
    		gradientx = gradient_x->imageData + i * gradient_x->widthStep;
    		gradienty = gradient_y->imageData + i * gradient_y->widthStep;
    		tempx = gradient_x->imageData + i * gradient_x->widthStep;
    		tempy = gradient_y->imageData + i * gradient_y->widthStep;
    
    		//在灰度图像上寻找空洞点
    		for(j = 0;j < src_gray->width;j++)
    		{
    			if(ptr3[j]!=0)
    				continue;
    			//若纹理在y方向
    			if(gradientx[j]>gradienty[j])
    			{
    				//该点值判定为上方一点的值
    				ptr1 = src->imageData + (i-1) * src->widthStep;//得到原图上方像素指针
    				ptr_gray=src_gray->imageData + (i-1) * src_gray->widthStep;//得到灰度图上方像素指针
    				//填灰度图,为下次判断进行填充
    				ptr3[j]=ptr_gray[j];
    				//填RGB图
    				ptr2[3*j]=ptr1[3*j];
    				ptr2[3*j+1]=ptr1[3*j+1];
    				ptr2[3*j+2]=ptr1[3*j+2];
    
    				if(gradientx[j+1]==gradienty[j+1])
    				{
    					tempx = gradient_x->imageData + (i-1) * gradient_x->widthStep;
    					tempy = gradient_y->imageData + i * gradient_y->widthStep;
    					gradientx[j+1] = (gradientx[j] + tempx[j])/2;
    					gradienty[j+1] = (gradienty[j] + tempy[j])/2;
    				}
    			}
    			//若纹理在x方向
    			else 
    			{
    				//该点值判定为左方一点的值
    				ptr1 = src->imageData + i * src->widthStep;//得到原图左方像素指针
    				ptr_gray=src_gray->imageData + i * src_gray->widthStep;//得到灰度图左方像素指针
    				//填灰度图,为下次判断进行填充
    				ptr3[j]=ptr_gray[j-1];
    				//填RGB图
    				ptr2[3*j] = ptr1[3*(j-1)];
    				ptr2[3*j+1] = ptr1[3*(j-1)+1];
    				ptr2[3*j+2] = ptr1[3*(j-1)+2];
    
    				if(gradientx[j+1]==gradienty[j+1])
    				{
    					tempx = gradient_x->imageData + (i-1) * gradient_x->widthStep;
    					tempy = gradient_y->imageData + i * gradient_y->widthStep;
    					gradientx[j+1] = (gradientx[j] + tempx[j])/2;
    					gradienty[j+1] = (gradienty[j] + tempy[j])/2;
    				}
    
    			}
    		}
    
    	}
    	//复制图像
    	cvCopy(src,dst);
    }


    效果图:




    展开全文
  • DIBR中对于模糊图像的基于分割的空洞填充算法,魏百平,桑新柱,2D视频到3D视频的转换过程会用到基于深度图像的绘制技术,其中有一个关键步骤,即warp处理。warp处理过程就是生成视差图的过程,必定
  • 三维卷积&空洞卷积

    2020-07-21 12:09:22
    三维卷积 1. 大致的结构 下面就是 3D 卷积,其过滤器...2D常用于计算机视觉、图像处理领域: 2D 卷积2D卷积操作如图1所示,为了解释的更清楚,分别展示了单通道和多通道的操作。且为了画图方便,假定只有1个filter,

    三维卷积

    1. 大致的结构

    下面就是 3D 卷积,其过滤器深度小于输入层深度(核大小<通道大小)。因此,3D 过滤器可以在所有三个方向(图像的高度、宽度、通道)上移动。在每个位置,逐元素的乘法和加法都会提供一个数值。因为过滤器是滑过一个 3D 空间,所以输出数值也按 3D 空间排布。也就是说输出是一个 3D 数据。
    在这里插入图片描述

    2. 2D与3D对比

    2D常用于计算机视觉、图像处理领域:
    2D 卷积2D卷积操作如图1所示,为了解释的更清楚,分别展示了单通道和多通道的操作。且为了画图方便,假定只有1个filter,即输出图像只有一个chanel。

    其中,针对单通道,输入图像的channel为1,即输入大小为(1, height, weight),卷积核尺寸为 (1, k_h, k_w),卷积核在输入图像上的的空间维度(即(height, width)两维)上进行进行滑窗操作,每次滑窗和 (k_h, k_w) 窗口内的values进行卷积操作(现在都用相关操作取代),得到输出图像中的一个value。

    针对多通道,假定输入图像的channel为3,即输入大小为(3, height, weight),卷积核尺寸为 (3, k_h, k_w), 卷积核在输入图像上的的空间维度(即(height, width)两维)上进行进行滑窗操作,每次滑窗与3个channels上的 (k_h, k_w) 窗口内的所有的values进行相关操作,得到输出图像中的一个value。

    在这里插入图片描述
    3D:三维卷积常用视频处理领域(检测动作及人物行为)。

    3D 卷积3D卷积操作如图2所示,同样分为单通道和多通道,且只使用一个filter,输出一个channel。

    其中,针对单通道,与2D卷积不同之处在于,输入图像多了一个 depth 维度,故输入大小为(1, depth, height, width),卷积核也多了一个k_d维度,因此卷积核在输入3D图像的空间维度(height和width维)和depth维度上均进行滑窗操作,每次滑窗与 (k_d, k_h, k_w) 窗口内的values进行相关操作,得到输出3D图像中的一个value.

    针对多通道,输入大小为(3, depth, height, width),则与2D卷积的操作一样,每次滑窗与3个channels上的 (k_d, k_h, k_w) 窗口内的所有values进行相关操作,得到输出3D图像中的一个value。
    在这里插入图片描述
    参考:
    https://blog.csdn.net/weixin_36836622/article/details/90355877
    https://www.zhihu.com/question/266352189

    空洞卷积

    在这里插入图片描述

    1.引入空洞卷积

    该结构的目的是在不用pooling(pooling层会导致信息损失)且计算量相当的情况下,提供更大的感受野。 顺便一提,卷积结构的主要问题如下:

    • 池化层不可学
    • 内部数据结构丢失;空间层级化信息丢失。
    • 小物体信息无法重建 (假设有四个pooling layer 则 任何小于 2^4 = 16 pixel 的物体信息将理论上无法重建。)

    而空洞卷积就有内部数据结构的保留和避免使用 down-sampling 这样的特性,优点明显。

    2.结构

    感受野 积神经网络中每层的特征图(Feature Map)上的像素点在原始图像中映射的区域大小,也就相当于高层的特征图中的像素点受原图多大区域的影响!
    感受野越大——每个卷积输出都包含较大范围的信息

    这对于视觉任务来说十分的关键!所以在设计神经网络时,要充分考虑到感受野的问题,这样模型也会更加精确和鲁棒~。

    扩张率(dilation rate) 主要用来表示扩张的大小 该参数定义了卷积核处理数据时各值的间距。

    在这里插入图片描述
    kernel都是3*3

    • 图(a)为1-dilated conv,感受野为3×3
    • 图(b)为2-dilated conv,跟在1-dilated conv后面,感受野扩大为为7×7
    • 图©为4-dilated conv,同样跟在1-dilated conv以及2-dilated conv后面,感受野扩大为为15×15
    • 相比之下,使用stride为1的普通卷积,三层后的感受野仅为7×7

    3.空洞卷积的作用

    (1)扩大感受野

    在deep net中为了增加感受野且降低计算量,总要进行降采样(pooling或s2/conv),这样虽然可以增加感受野,但空间分辨率降低了。**为了能不丢失分辨率,且仍然扩大感受野,可以使用空洞卷积。**这在检测,分割任务中十分有用。一方面感受野大了可以检测分割大目标,另一方面分辨率高了可以精确定位目标。

    (2) 捕获多尺度上下文信息

    空洞卷积有一个参数可以设置dilation rate,具体含义就是在卷积核中填充dilation rate-1个0,因此,当设置不同dilation rate时,感受野就会不一样,也即获取了多尺度信息。

    4.问题:

    (1) Gridding Effect

    扩张卷积虽然在不损失特征图尺寸的情况下增大了感受野,但是也会带来新的问题,主要是体现在卷积的输入,由于卷积核是有间隔的,这意味着不是所有的输入都参与计算,整体特征图上体现出一种卷积中心点的不连续,尤其是当叠加的卷积层都是用相同的dilation rate的时候:
    在这里插入图片描述
    上图中示例是三个dilation rate=2扩张卷积层连续卷积后的结果,蓝色的标识是参与计算的卷积中心,而颜色的深度表征次数。可以看到,由于3次的dilation rate是一致的额,所以卷积的计算中心会呈现出一种网格状向外扩展,有一些点不会成为计算的中心点。

    (2)

    光采用大 dilation rate 的信息或许只对一些大物体分割有效果,而对小物体来说可能则有弊无利了。

    5.解决

    解决这个问题最直接的方法当然就是不使用连续的dilation rate相同的扩展卷积,但是这还不够,因为如果dilation rate是成倍数的,那么问题还是存在。所以最好的方式是将连续排布的扩张卷积的dilation rate设置为“锯齿状”,比如分别是[1,2,3],

    一个简单的例子: dilation rate [1, 2, 5] with 3 x 3 kernel (可行的方案):
    在这里插入图片描述
    而这样的锯齿状本身的性质就比较好的来同时满足小物体大物体的分割要求(小 dilation rate 来关心近距离信息,大 dilation rate 来关心远距离信息)。

    空洞卷积一般应用在语义分割上~

    参考:
    https://blog.csdn.net/chaipp0607/article/details/99671483
    感受野计算
    https://www.jianshu.com/p/f743bd9041b3
    https://www.cnblogs.com/hellcat/p/9687624.html

    展开全文
  • 本文转自:...数字图像处理中的形态学处理是指将数字形态学作为工具从图像中提取对于表达和描绘区域形状有用处的图像分量,比如边界、骨架以及凸壳,还包括用于预处理或后处理的形态学过滤、细化和

    本文转自:http://blog.sina.com.cn/s/blog_3d8fb3a90100rg65.html

    一、图像腐蚀 膨胀 细化的基本原理

    1.图像细化的基本原理

     图像形态学处理的概念

    数字图像处理中的形态学处理是指将数字形态学作为工具从图像中提取对于表达和描绘区域形状有用处的图像分量,比如边界、骨架以及凸壳,还包括用于预处理或后处理的形态学过滤、细化和修剪等。图像形态学处理中我们感兴趣的主要是二值图像。

    在二值图像中,所有黑色像素的集合是图像完整的形态学描述,二值图像的各个分量是Z2的元素。假定二值图像A和形态学处理的结构元素B是定义在笛卡儿网格上的集合,网格中值为1的点是集合的元素,当结构元素的原点移到点(x,y)时,记为Sxy,为简单起见,结构元素为3x3,且全都为1,在这种限制下,决定输出结果的是逻辑运算。

     二值图像的逻辑运算

    逻辑运算尽管本质上很简单,但对于实现以形态学为基础额图像处理算法是一种有力的补充手段。在图像处理中用到的主要逻辑运算是:与、或和非(求补),它们可以互相组合形成其他逻辑运算。

     膨胀和腐蚀

    膨胀和腐蚀这两种操作是形态学处理的基础,许多形态学算法都是以这两种运算为基础的。

     膨胀

    是以得到B的相对与它自身原点的映像并且由z对映像进行移位为基础的。AB膨胀是所有位移z的集合,这样,A至少有一个元素是重叠的。我们可以把上式改写为:

    结构元素B可以看作一个卷积模板,区别在于膨胀是以集合运算为基础的,卷积是以算术运算为基础的,但两者的处理过程是相似的。

     用结构元素B,扫描图像A的每一个像素

     用结构元素与其覆盖的二值图像做“与”操作

     如果都为0,结果图像的该像素为0。否则为1

     腐蚀

    Z中的集合ABBA进行腐蚀的整个过程如下:

     用结构元素B,扫描图像A的每一个像素

     用结构元素与其覆盖的二值图像做“与”操作

     如果都为1,结果图像的该像素为1。否则为0

    腐蚀处理的结果是使原来的二值图像减小一圈。

     击中(匹配)或击不中变换

    假设集合A是由3个子集XYZ组成的集合,击中(匹配)的目的是要在A中找到X的位置,我们设X被包围在一个小窗口W中,与W有关的X的局部背景定义为集合的差(WX),则XA内能得到精确拟合位置集合是由XA的腐蚀后由(WX)对A的补集Ac腐蚀的交集,这个交集就是我们要找的位置,我们用集合B来表示由XX的背景构成的集合,我们可以令B=(B1B2),这里B1XB2=(WX),则在A中对B进行匹配可以表示为:

    AB

    我们称为形态学上的击中或击不中变换。

     开闭操作

    开操作是先腐蚀、后膨胀处理。

    闭操作是先膨胀、后腐蚀处理。

    (6) 细化

    图像细化一般作为一种图像预处理技术出现,目的是提取源图像的骨架,即是将原图像中线条宽度大于1个像素的线条细化成只有一个像素宽,形成“骨架”,形成骨架后能比较容易的分析图像,如提取图像的特征。

    细化基本思想是“层层剥夺”,即从线条边缘开始一层一层向里剥夺,直到线条剩下一个像素的为止。图像细化大大地压缩了原始图像地数据量,并保持其形状的基本拓扑结构不变,从而为文字识别中的特征抽取等应用奠定了基础。细化算法应满足以下条件:

     将条形区域变成一条薄线;

     薄线应位与原条形区域的中心;

     薄线应保持原图像的拓扑特性。

    细化分成串行细化和并行细化,串行细化即是一边检测满足细化条件的点,一边删除细化点;并行细化即是检测细化点的时候不进行点的删除只进行标记,而在检测完整幅图像后一次性去除要细化的点。

    常用的图像细化算法有hilditch算法,pavlidis算法和rosenfeld算法等。

    注:进行细化算法前要先对图像进行二值化,即图像中只包含“黑”和“白”两种颜色。

    二、OpenCv形态学操作相关函数

    1MorphologyEx         高级形态学变换

    void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp,

    IplConvKernel* element, int operation, int iterations=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 模式下需要。

    2Dilate    使用任意结构元素膨胀图像

    void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );

    src 输入图像.

    dst 输出图像.

    element 用于膨胀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素

    iterations 膨胀的次数

    函数 cvDilate 对输入图像使用指定的结构元进行膨胀,该结构决定每个具有最小值象素点的邻域形状:dst=dilate(src,element): dst(x,y)=max((x',y') in element))src(x+x',y+y')

    函数支持(in-place)模式。膨胀可以重复进行 (iterations) . 对彩色图像,每个彩色通道单独处理。

    3Erode    使用任意结构元素腐蚀图像

    void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );

    src 输入图像.

    dst 输出图像.

    element 用于腐蚀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素

    iterations 腐蚀的次数

    函数 cvErode 对输入图像使用指定的结构元素进行腐蚀,该结构元素决定每个具有最小值象素点的邻域形状:dst=erode(src,element): dst(x,y)=min((x',y') in element))src(x+x',y+y')

    函数可能是本地操作,不需另外开辟存储空间的意思。腐蚀可以重复进行 (iterations) . 对彩色图像,每个彩色通道单独处理。

    注:CreateStructuringElementEx  创建结构元素;ReleaseStructuringElement 删除结构元素。

    三、OpenCv形态学实例代码:

    1、腐蚀、膨胀、开运算、闭运算

     

    #include "cv.h"  

    #include "highgui.h"  

    #include <stdlib.h>  

    #include <stdio.h>  

     

    IplImage *src=0;  

    IplImage *dst=0;  

    IplConvKernel *element=0;//声明一个结构元素  

    int element_shape=CV_SHAPE_RECT;//长方形形状的元素  

    int max_iters=10;  

    int open_close_pos=0;  

    int erode_dilate_pos=0;  

    void OpenClose(int pos)  

    {  

        int n=open_close_pos-max_iters;  

        int an=n>0?n:-n;  

        element = cvCreateStructuringElementEx(an*2+1,   an*2+1,an,an,element_shape,0);//创建结构元素  

        if (n<0)  

        {  

            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);  

    }  

    void ErodeDilate(int pos)  

    {  

        int n=erode_dilate_pos-max_iters;  

        int an=n>0?n:-n;  

        element = cvCreateStructuringElementEx(an*2+1,an*2+1,an,an,element_shape,0);  

        if (n<0)  

        {  

            cvErode(src,dst,element,1);  

        }  

        else 

        {  

            cvDilate(src,dst,element,1);  

        }  

        cvReleaseStructuringElement(&element);  

        cvShowImage("Erode/Dilate",dst);  

    }  

     

    int main(int argc,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 = erode_dilate_pos = max_iters;  

        cvCreateTrackbar("iterations","Open/Close",&open_close_pos,max_iters*2+1,OpenClose);  

    cvCreateTrackbar("iterations","Erode/Dilate",&erode_dilate_pos,max_iters*2+1,

    ErodeDilate);  

        for (;;)  

        {  

            int c; 

            OpenClose(open_close_pos);  

            ErodeDilate(erode_dilate_pos);  

            c= cvWaitKey(0);  

            if (c==27)  

            {  

                break;  

            }  

            switch(c) {  

            case 'e':  

                element_shape=CV_SHAPE_ELLIPSE;  

                break;  

            case 'r':  

                element_shape=CV_SHAPE_RECT;  

                break;  

            case '\r':  

                element_shape=(element_shape+1)%3; 

                break;  

            default:  

                break; 

            }  

        }  

        cvReleaseImage(&src);  

        cvReleaseImage(&dst);  

        cvDestroyWindow("Open/Close");  

        cvDestroyWindow("Erode/Dilate");  

        return 0;  

    }  

    /***************************** 

    腐蚀和膨胀,看上去好像是一对互逆的操作,实际上,这两种操作不具有互逆的关系。 

    开运算和闭运算正是依据腐蚀和膨胀的不可逆性,演变而来的。 

    先腐蚀后膨胀的过程就称为开运算。

    闭运算是通过对腐蚀和膨胀的另一种不同次序的执行而得到的, 

    闭运算是先膨胀后腐蚀的过程,其功能是用来填充物体内细小空洞、连接邻近物体、平滑其边界,同时不明显改变不明显改变其面积。 


    展开全文
  • 图像处理-形态学操作

    2017-05-03 17:10:32
    关于形态学的实验需要对二值图像进行减噪处理图像形态学中的腐蚀和膨胀能很好的解决此问题。如果在腐蚀和膨胀操作前,对灰度图像做一次滤波,减噪效果将更明显。 腐蚀的具体操作是:用一个结构元素(一般是3×3的...

    关于形态学的实验需要对二值图像进行减噪处理,图像形态学中的腐蚀和膨胀能很好的解决此问题。如果在腐蚀和膨胀操作前,对灰度图像做一次滤波,减噪效果将更明显。
    腐蚀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。膨胀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。
    腐蚀的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点;膨胀的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的空洞。
    开运算是先腐蚀后膨胀的过程,可以消除图像上细小的噪声,并平滑物体边界。
    闭运算时先膨胀后腐蚀的过程,可以填充物体内细小的空洞,并平滑物体边界。

    MATLAB中基本知识点:

    1.对二值化图像进行形态学处理(bwmorph)

    函数调用格式:

    BW=bwmorph(I,operation);

    BW=bwmorph(I,operation,n);

    Operation:

    ‘bothat’:闭包运算,即先腐蚀,在膨胀,然后减去原图像;

    ‘branchpoints’:找出骨架的分支结点

    ‘endpoints’:找出骨架端点
    ‘bridge’:做连接运算;

    ‘clean’:去除孤立的亮点;

    ‘close’:进行二值闭运算(先膨胀后腐蚀);

    ‘diag’:采用对角线填充来去除8邻域的背景;

    ‘dilate’:采用结构元素ones(3)做膨胀运算;

    ‘erode’:采用结构元素ones(3)作腐蚀运算; 
    ‘fill’:填充孤立的黑点; 
        imfill

    ‘hbreak’:断开H形连接;

    ‘Majority’:若像素的8邻域中有大于或等于5的元素为1,则像素为1,否则为0; 
    ‘open’:执行二值开运算(先腐蚀后膨胀); 

    ‘remove’:去掉内点,即若像素的4邻域都为1,则像素为0;

    ‘shrink’n=inf:做收缩运算,这样没有孔的物体收缩为一个点,而含孔的物体收缩为一个相连的环,环的位置在孔和物体外边缘的中间,收缩运算保持欧拉数不变,

    ‘skel’n=inf: 提取物体的骨架,即去除物体外边缘的点,但是保持物体不发生断裂,它也保持欧拉数不变。 

    ‘spur’:去除物体小的分支; 
    ‘thicken’n=inf;对物体进行粗化,即对物体的外边缘增加像素,知道原来为连接的物体按照8邻域被连接起来。粗化保持欧拉数不变。 

    ‘thin’n=inf:对物体进行细化,使得没有孔的物体收缩为最小连接棒,而含有孔的物体收缩为一个连接的环,同样细化保持欧拉数不变。

    ‘tophat’:用原图减去开运算后的图像;

    2. matlab函数bwareaopen──删除小面积对象
    格式:BW2 
    bwareaopen(BW,P,conn)
    作用:删除二值图像BW中面积小于P的对象,默认情况下使用8邻域。

    算法:
    (1)Determine 
    the connected components.
     
     bwlabeln(BW, conn); %标记连通域
    (2)Compute 
    the area of each component.
     
     regionprops(L, 'Area');  %计算连通域面积
    (3)Remove 
    small objects.
     
     bw2 ismember(L, find([S.Area] >= P)); %删除面积大于等于p的连通域

    3.matlab函数bwarea──计算对象面积
    格式:total 
    bwarea(BW)
    作用:估计二值图像中对象的面积。
    注:该面积和二值图像中对象的像素数目不一定相等。

    3、matlab函数imclearborder──边界对象抑制
    格式:IM2 
    imclearborder(IM,conn)
    作用:抑制和图像边界相连的亮对象。若IM是二值图,imclearborder将删除和图像边界相连的对象。默认情况conn=8。
    注:For 
    grayscale images, imclearborder tends to reduce the overall intensity level in addition to suppressing border structures.
    算法:
    (1)Mask 
    image is the input image.
    (2)Marker 
    image is zero everywhere except along the border, where it equals the mask image.
    4、matlab函数bwboundaries──获取对象轮廓
    格式:B 
    bwboundaries(BW,conn)(基本格式)
    作用:获取二值图中对象的轮廓,和OpenCV中cvFindContours函数功能类似。B是一个P×1的cell数组,P为对象个数,每个cell 
    是Q×2的矩阵,对应于对象轮廓像素的坐标。
    5、matlab函数imregionalmin──获取极小值区域
    格式:BW 
    imregionalmin(I,conn)
    作用:寻找图像I的极小值区域(regional 
    maxima),默认情况conn=8。
    Regional 
    minima are connected components of pixels with constant intensity value, and whose external boundary pixels all have higher value.
    6、matlab函数bwulterode──距离变换的极大值
    格式:BW2 
    bwulterode(BW,method,conn)
    作用:终极腐蚀。寻找二值图像BW的距离变换图的区域极大值(regional 
    maxima)。用于距离变换的距离默认为euclidean,连通性为8邻域。
    7、regionprops统计被标记的区域的面积分布,显示区域总数。
    函数regionprops语法规则为:STATS 
    regionprops(L,properties)
    该函数用来测量标注矩阵L中每一个标注区域的一系列属性。
    L中不同的正整数元素对应不同的区域,例如:L中等于整数1的元素对应区域1;L中等于整数2的元素对应区域2;以此类推。
    返回值STATS是一个 
    长度为max(L(:))的结构数组,结构数组的相应域定义了每一个区域相应属性下的度量。
    Properties可以是由逗号分割的字符串列表、包含字符 
    串的单元数组、单个字符串'all'或者'basic'。如果properties等于字符串'all',则表4.1中的度量数据都将被计算;如果properties等于字符串'basic',则属性:'Area','Centroid'和'BoundingBox'将被计算。表1就是所有有效的属性字符串。
    属性字符串列表----度量图像区域的属性或功能
    'Area' 
    图像各个区域中像素总个数
    'BoundingBox' 
     包含相应区域的最小矩形
    'Centroid' 
    每个区域的质心(重心)
    'MajorAxisLength' 
    与区域具有相同标准二阶中心矩的椭圆的长轴长度(像素意义下)
    'MinorAxisLength' 
    与区域具有相同标准二阶中心矩的椭圆的短轴长度(像素意义下)
    'Eccentricity' 
    与区域具有相同标准二阶中心矩的椭圆的离心率(可作为特征)
    'Orientation' 
    与区域具有相同标准二阶中心矩的椭圆的长轴与x轴的交角(度)
    'Image' 
    与某区域具有相同大小的逻辑矩阵
    'FilledImage' 
    与某区域具有相同大小的填充逻辑矩阵
    'FilledArea' 
    填充区域图像中的on像素个数
    'ConvexHull' 
    包含某区域的最小凸多边形
    'ConvexImage' 
    画出上述区域最小凸多边形
    'ConvexArea' 
      填充区域凸多边形图像中的on像素个数
    'EulerNumber' 
    几何拓扑中的一个拓扑不变量——欧拉数
    'Extrema' 
    八方向区域极值点
    'EquivDiameter' 
    与区域具有相同面积的圆的直径
    'Solidity' 
    同时在区域和其最小凸多边形中的像素比例
    'Extent' 
    同时在区域和其最小边界矩形中的像素比例
    'PixelIdxList' 
    存储区域像素的索引下标
    'PixelList' 
    存储上述索引对应的像素坐标

    提醒

    使用逗号分割列表语法:当你基于regionprops函数的输出作算法设计时,使用逗号分割列表语法就凸显出其非常的价值。例如:对于一个存储标量的属性,可以利用此语法创建一个包含图像中不同区域内此属性值的向量。例如以下两句是等价的:

    stats(1).Area, stats(2).Area, ..., stats(end).Area

    stats.Area

    因此,可以使用下面的方法创建相应的向量:

    regionprops(L,'Area'); allArea [stats.Area];

    allArea 就是一个与结构数组 stats 具备相同长度的向量。

    基于特定原则的区域选择:当你要基于特定准则条件选择某个区域时,将函数 ismember 和 regionprops 联合使用是很有用处的。例如:创建一个只包含面积大于80的二值图像,用以下命令

    idx find([stats.Area] 80); BW2 ismember(L,idx);

    计算性能考虑:大多数的属性测量计算时间都非常地少,除了那些非常依赖于图像L中区域个数和像素个数的属性。例如:

    'ConvexHull' 'ConvexImage' 'ConvexArea' 'FilledImage'

    另外建议一次性计算所有属性值,因为分开计算和一起计算时间相差无几!

    使用二值图像工作:在调用regionprops之前必须将二值图像转变为标注矩阵。两个函数可以做到:

    bwlabel(BW); double(BW);

    注意:虽然这两个函数从同一二值图像产生不同的标注矩阵,但是它们是等效的!例如:给出如下的二值矩阵BW,

    1

    bwlabel 创建一个包含两个分别由整数1和2标注的连续区域标注矩阵

    mylabel bwlabel(BW)

     mylabel 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 0 2 2

    double 创建一个包含一个由整数1标注的不连续区域标注矩阵。

    mylabel2 = double(BW) 

    mylabel2 = 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1

    regionprops 并不负责自动转换二值图像数据类型,而是由你自己决定使用何种数据转换方法来存储自己想要的数据。

    regionprops函数的扩展思路:在regionprops函数的基础上,你可以使用它提供的基本数据来扩展它的功能,将区域的曲率数据和骨架数据作为它的另外属性值来开发,从而希望

    它能用来做更细致的特征提取。

    1. %% imdilate膨胀  
    2. clc  
    3. clear  
    4.   
    5. A1=imread('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif');  
    6. info=imfinfo('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif')  
    7. B=[0 1 0  
    8.    1 1 1  
    9.    0 1 0];  
    10. A2=imdilate(A1,B);%图像A1被结构元素B膨胀  
    11. A3=imdilate(A2,B);  
    12. A4=imdilate(A3,B);  
    13.   
    14. subplot(221),imshow(A1);  
    15. title('imdilate膨胀原始图像');  
    16.   
    17. subplot(222),imshow(A2);  
    18. title('使用B后1次膨胀后的图像');  
    19.   
    20. subplot(223),imshow(A3);  
    21. title('使用B后2次膨胀后的图像');  
    22.   
    23. subplot(224),imshow(A4);  
    24. title('使用B后3次膨胀后的图像');  
    25. %imdilate图像膨胀处理过程运行结果如下:  
    26. <img src="https://img-blog.csdn.net/20150511101157664?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    27. %% imerode腐蚀  
    28. clc  
    29. clear  
    30. A1=imread('.\images\dipum_images_ch09\Fig0908(a)(wirebond-mask).tif');  
    31. subplot(221),imshow(A1);  
    32. title('腐蚀原始图像');  
    33.   
    34. %strel函数的功能是运用各种形状和大小构造结构元素  
    35. se1=strel('disk',5);%这里是创建一个半径为5的平坦型圆盘结构元素  
    36. A2=imerode(A1,se1);  
    37. subplot(222),imshow(A2);  
    38. title('使用结构原始disk(5)腐蚀后的图像');  
    39.   
    40. se2=strel('disk',10);  
    41. A3=imerode(A1,se2);  
    42. subplot(223),imshow(A3);  
    43. title('使用结构原始disk(10)腐蚀后的图像');  
    44.   
    45. se3=strel('disk',20);  
    46. A4=imerode(A1,se3);  
    47. subplot(224),imshow(A4);  
    48. title('使用结构原始disk(20)腐蚀后的图像');  
    49. %图像腐蚀处理过程运行结果如下:  
    50. <img src="https://img-blog.csdn.net/20150511101025028?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    51. %% 开运算和闭运算  
    52. clc  
    53. clear  
    54. f=imread('.\images\dipum_images_ch09\Fig0910(a)(shapes).tif');  
    55. %se=strel('square',5');%方型结构元素  
    56. se=strel('disk',5');%圆盘型结构元素  
    57. imshow(f);%原图像  
    58. title('开闭运算原始图像')  
    59. %运行结果如下:  
    60. <img src="https://img-blog.csdn.net/20150511101045230?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    61. %开运算数学上是先腐蚀后膨胀的结果  
    62. %开运算的物理结果为完全删除了不能包含结构元素的对象区域,平滑  
    63. %了对象的轮廓,断开了狭窄的连接,去掉了细小的突出部分  
    64. fo=imopen(f,se);%直接开运算  
    65. figure,subplot(221),imshow(fo);  
    66. title('直接开运算');  
    67.   
    68. %闭运算在数学上是先膨胀再腐蚀的结果  
    69. %闭运算的物理结果也是会平滑对象的轮廓,但是与开运算不同的是,闭运算  
    70. %一般会将狭窄的缺口连接起来形成细长的弯口,并填充比结构元素小的洞  
    71. fc=imclose(f,se);%直接闭运算  
    72. subplot(222),imshow(fc);  
    73. title('直接闭运算');  
    74.   
    75. foc=imclose(fo,se);%先开后闭运算  
    76. subplot(223),imshow(foc);  
    77. title('先开后闭运算');  
    78.   
    79. fco=imopen(fc,se);%先闭后开运算  
    80. subplot(224),imshow(fco);  
    81. title('先闭后开运算');  
    82. %开闭运算结果如下:  
    83. <img src="https://img-blog.csdn.net/20150511101101345?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    84. %先膨胀再腐蚀  
    85. fse=imdilate(f,se);%膨胀  
    86.   
    87. %gcf为得到当前图像的句柄,当前图像是指例如PLOT,TITLE,SURF等  
    88. %get函数为得到物体的属性,get(0,'screensize')为返回所有物体screensize属性值  
    89. %set函数为设置物体的属性  
    90. figure,set(gcf,'outerposition',get(0,'screensize'));%具体目的是设置当前窗口的大小  
    91. subplot(211),imshow(fse);  
    92. title('使用disk(5)先膨胀后的图像');  
    93.   
    94. fes=imerode(fse,se);  
    95. subplot(212),imshow(fes);  
    96. title('使用disk(5)先膨胀再腐蚀后的图像');  
    97. %先膨胀后腐蚀图像如下:  
    98. <img src="https://img-blog.csdn.net/20150511101316569?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    99. %先腐蚀再膨胀  
    100. fse=imerode(f,se);  
    101. figure,set(gcf,'outerposition',get(0,'screensize'))  
    102. subplot(211),imshow(fse);  
    103. title('使用disk(5)先腐蚀后的图像');  
    104.   
    105. fes=imdilate(fse,se);  
    106. subplot(212),imshow(fes);  
    107. title('使用disk(5)先腐蚀再膨胀后的图像');  
    108. %先腐蚀后膨胀的图像如下:  
    109. <img src="https://img-blog.csdn.net/20150511101331576?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    110. %% imopen imclose在指纹上的应用  
    111. clc  
    112. clear  
    113. f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');  
    114. se=strel('square',3);%边长为3的方形结构元素  
    115. subplot(121),imshow(f);  
    116. title('指纹原始图像');  
    117.   
    118. A=imerode(f,se);%腐蚀  
    119. subplot(122),imshow(A);  
    120. title('腐蚀后的指纹原始图像');  
    121. %指纹原始图像和腐蚀后的图像结果如下:  
    122. <img src="https://img-blog.csdn.net/20150511101349765?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    123. fo=imopen(f,se);  
    124. figure,subplot(221),imshow(fo);  
    125. title('使用square(3)开操作后的图像');  
    126.   
    127. fc=imclose(f,se);  
    128. subplot(222),imshow(fc);  
    129. title('使用square闭操作后的图像');  
    130.   
    131. foc=imclose(fo,se);  
    132. subplot(223),imshow(foc);  
    133. title('使用square(3)先开后闭操作后的图像')  
    134.   
    135. fco=imopen(fc,se);  
    136. subplot(224),imshow(fco);  
    137. title('使用square(3)先闭后开操作后的图像');  
    138. %指纹图像开闭操作过程结果如下:  
    139. <img src="https://img-blog.csdn.net/20150511101217629?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    140. %% bwhitmiss击中或击不中变换  
    141. clc  
    142. clear  
    143. f=imread('.\images\dipum_images_ch09\Fig0913(a)(small-squares).tif');  
    144. imshow(f);  
    145. title('击中或不击中原始图像');  
    146. %击中或不击中原始图像显示结果如下:  
    147. <img src="https://img-blog.csdn.net/20150511101425458?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    148. B1=strel([0 0 0;0 1 1;0 1 0]);%击中:要求击中所有1的位置  
    149. B2=strel([1 1 1;1 0 0;1 0 0]);%击不中,要求击不中所有1的位置  
    150. B3=strel([0 1 0;1 1 1;0 1 0]);%击中  
    151. B4=strel([1 0 1;0 0 0;0 0 0]);%击不中  
    152. B5=strel([0 0 0;0 1 0;0 0 0]);%击中  
    153. B6=strel([1 1 1;1 0 0;1 0 0]);%击不中  
    154.   
    155. g=imerode(f,B1)&imerode(~f,B2)%利用定义来实现击中或击不中  
    156. figure,subplot(221),imshow(g);  
    157. title('定义实现组1击中击不中图像');  
    158.   
    159. g1=bwhitmiss(f,B1,B2);  
    160. subplot(222),imshow(g1);  
    161. title('结构数组1击中击不中后的图像');  
    162.   
    163. g2=bwhitmiss(f,B3,B4);  
    164. subplot(223),imshow(g2);  
    165. title('结构数组2击中击不中的图像');  
    166.   
    167. g3=bwhitmiss(f,B5,B6);  
    168. subplot(224),imshow(g3);  
    169. title('结构数组3击中击不中的图像');  
    170. %击中击不中变换后图像如下:  
    171. <img src="https://img-blog.csdn.net/20150511101443648?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    172. %%makelut  
    173. clc  
    174. clear  
    175.   
    176. f=inline('sum(x(:))>=3');%inline是用来定义局部函数的  
    177. lut2=makelut(f,2)%为函数f构造一个接收2*2矩阵的查找表  
    178. lut3=makelut(f,3)  
    179.   
    180. %% Conway生命游戏  
    181. clc  
    182. clear  
    183. lut=makelut(@conwaylaws,3);  
    184. bw1=  [0     0     0     0     0     0     0     0     0     0  
    185.        0     0     0     0     0     0     0     0     0     0  
    186.        0     0     0     1     0     0     1     0     0     0  
    187.        0     0     0     1     1     1     1     0     0     0  
    188.        0     0     1     0     0     0     0     1     0     0  
    189.        0     0     1     0     1     1     0     1     0     0  
    190.        0     0     1     0     0     0     0     1     0     0  
    191.        0     0     0     1     1     1     1     0     0     0  
    192.        0     0     0     0     0     0     0     0     0     0  
    193.        0     0     0     0     0     0     0     0     0     0  ];  
    194. subplot(221),imshow(bw1,'InitialMagnification','fit');  
    195. title('Generation 1');  
    196.   
    197. bw2=applylut(bw1,lut);  
    198. subplot(222),imshow(bw2,'InitialMagnification','fit'),  
    199. title('Generation 2');  
    200.   
    201. bw3=applylut(bw2,lut);  
    202. subplot(223),imshow(bw3,'InitialMagnification','fit');  
    203. title('Generation 3');  
    204.   
    205. temp=bw1;  
    206. for i=2:100  
    207.     bw100=applylut(temp,lut);  
    208.     temp=bw100;  
    209. end  
    210. subplot(224),imshow(bw100,'InitialMagnification','fit')  
    211. title('Generation 100');  
    212. %显示Generation结果如下:  
    213. <img src="https://img-blog.csdn.net/20150511101505488?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    214. %% getsequence  
    215. clc  
    216. clear  
    217. se=strel('diamond',5)  
    218. decomp=getsequence(se)%getsequence函数为得到分解的strel序列  
    219. decomp(1)  
    220. decomp(2)  
    221.   
    222. %% endpoints  
    223. clc  
    224. clear  
    225.   
    226. f1=imread('.\images\dipum_images_ch09\Fig0914(a)(bone-skel).tif');  
    227. subplot(121),imshow(f1);  
    228. title('原始形态骨架图像');  
    229.   
    230. g1=endpoints(f1);  
    231. %set(gcf,'outerposition',get(0,'screensize'));%运行完后自动生成最大的窗口  
    232. subplot(122),imshow(g1);  
    233. title('骨架图像的端点图像');  
    234. <img src="https://img-blog.csdn.net/20150511101524941?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    235. %骨架头像端点检测头像如下:  
    236. f2=imread('.\images\dipum_images_ch09\Fig0916(a)(bone).tif');  
    237. figure,subplot(121),imshow(f2);  
    238. title('原始骨头图像');  
    239.   
    240. g2=endpoints(f2);  
    241. subplot(122),imshow(g2);  
    242. title('骨头图像端点头像');%结果是没有端点  
    243. %骨头头像端点检测图像如下:  
    244. <img src="https://img-blog.csdn.net/20150511101352134?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    245. %% bwmorph组合常见形态学之细化  
    246. clc  
    247. clear  
    248. f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');  
    249. subplot(221),imshow(f);  
    250. title('指纹图像细化原图');  
    251.   
    252. g1=bwmorph(f,'thin',1);  
    253. subplot(222),imshow(g1);  
    254. title('指纹图像细化原图');  
    255.   
    256. g2=bwmorph(f,'thin',2);  
    257. subplot(223),imshow(g2);  
    258. title('指纹图像细化原图');  
    259.   
    260. g3=bwmorph(f,'thin',Inf);  
    261. subplot(224),imshow(g3);  
    262. title('指纹图像细化原图');  
    263. %指纹图像细化过程显示如下:  
    264. <img src="https://img-blog.csdn.net/20150511101604674?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    265. %% bwmorph组合常见形态学之骨骼化  
    266. clc  
    267. clear  
    268. f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');  
    269. subplot(131),imshow(f);  
    270. title('指纹图像骨骼化原图');  
    271.   
    272. fs=bwmorph(f,'skel',Inf);  
    273. subplot(132),imshow(fs);  
    274. title('指纹图像骨骼化');  
    275.   
    276. for k=1:5  
    277.     fs=fs&~endpoints(fs);  
    278. end  
    279. subplot(133),imshow(fs);  
    280. title('指纹图像修剪后骨骼话');  
    281. %指纹图像骨骼化过程显示:  
    282. <img src="https://img-blog.csdn.net/20150511101625126?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    283. %% 使用函数bwlabel标注连通分量  
    284. clc  
    285. clear  
    286. f=imread('.\images\dipum_images_ch09\Fig0917(a)(ten-objects).tif');  
    287. imshow(f),title('标注连通分量原始图像');  
    288. %其结果显示如下:  
    289. <img src="https://img-blog.csdn.net/20150511101453130?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    290. [L,n]=bwlabel(f);%L为标记矩阵,n为找到连接分量的总数  
    291. [r,c]=find(L==3);%返回第3个对象所有像素的行索引和列索引  
    292.   
    293. rbar=mean(r);  
    294. cbar=mean(c);  
    295.   
    296. figure,imshow(f)  
    297. hold on%保持当前图像使其不被刷新  
    298. for k=1:n  
    299.     [r,c]=find(L==k);  
    300.     rbar=mean(r);  
    301.     cbar=mean(c);  
    302.     plot(cbar,rbar,'Marker','o','MarkerEdgeColor','k',...  
    303.          'MarkerFaceColor','k','MarkerSize',10);%这个plot函数用法不是很熟悉  
    304.     plot(cbar,rbar,'Marker','*','MarkerFaceColor','w');%其中的marker为标记  
    305. end  
    306. title('标记所有对象质心后的图像');  
    307. <img src="https://img-blog.csdn.net/20150511101702129?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    308. %% 由重构做开运算  
    309. clc  
    310. clear  
    311. f=imread('.\images\dipum_images_ch09\Fig0922(a)(book-text).tif');  
    312. subplot(321),imshow(f);  
    313. title('重构原始图像');  
    314.   
    315. fe=imerode(f,ones(51,1));%竖线腐蚀  
    316. subplot(322),imshow(fe);  
    317. title('使用竖线腐蚀后的结果');  
    318.   
    319. fo=imopen(f,ones(51,1));%竖线做开运算  
    320. subplot(323),imshow(fo);  
    321. title('使用竖线做开运算结果');  
    322.   
    323. fobr=imreconstruct(fe,f);%fe做标记  
    324. subplot(324),imshow(fobr);  
    325. title('使用竖线做重构开运算');  
    326.   
    327. ff=imfill(f,'holes');%对f进行孔洞填充  
    328. subplot(325),imshow(ff);  
    329. title('对f填充孔洞后的图像');  
    330.   
    331. fc=imclearborder(f,8);%清除边界,2维8邻接  
    332. subplot(326),imshow(fc);  
    333. title('对f清除边界后的图像');  
    334. %图像重构过程显示如下:  
    335. <img src="https://img-blog.csdn.net/20150511101524392?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    336. %% 使用顶帽变换和底帽变换  
    337. clc  
    338. clear  
    339. f=imread('.\images\dipum_images_ch09\Fig0926(a)(rice).tif');  
    340. subplot(221),imshow(f);  
    341. title('顶帽底帽变换原始图像');  
    342.   
    343. se=strel('disk',10);%产生结构元素  
    344. %顶帽变换是指原始图像减去其开运算的图像  
    345. %而开运算可用于补偿不均匀的背景亮度,所以用一个大的结构元素做开运算后  
    346. %然后用原图像减去这个开运算,就得到了背景均衡的图像,这也叫做是图像的顶帽运算  
    347. f1=imtophat(f,se);%使用顶帽变换  
    348. subplot(222),imshow(f1);  
    349. title('使用顶帽变换后的图像');  
    350.   
    351. %底帽变换是原始图像减去其闭运算后的图像  
    352. f2=imbothat(imcomplement(f),se);%使用底帽变换,为什么原图像要求补呢?  
    353. %f2=imbothat(f,se);%使用底帽变换  
    354. subplot(223),imshow(f2);  
    355. title('使用底帽变换后的图像');  
    356.   
    357. %顶帽变换和底帽变换联合起来用,用于增加对比度  
    358. f3=imsubtract(imadd(f,imtophat(f,se)),imbothat(f,se));%里面参数好像不合理?  
    359. subplot(224),imshow(f3);  
    360. title('使用顶帽底帽联合变换后图像');  
    361. %顶帽底帽变换过程图像如下:  
    362. <img src="https://img-blog.csdn.net/20150511101541786?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    363. %%使用开运算和闭运算做形态学平滑  
    364. %由于开运算可以除去比结构元素更小的明亮细节,闭运算可以除去比结构元素更小的暗色细节  
    365. %所以它们经常组合起来一起进行平滑图像并去除噪声  
    366. clc  
    367. clear  
    368. f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif');  
    369. subplot(221),imshow(f);  
    370. title('木钉图像原图');  
    371.   
    372. se=strel('disk',5);%disk其实就是一个八边形  
    373. fo=imopen(f,se);%经过开运算  
    374. subplot(222),imshow(f);  
    375. title('使用半径5的disk开运算后的图像');  
    376.   
    377. foc=imclose(fo,se);  
    378. subplot(223),imshow(foc);  
    379. title('先开后闭的图像');  
    380.   
    381. fasf=f;  
    382. for i=2:5  
    383.     se=strel('disk',i);  
    384.     fasf=imclose(imopen(fasf,se),se);  
    385. end  
    386. subplot(224),imshow(fasf);  
    387. title('使用开闭交替滤波后图像');  
    388. %使用开运算和闭运算做形态学平滑结果如下:  
    389. <img src="https://img-blog.csdn.net/20150511101753750?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    390. %% 颗粒分析  
    391. clc  
    392. clear  
    393. f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif');  
    394.   
    395. sumpixels=zeros(1,36);  
    396. for k=0:35  
    397.     se=strel('disk',k);  
    398.     fo=imopen(f,se);  
    399.     sumpixels(k+1)=sum(fo(:));  
    400. end  
    401.   
    402. %可以看到,连续开运算之间的表面积会减少  
    403. plot(0:35,sumpixels),xlabel('k'),ylabel('surface area');  
    404. title('表面积和结构元素半径之间的关系');  
    405. %其运算结果如下:     
    406. <img src="https://img-blog.csdn.net/20150511102014946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    407. figure,plot(-diff(sumpixels));%diff()函数为差分或者近似倒数,即相邻2个之间的差值  
    408. xlabel('k'),ylabel('surface area reduction');  
    409. title('减少的表面积和结构元素半径之间的关系');  
    410. %其运算结果如下:  
    411. <img src="https://img-blog.csdn.net/20150511102031341?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    412. %% 使用重构删除复杂图像的背景  
    413. clc  
    414. clear  
    415. f=imread('.\images\dipum_images_ch09\Fig0930(a)(calculator).tif');  
    416. subplot(221),imshow(f);  
    417. title('灰度级重构原图像');  
    418.   
    419. f_obr=imreconstruct(imerode(f,ones(1,71)),f);  
    420. subplot(222),imshow(f_obr);  
    421. title('经开运算重构图');  
    422.   
    423. f_o=imopen(f,ones(1,71));  
    424. subplot(223),imshow(f_o);  
    425. title('经开运算后图');  
    426.   
    427. f_thr=imsubtract(f,f_obr);  
    428. subplot(224),imshow(f_thr);  
    429. title('顶帽运算重构图')  
    430. %使用重构删除复杂图像的背景1:  
    431. <img src="https://img-blog.csdn.net/20150511101729692?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    432. f_th=imsubtract(f,f_o)  
    433. figure,subplot(221),imshow(f_th);  
    434. title('经顶帽运算图');  
    435.   
    436. g_obr=imreconstruct(imerode(f_thr,ones(1,11)),f_thr);  
    437. subplot(222),imshow(g_obr);  
    438. title('用水平线对f_thr经开运算后重构图');  
    439.   
    440. g_obrd=imdilate(g_obr,ones(1,2));  
    441. subplot(223),imshow(g_obrd);  
    442. title('使用水平线对上图进行膨胀');  
    443.   
    444. f2=imreconstruct(min(g_obrd,f_thr),f_thr);  
    445. subplot(224),imshow(f2);  
    446. title('最后的重构结果');  
    447. %使用重构删除复杂图像的背景2:  
    448. <img src="https://img-blog.csdn.net/20150511101757132?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />  
    449. 其中代码实现部分特别详细:  
    save_snippets.png
    %% imdilate膨胀
    clc
    clear
    
    A1=imread('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif');
    info=imfinfo('.\images\dipum_images_ch09\Fig0906(a)(broken-text).tif')
    B=[0 1 0
       1 1 1
       0 1 0];
    A2=imdilate(A1,B);%图像A1被结构元素B膨胀
    A3=imdilate(A2,B);
    A4=imdilate(A3,B);
    
    subplot(221),imshow(A1);
    title('imdilate膨胀原始图像');
    
    subplot(222),imshow(A2);
    title('使用B后1次膨胀后的图像');
    
    subplot(223),imshow(A3);
    title('使用B后2次膨胀后的图像');
    
    subplot(224),imshow(A4);
    title('使用B后3次膨胀后的图像');
    %imdilate图像膨胀处理过程运行结果如下:
    <img src="https://img-blog.csdn.net/20150511101157664?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% imerode腐蚀
    clc
    clear
    A1=imread('.\images\dipum_images_ch09\Fig0908(a)(wirebond-mask).tif');
    subplot(221),imshow(A1);
    title('腐蚀原始图像');
    
    %strel函数的功能是运用各种形状和大小构造结构元素
    se1=strel('disk',5);%这里是创建一个半径为5的平坦型圆盘结构元素
    A2=imerode(A1,se1);
    subplot(222),imshow(A2);
    title('使用结构原始disk(5)腐蚀后的图像');
    
    se2=strel('disk',10);
    A3=imerode(A1,se2);
    subplot(223),imshow(A3);
    title('使用结构原始disk(10)腐蚀后的图像');
    
    se3=strel('disk',20);
    A4=imerode(A1,se3);
    subplot(224),imshow(A4);
    title('使用结构原始disk(20)腐蚀后的图像');
    %图像腐蚀处理过程运行结果如下:
    <img src="https://img-blog.csdn.net/20150511101025028?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% 开运算和闭运算
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0910(a)(shapes).tif');
    %se=strel('square',5');%方型结构元素
    se=strel('disk',5');%圆盘型结构元素
    imshow(f);%原图像
    title('开闭运算原始图像')
    %运行结果如下:
    <img src="https://img-blog.csdn.net/20150511101045230?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %开运算数学上是先腐蚀后膨胀的结果
    %开运算的物理结果为完全删除了不能包含结构元素的对象区域,平滑
    %了对象的轮廓,断开了狭窄的连接,去掉了细小的突出部分
    fo=imopen(f,se);%直接开运算
    figure,subplot(221),imshow(fo);
    title('直接开运算');
    
    %闭运算在数学上是先膨胀再腐蚀的结果
    %闭运算的物理结果也是会平滑对象的轮廓,但是与开运算不同的是,闭运算
    %一般会将狭窄的缺口连接起来形成细长的弯口,并填充比结构元素小的洞
    fc=imclose(f,se);%直接闭运算
    subplot(222),imshow(fc);
    title('直接闭运算');
    
    foc=imclose(fo,se);%先开后闭运算
    subplot(223),imshow(foc);
    title('先开后闭运算');
    
    fco=imopen(fc,se);%先闭后开运算
    subplot(224),imshow(fco);
    title('先闭后开运算');
    %开闭运算结果如下:
    <img src="https://img-blog.csdn.net/20150511101101345?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %先膨胀再腐蚀
    fse=imdilate(f,se);%膨胀
    
    %gcf为得到当前图像的句柄,当前图像是指例如PLOT,TITLE,SURF等
    %get函数为得到物体的属性,get(0,'screensize')为返回所有物体screensize属性值
    %set函数为设置物体的属性
    figure,set(gcf,'outerposition',get(0,'screensize'));%具体目的是设置当前窗口的大小
    subplot(211),imshow(fse);
    title('使用disk(5)先膨胀后的图像');
    
    fes=imerode(fse,se);
    subplot(212),imshow(fes);
    title('使用disk(5)先膨胀再腐蚀后的图像');
    %先膨胀后腐蚀图像如下:
    <img src="https://img-blog.csdn.net/20150511101316569?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %先腐蚀再膨胀
    fse=imerode(f,se);
    figure,set(gcf,'outerposition',get(0,'screensize'))
    subplot(211),imshow(fse);
    title('使用disk(5)先腐蚀后的图像');
    
    fes=imdilate(fse,se);
    subplot(212),imshow(fes);
    title('使用disk(5)先腐蚀再膨胀后的图像');
    %先腐蚀后膨胀的图像如下:
    <img src="https://img-blog.csdn.net/20150511101331576?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% imopen imclose在指纹上的应用
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');
    se=strel('square',3);%边长为3的方形结构元素
    subplot(121),imshow(f);
    title('指纹原始图像');
    
    A=imerode(f,se);%腐蚀
    subplot(122),imshow(A);
    title('腐蚀后的指纹原始图像');
    %指纹原始图像和腐蚀后的图像结果如下:
    <img src="https://img-blog.csdn.net/20150511101349765?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    fo=imopen(f,se);
    figure,subplot(221),imshow(fo);
    title('使用square(3)开操作后的图像');
    
    fc=imclose(f,se);
    subplot(222),imshow(fc);
    title('使用square闭操作后的图像');
    
    foc=imclose(fo,se);
    subplot(223),imshow(foc);
    title('使用square(3)先开后闭操作后的图像')
    
    fco=imopen(fc,se);
    subplot(224),imshow(fco);
    title('使用square(3)先闭后开操作后的图像');
    %指纹图像开闭操作过程结果如下:
    <img src="https://img-blog.csdn.net/20150511101217629?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% bwhitmiss击中或击不中变换
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0913(a)(small-squares).tif');
    imshow(f);
    title('击中或不击中原始图像');
    %击中或不击中原始图像显示结果如下:
    <img src="https://img-blog.csdn.net/20150511101425458?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    B1=strel([0 0 0;0 1 1;0 1 0]);%击中:要求击中所有1的位置
    B2=strel([1 1 1;1 0 0;1 0 0]);%击不中,要求击不中所有1的位置
    B3=strel([0 1 0;1 1 1;0 1 0]);%击中
    B4=strel([1 0 1;0 0 0;0 0 0]);%击不中
    B5=strel([0 0 0;0 1 0;0 0 0]);%击中
    B6=strel([1 1 1;1 0 0;1 0 0]);%击不中
    
    g=imerode(f,B1)&imerode(~f,B2)%利用定义来实现击中或击不中
    figure,subplot(221),imshow(g);
    title('定义实现组1击中击不中图像');
    
    g1=bwhitmiss(f,B1,B2);
    subplot(222),imshow(g1);
    title('结构数组1击中击不中后的图像');
    
    g2=bwhitmiss(f,B3,B4);
    subplot(223),imshow(g2);
    title('结构数组2击中击不中的图像');
    
    g3=bwhitmiss(f,B5,B6);
    subplot(224),imshow(g3);
    title('结构数组3击中击不中的图像');
    %击中击不中变换后图像如下:
    <img src="https://img-blog.csdn.net/20150511101443648?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %%makelut
    clc
    clear
    
    f=inline('sum(x(:))>=3');%inline是用来定义局部函数的
    lut2=makelut(f,2)%为函数f构造一个接收2*2矩阵的查找表
    lut3=makelut(f,3)
    
    %% Conway生命游戏
    clc
    clear
    lut=makelut(@conwaylaws,3);
    bw1=  [0     0     0     0     0     0     0     0     0     0
           0     0     0     0     0     0     0     0     0     0
           0     0     0     1     0     0     1     0     0     0
           0     0     0     1     1     1     1     0     0     0
           0     0     1     0     0     0     0     1     0     0
           0     0     1     0     1     1     0     1     0     0
           0     0     1     0     0     0     0     1     0     0
           0     0     0     1     1     1     1     0     0     0
           0     0     0     0     0     0     0     0     0     0
           0     0     0     0     0     0     0     0     0     0  ];
    subplot(221),imshow(bw1,'InitialMagnification','fit');
    title('Generation 1');
    
    bw2=applylut(bw1,lut);
    subplot(222),imshow(bw2,'InitialMagnification','fit'),
    title('Generation 2');
    
    bw3=applylut(bw2,lut);
    subplot(223),imshow(bw3,'InitialMagnification','fit');
    title('Generation 3');
    
    temp=bw1;
    for i=2:100
        bw100=applylut(temp,lut);
        temp=bw100;
    end
    subplot(224),imshow(bw100,'InitialMagnification','fit')
    title('Generation 100');
    %显示Generation结果如下:
    <img src="https://img-blog.csdn.net/20150511101505488?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% getsequence
    clc
    clear
    se=strel('diamond',5)
    decomp=getsequence(se)%getsequence函数为得到分解的strel序列
    decomp(1)
    decomp(2)
    
    %% endpoints
    clc
    clear
    
    f1=imread('.\images\dipum_images_ch09\Fig0914(a)(bone-skel).tif');
    subplot(121),imshow(f1);
    title('原始形态骨架图像');
    
    g1=endpoints(f1);
    %set(gcf,'outerposition',get(0,'screensize'));%运行完后自动生成最大的窗口
    subplot(122),imshow(g1);
    title('骨架图像的端点图像');
    <img src="https://img-blog.csdn.net/20150511101524941?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %骨架头像端点检测头像如下:
    f2=imread('.\images\dipum_images_ch09\Fig0916(a)(bone).tif');
    figure,subplot(121),imshow(f2);
    title('原始骨头图像');
    
    g2=endpoints(f2);
    subplot(122),imshow(g2);
    title('骨头图像端点头像');%结果是没有端点
    %骨头头像端点检测图像如下:
    <img src="https://img-blog.csdn.net/20150511101352134?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% bwmorph组合常见形态学之细化
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');
    subplot(221),imshow(f);
    title('指纹图像细化原图');
    
    g1=bwmorph(f,'thin',1);
    subplot(222),imshow(g1);
    title('指纹图像细化原图');
    
    g2=bwmorph(f,'thin',2);
    subplot(223),imshow(g2);
    title('指纹图像细化原图');
    
    g3=bwmorph(f,'thin',Inf);
    subplot(224),imshow(g3);
    title('指纹图像细化原图');
    %指纹图像细化过程显示如下:
    <img src="https://img-blog.csdn.net/20150511101604674?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% bwmorph组合常见形态学之骨骼化
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0911(a)(noisy-fingerprint).tif');
    subplot(131),imshow(f);
    title('指纹图像骨骼化原图');
    
    fs=bwmorph(f,'skel',Inf);
    subplot(132),imshow(fs);
    title('指纹图像骨骼化');
    
    for k=1:5
        fs=fs&~endpoints(fs);
    end
    subplot(133),imshow(fs);
    title('指纹图像修剪后骨骼话');
    %指纹图像骨骼化过程显示:
    <img src="https://img-blog.csdn.net/20150511101625126?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% 使用函数bwlabel标注连通分量
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0917(a)(ten-objects).tif');
    imshow(f),title('标注连通分量原始图像');
    %其结果显示如下:
    <img src="https://img-blog.csdn.net/20150511101453130?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    [L,n]=bwlabel(f);%L为标记矩阵,n为找到连接分量的总数
    [r,c]=find(L==3);%返回第3个对象所有像素的行索引和列索引
    
    rbar=mean(r);
    cbar=mean(c);
    
    figure,imshow(f)
    hold on%保持当前图像使其不被刷新
    for k=1:n
        [r,c]=find(L==k);
        rbar=mean(r);
        cbar=mean(c);
        plot(cbar,rbar,'Marker','o','MarkerEdgeColor','k',...
             'MarkerFaceColor','k','MarkerSize',10);%这个plot函数用法不是很熟悉
        plot(cbar,rbar,'Marker','*','MarkerFaceColor','w');%其中的marker为标记
    end
    title('标记所有对象质心后的图像');
    <img src="https://img-blog.csdn.net/20150511101702129?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% 由重构做开运算
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0922(a)(book-text).tif');
    subplot(321),imshow(f);
    title('重构原始图像');
    
    fe=imerode(f,ones(51,1));%竖线腐蚀
    subplot(322),imshow(fe);
    title('使用竖线腐蚀后的结果');
    
    fo=imopen(f,ones(51,1));%竖线做开运算
    subplot(323),imshow(fo);
    title('使用竖线做开运算结果');
    
    fobr=imreconstruct(fe,f);%fe做标记
    subplot(324),imshow(fobr);
    title('使用竖线做重构开运算');
    
    ff=imfill(f,'holes');%对f进行孔洞填充
    subplot(325),imshow(ff);
    title('对f填充孔洞后的图像');
    
    fc=imclearborder(f,8);%清除边界,2维8邻接
    subplot(326),imshow(fc);
    title('对f清除边界后的图像');
    %图像重构过程显示如下:
    <img src="https://img-blog.csdn.net/20150511101524392?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% 使用顶帽变换和底帽变换
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0926(a)(rice).tif');
    subplot(221),imshow(f);
    title('顶帽底帽变换原始图像');
    
    se=strel('disk',10);%产生结构元素
    %顶帽变换是指原始图像减去其开运算的图像
    %而开运算可用于补偿不均匀的背景亮度,所以用一个大的结构元素做开运算后
    %然后用原图像减去这个开运算,就得到了背景均衡的图像,这也叫做是图像的顶帽运算
    f1=imtophat(f,se);%使用顶帽变换
    subplot(222),imshow(f1);
    title('使用顶帽变换后的图像');
    
    %底帽变换是原始图像减去其闭运算后的图像
    f2=imbothat(imcomplement(f),se);%使用底帽变换,为什么原图像要求补呢?
    %f2=imbothat(f,se);%使用底帽变换
    subplot(223),imshow(f2);
    title('使用底帽变换后的图像');
    
    %顶帽变换和底帽变换联合起来用,用于增加对比度
    f3=imsubtract(imadd(f,imtophat(f,se)),imbothat(f,se));%里面参数好像不合理?
    subplot(224),imshow(f3);
    title('使用顶帽底帽联合变换后图像');
    %顶帽底帽变换过程图像如下:
    <img src="https://img-blog.csdn.net/20150511101541786?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %%使用开运算和闭运算做形态学平滑
    %由于开运算可以除去比结构元素更小的明亮细节,闭运算可以除去比结构元素更小的暗色细节
    %所以它们经常组合起来一起进行平滑图像并去除噪声
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif');
    subplot(221),imshow(f);
    title('木钉图像原图');
    
    se=strel('disk',5);%disk其实就是一个八边形
    fo=imopen(f,se);%经过开运算
    subplot(222),imshow(f);
    title('使用半径5的disk开运算后的图像');
    
    foc=imclose(fo,se);
    subplot(223),imshow(foc);
    title('先开后闭的图像');
    
    fasf=f;
    for i=2:5
        se=strel('disk',i);
        fasf=imclose(imopen(fasf,se),se);
    end
    subplot(224),imshow(fasf);
    title('使用开闭交替滤波后图像');
    %使用开运算和闭运算做形态学平滑结果如下:
    <img src="https://img-blog.csdn.net/20150511101753750?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% 颗粒分析
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0925(a)(dowels).tif');
    
    sumpixels=zeros(1,36);
    for k=0:35
        se=strel('disk',k);
        fo=imopen(f,se);
        sumpixels(k+1)=sum(fo(:));
    end
    
    %可以看到,连续开运算之间的表面积会减少
    plot(0:35,sumpixels),xlabel('k'),ylabel('surface area');
    title('表面积和结构元素半径之间的关系');
    %其运算结果如下:   
    <img src="https://img-blog.csdn.net/20150511102014946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    figure,plot(-diff(sumpixels));%diff()函数为差分或者近似倒数,即相邻2个之间的差值
    xlabel('k'),ylabel('surface area reduction');
    title('减少的表面积和结构元素半径之间的关系');
    %其运算结果如下:
    <img src="https://img-blog.csdn.net/20150511102031341?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    %% 使用重构删除复杂图像的背景
    clc
    clear
    f=imread('.\images\dipum_images_ch09\Fig0930(a)(calculator).tif');
    subplot(221),imshow(f);
    title('灰度级重构原图像');
    
    f_obr=imreconstruct(imerode(f,ones(1,71)),f);
    subplot(222),imshow(f_obr);
    title('经开运算重构图');
    
    f_o=imopen(f,ones(1,71));
    subplot(223),imshow(f_o);
    title('经开运算后图');
    
    f_thr=imsubtract(f,f_obr);
    subplot(224),imshow(f_thr);
    title('顶帽运算重构图')
    %使用重构删除复杂图像的背景1:
    <img src="https://img-blog.csdn.net/20150511101729692?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    f_th=imsubtract(f,f_o)
    figure,subplot(221),imshow(f_th);
    title('经顶帽运算图');
    
    g_obr=imreconstruct(imerode(f_thr,ones(1,11)),f_thr);
    subplot(222),imshow(g_obr);
    title('用水平线对f_thr经开运算后重构图');
    
    g_obrd=imdilate(g_obr,ones(1,2));
    subplot(223),imshow(g_obrd);
    title('使用水平线对上图进行膨胀');
    
    f2=imreconstruct(min(g_obrd,f_thr),f_thr);
    subplot(224),imshow(f2);
    title('最后的重构结果');
    %使用重构删除复杂图像的背景2:
    <img src="https://img-blog.csdn.net/20150511101757132?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuZ2IyMDE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
    其中代码实现部分特别详细:

    http://www.cnblogs.com/tornadomeet/archive/2012/03/20/2408086.html

    Matlab 形态学图像处理(原文作者很是细心,感谢!)


    参考链接:http://blog.sina.com.cn/s/blog_a37026d60101jkqa.html

                      http://www.cnblogs.com/libing64/archive/2012/01/05/2878735.html

                      http://blog.sina.com.cn/s/blog_3d8fb3a90100rg65.html

                      http://zh.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E5%BD%A2%E6%80%81%E5%AD%A6

    展开全文
  • 中值滤波更接近于灰度图像的腐蚀和膨胀,是在一定区域内比较大小,找出中值,也就是排序后中间那个数,也就是中学的中位数,平均数用于均值滤波,中位数用于中值滤波,要是专家就可以写本书:统计学在图像处理中的二...
  • 基于Kinect 2.0深度图像的快速体积测量 ...摘要: 为了满足现实生活中对物体体积实时测量的需求,提出了一套基于Kinect 2.0深度图像处理的快速体积测量方案。首先,使用Kinect 2.0 深度传感器获得深度图...
  • 点击上方“3D视觉工坊”,选择“星标”干货第一时间送达本文由知乎作者robot L授权转载,不得擅自二次转载。原文链接:https://zhuanlan.zhihu.com/p/114...
  • 2015 CVPR Multi-Scale Context Aggregation by Dilated Convolutions Hole (Both large feature map & receptive field) hole algorithm:up-sample the original filter by a factor of the strides(rate=...
  • 真实场景的虚拟视点合成(View Synthsis)详解  上一篇博客中介绍了从拍摄...虚拟视点合成是指利用已知的参考相机拍摄的图像合成出参考相机之间的虚拟相机位置拍摄的图像,能够获取更多视角下的图片,在VR中应用...
  • 本项目使用双目相机或者手机平行移动拍摄同一场景的左、右两幅视点图像,接着使用摄像机标定后的参数进行双目图像的畸变校正和立体校正并得到矫正好的图像对,然后使用SGBM算法获取视差图并进行空洞填充进而获取深度...
  • 部分 IVOpenCV 中的图像处理 OpenCV-Python 中文教程(搬运)目录 21 OpenCV 中的轮廓 21.1 初识轮廓目标 • 理解什么是轮廓 • 学习找轮廓,绘制轮廓等 • 函数:cv2.findContours(),cv2.drawContours() ...
  • 网络分为两大部分,提出新的滑动框搜索球形投影后的“像素点”,接着使用改进的MiniNetV2网络进行分割,然后将带着标签数据的点反投影回3D点云,最后加入后处理过程,网络结构比较清晰。发布的两个不同参数大小的...
  • 3D-MiniNet: 从点云中学习2D表示以实现快速有效的3D LIDAR语义分割 西班牙Zaragoza大学的研究人员提出的最新3D点云语义分割的深度学习方法,提出新的滑动框搜索球形投影后的“像素点”,使用改进的MiniNetV2发布的两...
  • 前言: 深度图目前应用在很多场景,比如自动避障、活体检测、三维建模等等。但是,当面对光滑/明亮/透明/遥远场景时,深度图往往会存在一些无效点组成的缺失区域。本文介绍的是CVPR2018 的一项最新研究deep depth ...
  • regionprops是用来度量图像中不同区域属性的函数。 http://www.zdh1909.com/html/matlab/16292.html 表示形式是:stats=regionprops(L,properties) 测量标注矩阵L中每一个标注区域的一系列属性。L中不同...
  • 三维重构学习笔记(7):双目立体视觉梳理(细节处理,算法理解) 在上一篇博客中,遗留下来以下问题: 视差图填充,视差图格式,深度范围限制(防止出现inf出现,导致视图显示不完整),视差图转色温图(为了显示...
  • OpenGL入门教程

    2018-12-04 11:06:10
    OpenGL是渲染2D、3D矢量图形硬件的一种软件接口。本质上说,它是一个3D图形和模型库,具有高度的可移植性,并且具有非常快的渲染速度。OpenGL并不是一种语言,而是更像一个C运行时函数库。它提供了一些预包装的功能...
1 2 3 4 5 ... 12
收藏数 229
精华内容 91
关键字:

3d空洞填充 图像处理