精华内容
下载资源
问答
  • 腐蚀膨胀

    千次阅读 2018-01-28 11:29:20
    结构元素:膨胀腐蚀操作的最基本组成部分,用于测试输出图像,通常要比待处理的图像小还很多。二维平面结构元素由一个数值为0或1的矩阵组成。结构元素的原点指定了图像中需要处理的像素范围,结构元

    原理:在特殊领域运算形式——结构元素(Sturcture Element),在每个像素位置上与二值图像对应的区域进行特定的逻辑运算。运算结构是输出图像的相应像素。运算效果取决于结构元素大小内容以及逻辑运算性质。

    结构元素:膨胀和腐蚀操作的最基本组成部分,用于测试输出图像,通常要比待处理的图像小还很多。二维平面结构元素由一个数值为0或1的矩阵组成。结构元素的原点指定了图像中需要处理的像素范围,结构元素中数值为1的点决定结构元素的邻域像素在进行膨胀或腐蚀操作时是否需要参与计算。

    先来定义一些基本符号和关系。

    1.         元素

    设有一幅图象X,若点aX的区域以内,则称aX的元素,记作aX,如图6.1所示。

    2.         B包含于X

    设有两幅图象BX。对于B中所有的元素ai,都有aiX,则称B包含于(included in)X,记作BX,如图6.2所示。

    3.         B击中X

    设有两幅图象BX。若存在这样一个点,它即是B的元素,又是X的元素,则称B击中(hit)X,记作BX,如图6.3所示。

    4.         B不击中X

    设有两幅图象BX。若不存在任何一个点,它即是B的元素,又是X的元素,即BX的交集是空,则称B不击中(miss)X,记作BX=Ф;其中∩是集合运算相交的符号,Ф表示空集。如图6.4所示。

    6.1     元素

    6.2     包含

    6.3     击中

    6.4     不击中

    5.         补集

    设有一幅图象X,所有X区域以外的点构成的集合称为X的补集,记作Xc,如图6.5所示。显然,如果BX=Ф,则BX的补集内,即BXc

    6.5     补集的示意图

    6.         结构元素

    设有两幅图象BX。若X是被处理的对象,而B是用来处理X的,则称B为结构元素(structure element),又被形象地称做刷子。结构元素通常都是一些比较小的图象。

    7.         对称集

    设有一幅图象B,将B中所有元素的坐标取反,即令(xy)变成(-x-y),所有这些点构成的新的集合称为B的对称集,记作Bv,如图6.6所示。

    8.         平移

    设有一幅图象B,有一个点a(x0,y0),将B平移a后的结果是,把B中所有元素的横坐标加x0,纵坐标加y0,即令(xy)变成(x+x0y+y0),所有这些点构成的新的集合称为B的平移,记作Ba,如图6.7所示。

    6.6     对称集的示意图

    6.7     平移的示意图

    好了,介绍了这么多基本符号和关系,现在让我们应用这些符号和关系,看一下形态学的基本运算。

    6.1 腐蚀

    把结构元素B平移a后得到Ba,若Ba包含于X,我们记下这个a点,所有满足上述条件的a点组成的集合称做XB腐蚀(Erosion)的结果。用公式表示为:E(X)={a| BaX}=X B,如图6.8所示。

    6.8     腐蚀的示意图

    6.8X是被处理的对象,B是结构元素。不难知道,对于任意一个在阴影部分的点aBa包含于X,所以XB腐蚀的结果就是那个阴影部分。阴影部分在X的范围之内,且比X小,就象X被剥掉了一层似的,这就是为什么叫腐蚀的原因。

    值得注意的是,上面的B是对称的,即B的对称集Bv=B,所以XB腐蚀的结果和X Bv腐蚀的结果是一样的。如果B不是对称的,让我们看看图6.9,就会发现XB腐蚀的结果和X Bv腐蚀的结果不同。

    6.9     结构元素非对称时,腐蚀的结果不同

    6.8和图6.9都是示意图,让我们来看看实际上是怎样进行腐蚀运算的。

    在图6.10中,左边是被处理的图象X(二值图象,我们针对的是黑点),中间是结构元素B,那个标有origin的点是中心点,即当前处理元素的位置,我们在介绍模板操作时也有过类似的概念。腐蚀的方法是,拿B的中心点和X上的点一个一个地对比,如果B上的所有点都在X的范围内,则该点保留,否则将该点去掉;右边是腐蚀后的结果。可以看出,它仍在原来X的范围内,且比X包含的点要少,就象X被腐蚀掉了一层。

    6.10   腐蚀运算

    6.11为原图,图6.12为腐蚀后的结果图,能够很明显地看出腐蚀的效果。

    6.11    原图

    6.12   腐蚀后的结果图

    下面的这段程序,实现了上述的腐蚀运算,针对的都是黑色点。参数中有一个BOOL变量,为真时,表示在水平方向进行腐蚀运算,即结构元素B;否则在垂直方向上进行腐蚀运算,即结构元素B

    腐蚀源码

    膨胀

    膨胀(dilation)可以看做是腐蚀的对偶运算,其定义是:把结构元素B平移a后得到Ba,若Ba击中X,我们记下这个a点。所有满足上述条件的a点组成的集合称做XB膨胀的结果。用公式表示为:D(X)={a | BaX}=X B,如图6.13所示。图6.13X是被处理的对象,B是结构元素,不难知道,对于任意一个在阴影部分的点aBa击中X,所以XB膨胀的结果就是那个阴影部分。阴影部分包括X的所有范围,就象X膨胀了一圈似的,这就是为什么叫膨胀的原因。

    同样,如果B不是对称的,XB膨胀的结果和X Bv膨胀的结果不同。

    让我们来看看实际上是怎样进行膨胀运算的。在图6.14中,左边是被处理的图象X(二值图象,我们针对的是黑点),中间是结构元素B。膨胀的方法是,拿B的中心点和X上的点及X周围的点一个一个地对,如果B上有一个点落在X的范围内,则该点就为黑;右边是膨胀后的结果。可以看出,它包括X的所有范围,就象X膨胀了一圈似的。

    6.13   膨胀的示意图

    6.14   膨胀运算

    6.15为图6.11膨胀后的结果图,能够很明显的看出膨胀的效果。

    6.15   6.11膨胀后的结果图

    下面的这段程序,实现了上述的膨胀运算,针对的都是黑色点。参数中有一个BOOL变量,为真时,表示在水平方向进行膨胀运算,即结构元素B;否则在垂直方向上进行膨胀运算,即结构元素B

    膨胀源码

    腐蚀运算和膨胀运算互为对偶的,用公式表示为(X B)c=(Xc B),即X B腐蚀后的补集等于X的补集被B膨胀。这句话可以形象的理解为:河岸的补集为河面,河岸的腐蚀等价于河面的膨胀。你可以自己举个例子来验证一下这个关系。在有些情况下,这个对偶关系是非常有用的。例如:某个图象处理系统用硬件实现了腐蚀运算,那么不必再另搞一套膨胀的硬件,直接利用该对偶就可以实现了。

    先腐蚀后膨胀称为开(open),即OPEN(X)=D(E(X))

    让我们来看一个开运算的例子(见图6.16)

    6.16开运算

    在图16上面的两幅图中,左边是被处理的图象X(二值图象,我们针对的是黑点),右边是结构元素B,下面的两幅图中左边是腐蚀后的结果;右边是在此基础上膨胀的结果。可以看到,原图经过开运算后,一些孤立的小点被去掉了。一般来说,开运算能够去除孤立的小点,毛刺和小桥(即连通两块区域的小点),而总的位置和形状不变。这就是开运算的作用。要注意的是,如果B是非对称的,进行开运算时要用B的对称集Bv膨胀,否则,开运算的结果和原图相比要发生平移。图6.17和图6.18能够说明这个问题。

    6.17 B膨胀后,结果向左平移了

    6.18   Bv膨胀后位置不变

    6.17是用B膨胀的,可以看到,OPEN(X)向左平移了。图18是用Bv膨胀的,可以看到,总的位置和形状不变。

    6.19为图6.11经过开运算后的结果。

    6.19   6.11经过开运算后的结果

    开运算的源程序可以很容易的根据上面的腐蚀,膨胀程序得到,这里就不给出了。

    先膨胀后腐蚀称为闭(close),即CLOSE(X)=E(D(X))

    让我们来看一个闭运算的例子(见图6.20)

    6.20   闭运算

    在图6.20上面的两幅图中,左边是被处理的图象X(二值图象,我们针对的是黑点),右边是结构元素B,下面的两幅图中左边是膨胀后的结果,右边是在此基础上腐蚀的结果可以看到,原图经过闭运算后,断裂的地方被弥合了。一般来说,闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变。这就是闭运算的作用。同样要注意的是,如果B是非对称的,进行闭运算时要用B的对称集Bv膨胀,否则,闭运算的结果和原图相比要发生平移。

    6.21为图6.11经过闭运算后的结果。

    6.21   .611经过闭运算后的结果

    闭运算的源程序可以很容易的根据上面的膨胀,腐蚀程序得到,这里就不给出了。

    你大概已经猜到了,开和闭也是对偶运算,的确如此。用公式表示为(OPEN(X))c=CLOSE((Xc)),或者(CLOSE(X))c =OPEN((Xc))。即X 开运算的补集等于X的补集的闭运算,或者X 闭运算的补集等于X的补集的开运算。这句话可以这样来理解:在两个小岛之间有一座小桥,我们把岛和桥看做是处理对象X,则X的补集为大海。如果涨潮时将小桥和岛的外围淹没(相当于用尺寸比桥宽大的结构元素对X进行开运算),那么两个岛的分隔,相当于小桥两边海域的连通(Xc做闭运算)

    细化

    细化(thinning)算法有很多,我们在这里介绍的是一种简单而且效果很好的算法,用它就能够实现从文本抽取骨架的功能。我们的对象是白纸黑字的文本,但在程序中为了处理的方便,还是采用256级灰度图,不过只用到了调色板中0255两项。

    所谓细化,就是从原来的图中去掉一些点,但仍要保持原来的形状。实际上,是保持原图的骨架。所谓骨架,可以理解为图象的中轴,例如一个长方形的骨架是它的长方向上的中轴线;正方形的骨架是它的中心点;圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。文本的骨架嘛,前言中的例子显示的很明白。那么怎样判断一个点是否能去掉呢?显然,要根据它的八个相邻点的情况来判断,我们给几个例子(如图6.22所示)

    6.22   根据某点的八个相邻点的情况来判断该点是否能删除

    6.22中,(1)不能删,因为它是个内部点,我们要求的是骨架,如果连内部点也删了,骨架也会被掏空的;(2)不能删,和(1)是同样的道理;(3)可以删,这样的点不是骨架;(4)不能删,因为删掉后,原来相连的部分断开了;(5)可以删,这样的点不是骨架;(6)不能删,因为它是直线的端点,如果这样的点删了,那么最后整个直线也被删了,剩不下什么;(7)不能删,因为孤立点的骨架就是它自身。

    总结一下,有如下的判据:(1)内部点不能删除;(2)孤立点不能删除;(3)直线端点不能删除;(4)如果P是边界点,去掉P后,如果连通分量不增加,则P可以删除。

    我们可以根据上述的判据,事先做出一张表,从0255共有256个元素,每个元素要么是0,要么是1。我们根据某点(当然是要处理的黑色点了)的八个相邻点的情况查表,若表中的元素是1,则表示该点可删,否则保留。

    查表的方法是,设白点为1,黑点为0;左上方点对应一个8位数的第一位(最低位),正上方点对应第二位,右上方点对应的第三位,左邻点对应第四位,右邻点对应第五位,左下方点对应第六位,正下方点对应第七位,右下方点对应的第八位,按这样组成的8位数去查表即可。例如上面的例子中(1)对应表中的第0项,该项应该为0(2)对应37,该项应该为0(3)对应173,该项应该为1(4)对应231,该项应该为0(5)对应237,该项应该为1(6)对应254,该项应该为0(7)对应255,该项应该为0

    这张表我已经替大家做好了,可花了我不少时间呢!

    static int erasetable[256]={

                                             0,0,1,1,0,0,1,1,          1,1,0,1,1,1,0,1,

                                       1,1,0,0,1,1,1,1,             0,0,0,0,0,0,0,1,

                                              0,0,1,1,0,0,1,1,             1,1,0,1,1,1,0,1,

                                              1,1,0,0,1,1,1,1,             0,0,0,0,0,0,0,1,

                                              1,1,0,0,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,0,0,0,

                                              1,1,0,0,1,1,0,0,             1,1,0,1,1,1,0,1,

                                       0,0,0,0,0,0,0,0,             0,0,0,0,0,0,0,0,

                               0,0,1,1,0,0,1,1,             1,1,0,1,1,1,0,1,

                                              1,1,0,0,1,1,1,1,             0,0,0,0,0,0,0,1,

                                              0,0,1,1,0,0,1,1,             1,1,0,1,1,1,0,1,

                                              1,1,0,0,1,1,1,1,             0,0,0,0,0,0,0,0,

                                              1,1,0,0,1,1,0,0,             0,0,0,0,0,0,0,0,

                                    1,1,0,0,1,1,1,1,             0,0,0,0,0,0,0,0,

                                              1,1,0,0,1,1,0,0,             1,1,0,1,1,1,0,0,

                                       1,1,0,0,1,1,1,0,             1,1,0,0,1,0,0,0

                                         };

    有了这张表,算法就很简单了,每次对一行一行的将整个图象扫描一遍,对于每个点(不包括边界点),计算它在表中对应的索引,若为0,则保留,否则删除该点。如果这次扫描没有一个点被删除,则循环结束,剩下的点就是骨架点,如果有点被删除,则进行新的一轮扫描,如此反复,直到没有点被删除为止。

    实际上,该算法有一些缺陷。举个简单的例子,有一个黑色矩形,如图6.23所示。

    6.23经过细化后,我们预期的结果是一条水平直线,且位于该黑色矩形的中心。实际的结果确实是一条水平直线,但不是位于黑色矩形的中心,而是最下面的一条边。

    为什么会这样,我们来分析一下:在从上到下,从左到右的扫描过程中,我们遇到的第一个黑点就是黑色矩形的左上角点,经查表,该点可以删。下一个点是它右边的点,经查表,该点也可以删,如此下去,整个一行被删了。每一行都是同样的情况,所以都被删除了。到了最后一行时,黑色矩形已经变成了一条直线,最左边的黑点不能删,因为它是直线的端点,它右边的点也不能删,因为如果删除,直线就断了,如此下去,直到最右边的点,也不能删,因为它是直线的右端点。所以最下面的一条边保住了,但这并不是我们希望的结果。

    解决的办法是,在每一行水平扫描的过程中,先判断每一点的左右邻居,如果都是黑点,则该点不做处理。另外,如果某个黑点被删除了,那么跳过它的右邻居,处理下一个点。这样就避免了上述的问题。

    6.23  黑色矩形


    6.24  6.23细化后的结果


    解决了上面的问题,我们来看看处理后的结果,如图6.24所示。这次变成一小段竖线了,还是不对,是不是很沮丧?别着急,让我们再来分析一下:在上面的算法中,我们遇到的第一个能删除的点就是黑色矩形的左上角点;第二个是第一行的最右边的点,即黑色矩形的右上角点;第三个是第二行的最左边的点;第四个是第二行的最右边的点;……;整个图象处理这样一次后,宽度减少2。每次都是如此,直到剩最中间一列,就不能再删了。为什么会这样呢?原因是这样的处理过程只实现了水平细化,如果在每一次水平细化后,再进行一次垂直方向的细化(只要把上述过程的行列换一下),就可以了。

    这样一来,每处理一次,删除点的顺序变成:(先是水平方向扫描)第一行最左边的点;第一行最右边的点;第二行最左边的点;第二行最右边的点;……最后一行最左边的点;最后一行最右边的点;(然后是垂直方向扫描)第二列最上边的点(因为第一列最上边的点已被删除);第二列最下边的点;第三列最上边的点;第三列最下边的点;……倒数第二列最上边的点(因为倒数第一列最上边的点已被删除);倒数第二列最下边的点。我们发现,刚好剥掉了一圈,这也正是细化要做的事。实际的结果也验证了我们的想法。

    以下是源程序,黑体字部分是值得注意的地方。

    细化源码

    题外话:

    腐蚀:删除对象边界的某些像素

    膨胀:给图像中的对象边界添加像素

    算法:

    膨胀算法:用3X3的结构元素,扫描二值图像的每一个像素,用结构元素与其覆盖的二值图像做“与”运算,如果都为0,结构图像的该像素为0,否则为1.结果:使二值图像扩大一圈。

    腐蚀算法:用3X3的结构元素,扫描二值图像的每一个像素,用结构元素与其覆盖的二值图像做“与”运算,如果都为1,结构图像的该像素为1,否则为0.结果:使二值图像减小一圈。

                    </div>
    
    展开全文
  • 腐蚀膨胀DFT IDFT

    2018-05-07 20:28:31
    形态学处理,腐蚀膨胀来处理图形边缘,以及图像用傅里叶变换由空间域转换为频域,由频域转换回空间域
  • 基于OpenCV,根据腐蚀膨胀原理写的图像的腐蚀膨胀源码,没有调用现成函数,以前课程设计的结果。
  • matlab 腐蚀膨胀 代码

    2014-04-27 16:30:33
    matlab 腐蚀膨胀的代码,还挺好用的
  • 图像处理 腐蚀膨胀算法
  • matlab腐蚀膨胀源程序

    2013-04-23 16:38:15
    matlab腐蚀膨胀源程序
  • Ubuntu16.04系统,数字图像处理腐蚀膨胀操作,完整工作空间文件夹,C++文件运行,含注释,以及具有直方图输出,便于比较直观显示,还含有代码运行示意图
  • C#实现打开图片,腐蚀膨胀灰度化二值化
  • 传统的腐蚀膨胀算法会在一定层度上改变图像,为消除这一影响,在该算法基础上又设计了一种对比采样的方法,将原图像与初步处理过的图像进行对比,得到最终图像。结果表明在:此方法能够在基本不改变原图的情况下有效...
  • python实现腐蚀膨胀

    2021-02-01 16:22:21
    腐蚀膨胀是形态学的基本处理方法 开运算:先腐蚀后膨胀,可消除细小物体或断开两个区域间的细小连接处。 闭运算:先膨胀后腐蚀,填充物体内细小空洞,连接邻近物体和平滑边界。 代码: import cv2 import numpy as ...
    • 腐蚀膨胀是形态学的基本处理方法
    • 开运算:先腐蚀后膨胀,可消除细小物体或断开两个区域间的细小连接处。
    • 闭运算:先膨胀后腐蚀,填充物体内细小空洞,连接邻近物体和平滑边界。

    代码:

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def erode_demo(pic):
        #gray = cv2.cvtColor(pic,cv2.COLOR_RGB2GRAY) # 原图片类型转换为灰度图像
        #ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV)
        #cv2.imshow("binary", binary)
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 6))
        dst = cv2.erode(pic, kernel)
        return dst
    
    def dilate_demo(binary):
        #gray = cv2.cvtColor(pic,cv2.COLOR_RGB2GRAY)
        #ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV)
        #cv2.imshow("binary", binary)
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 6))
        dst = cv2.dilate(binary, kernel)
        return dst
    
    
    img = cv2.imread('1.png')
    img1 = '1.png'
    src = cv2.imread(img1, cv2.IMREAD_UNCHANGED)
    gray1 = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
    
    imageVar = cv2.Laplacian(gray1, cv2.CV_64F).var()
    
    
    a = 3
    O = float(a) * img
    # 进行数据截断,大于255 的值要截断为255
    O[0 > 255] = 255
    # 数据类型转换
    O = np.round(O)
    # uint8类型
    O = O.astype(np.uint8)
    # 显示原图和线性变换后的效果
    #cv2.imshow("I", I)
    cv2.imshow("O", O)
    
    result = erode_demo(src)
    result2 = dilate_demo(src)
    cv2.imshow('ori',img)
    cv2.imshow('result',result)
    cv2.imshow('result2',result2)
    cv2.imshow('imageVar',imageVar)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    展开全文
  • 形态学运算中腐蚀膨胀开运算和闭运算 (针对二值图而言 ) 6.1 腐蚀 腐蚀是一种消除边界点使边界向内部收缩的过程可以用来消除小且无意义的物体 腐蚀的算法 用 3x3 的结构元素扫描图像的每一个像素 用结构元素与其...
  • opencv 腐蚀膨胀

    2017-03-25 11:56:54
    腐蚀膨胀是图像形态学比较常见的处理,腐蚀一般可以用来消除噪点,分割出独立的图像元素等。  一般腐蚀操作对二值图进行处理,腐蚀操作如下图,中心位置的像素点是否与周围领域的像素点颜色一样(即是否是白色点...

    http://www.cnblogs.com/huhuuu/p/3528867.html

    腐蚀膨胀是图像形态学比较常见的处理,腐蚀一般可以用来消除噪点,分割出独立的图像元素等。

      一般腐蚀操作对二值图进行处理,腐蚀操作如下图,中心位置的像素点是否与周围领域的像素点颜色一样(即是否是白色点,即值是否为255),若一致,则保留,不一致则该点变为黑色(值即为0)

      

      opencv中的腐蚀操作:

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

      前两个参数比较熟悉,第三个参数是用于传递模板的信息,默认是(NULL),即为3*3的模板,第四个参数是迭代的次数(即该腐蚀操作做几次)

      opencv中的膨胀操作其实就是腐蚀的反操作:

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

      测试代码:

      

    复制代码
    #include "stdafx.h"
    #include "cv.h"
    #include "highgui.h"
    
    int main(){
        IplImage *img= cvLoadImage("C:/fu.jpg");//读取图片
        cvNamedWindow("Example1",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example3",CV_WINDOW_AUTOSIZE);
    
        cvShowImage("Example1",img);//在Example1显示图片
        //    cvCopy(img,temp);
        IplImage* temp=cvCreateImage( //创建一个size为image,三通道8位的彩色图
            cvGetSize(img),
            IPL_DEPTH_8U,
            3
            );
    
        cvErode(img,temp,0,1);//腐蚀
        cvShowImage("Example2",temp);
    
        cvDilate(img,temp,0,1);//膨胀
        cvShowImage("Example3",temp);
    
    
        cvWaitKey(0);//暂停用于显示图片
    
    
        cvReleaseImage(&img);//释放img所指向的内存空间并且
        cvDestroyWindow("Example1");
        cvDestroyWindow("Example2");
        cvDestroyWindow("Example3");
        
        return 0;
    }
    复制代码

      效果图:

      

     

      以上都是在模板3*3的情况下处理的,要是我们期望使用自己定义的模板时候,就需要自己做模板。

      

    CVAPI(IplConvKernel*)  cvCreateStructuringElementEx(
                int cols, int  rows, int  anchor_x, int  anchor_y,
                int shape, int* values CV_DEFAULT(NULL) );

    前两个参数是定义模板的大小,后两个参数是参考点的坐标(比如默认3*3模板的参考点坐标是2*2),第五个参数是模板的类型(可以是矩形,十字形,椭圆形,甚至是用户自己定义形状),最后一个参数是在使用自自定义形状的时候,通过value传递模板的形状。

    模板的类型:

    CVAPI(void)  cvReleaseStructuringElement( IplConvKernel** element ); //释放模板所占用的内存

     

    自定义5*5,参考点(3,3)的矩形模板的测试代码:

    复制代码
    #include "stdafx.h"
    #include "cv.h"
    #include "highgui.h"
    
    int main(){
        IplImage *img= cvLoadImage("C:/fu.jpg");//读取图片
        cvNamedWindow("Example1",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example3",CV_WINDOW_AUTOSIZE);
    
        cvShowImage("Example1",img);//在Example1显示图片
        //    cvCopy(img,temp);
        IplImage* temp=cvCreateImage( //创建一个size为image,三通道8位的彩色图
            cvGetSize(img),
            IPL_DEPTH_8U,
            3
            );
    
        IplConvKernel * myModel;
        myModel=cvCreateStructuringElementEx( //自定义5*5,参考点(3,3)的矩形模板
            5,5,2,2,CV_SHAPE_RECT
            );
    
        cvErode(img,temp,myModel,1);
        cvShowImage("Example2",temp);
    
        cvDilate(img,temp,myModel,1);
        cvShowImage("Example3",temp);
    
    
        cvWaitKey(0);//暂停用于显示图片
    
        cvReleaseStructuringElement(&myModel);
        cvReleaseImage(&img);//释放img所指向的内存空间并且
        cvDestroyWindow("Example1");
        cvDestroyWindow("Example2");
        cvDestroyWindow("Example3");
        
        return 0;
    }
    复制代码

    效果图:

    展开全文
  • 本程序是中国科学技术大学谭立湘老师GPU并行计算最后大作业的实验程序。主要内容是利用CUDA全局和共享内存实现了对图像腐蚀膨胀的优化加速。可用作学习参考。
  • 形态学腐蚀膨胀是常用的算子,本资源提供的腐蚀膨胀,不需要调用opencv
  • 本篇文章我要写的是基于的腐蚀膨胀算法实现腐蚀膨胀是形态学图像处理的基础 腐蚀在二值图像的基础上做收缩或细化操作膨胀在二值图像的基础上做加长 或变粗的操作那么什么是二值图像呢把一幅图片看做成一个二维的数组...
  • 原始代码 非调用函数 自己编写的腐蚀 膨胀 开运算 闭运算 代码
  • 图像处理入门C源码分析 图像腐蚀膨胀和细化
  • MFC腐蚀膨胀求边界

    2010-05-25 16:15:09
    在MFC中,通过灰值腐蚀膨胀的方法求形态梯度。 其中还包含其他一些功能,具体见程序
  • 本文基于《OpenCV-Python图像矩阵不扩充边界腐蚀膨胀函数处理算法探究》介绍算法的基础上,用Python 的矩阵操作模拟实现了OpenCV灰度图的腐蚀和膨胀的自定义函数,并在图像处理中,使用OpenCV的膨胀和腐蚀函数和...

    ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython

    一、引言

    在《OpenCV-Python图像矩阵不扩充边界腐蚀膨胀函数处理算法探究:https://blog.csdn.net/LaoYuanPython/article/details/109283825》介绍了OpenCV图像腐蚀膨胀具体实现算法,在本节我们将用Python模拟实现OpenCV的图像腐蚀膨胀,结合相关代码,有助于大家更加清晰的理解腐蚀膨胀以及图像卷积的具体原来和算法。

    本文是老猿关于图像腐蚀与膨胀系列博文之一,也是最后一篇,该系列包括如下博文:

    1. OpenCV-Python图像处理:腐蚀和膨胀原理及erode、dilate函数介绍:https://blog.csdn.net/LaoYuanPython/article/details/109441709
    2. OpenCV-Python腐蚀膨胀函数erode、dilate使用详解:https://blog.csdn.net/LaoYuanPython/article/details/109477130
    3. OpenCV-Python图像矩阵不扩充边界腐蚀膨胀函数处理算法探究:https://blog.csdn.net/LaoYuanPython/article/details/109283825
    4. OpenCV图像腐蚀膨胀算法的Python模拟实现:
      https://blog.csdn.net/LaoYuanPython/article/details/109407091

    二、关于实现的一些处理思路

    本次介绍的图像腐蚀膨胀算法模拟实现,有如下特殊处理:

    1. 对于边界扩充处理,只采用固定填0值的边界扩充处理模式;
    2. 对边界是否扩充的处理,程序对源矩阵的处理都采用在其上部和下部各扩充核矩阵高度减一行数据,对左边和右边各扩充核矩阵宽度减一列数据,但二者扩充数据填值不同,对于扩边模式,采用固定填值为0,对于非扩边模式,填值为np.NaN无效数字值,当运算时,对于np.NaN值不参与运算处理,这样就等于没有扩充边界,具体请参考代码中的matirxKernalOp函数;
    3. 对于卷积处理运算,运算过程是对源矩阵当前处理位置返回与卷积核矩阵相同大小的矩阵进行后续运算,然后当前位置往前移动一个位置(先按列移动,移动到矩阵最右时下移一行),具体实现请参考movKernalGetNextCoverMatrix函数;
    4. 在进行腐蚀和膨胀处理时,处理分为扩边和不扩边两种模式,分别调用OpenCV函数和自定义函数进行处理, 处理完之后对比两种模式处理结果,看结果是否相同来核实自定义函数的算法正确性,具体实现请参考kernalAndAnchorTest函数。

    三、代码

    
    
    import cv2,sys
    import numpy as np
    
    def print2DMatrix(matrix):
        """
        将2阶矩阵按照行和列方式打印输出每个元素
        :param matrix: 需要打印的矩阵
        :return: None
        """
        if len(matrix.shape)!=2:
            print("只能输出一阶矩阵的信息,传入实参不是一阶矩阵,退出!")
            return None
    
        x,y = matrix.shape
        for i in range(x):
            print(" ")
            for j in range(y):
                if matrix[i][j]==np.NaN:print(f' NAN',end=' ')
                if matrix.dtype in(np.uint8,np.uint,np.uint16,np.uint32):print(f'{matrix[i][j]:4d}',end='\t')
                else:print(f'{matrix[i][j]:4f}',end='\t')
        print("\n")
    
    def movKernalGetNextCoverMatrix(matrix,kernal,anchor):
        """
        movKernalGetNextCoverMatrix为生成器函数:
        以卷积矩阵kernal对源矩阵matrix进行卷积处理,处理时从matrix的零行零列的当前位置开始,按列和行将kernal矩阵左上角
        与matrix的当前位置重合,重合后yield返回kernal矩阵锚点anchor对应的matrix位置、matrix矩阵与kernal重合部分的matrix子矩阵,
        以方便后续继续对该子矩阵进行锚点对应位置的值计算
        由于自定义方式程序效率不高,所以处理过程中每处理一行数据就会输出处理进度
        :param matrix:源矩阵
        :param kernal:核矩阵
        :param anchor:核矩阵锚点,为(-1,-1)表示核矩阵中心为锚点
        :return:
        """
        print(f"开始处理矩阵卷积,矩阵大小:{matrix.shape}")
        matrixH,matrixW = matrix.shape
        kernalH,kernalW = kernal.shape
    
        if anchor==(-1,-1):
            anchor = (int(kernalW/2),int(kernalH/2))
        elif (anchor[0]<0) or (anchor[1]<0) or (anchor[0]>=kernalW) or (anchor[1]>=kernalH) :
            raise ValueError("matirxKernalOp函数中,锚点坐标非法")
    
        if (len(matrix.shape)!=2) and (len(kernal.shape)!=2):
            raise ValueError("源矩阵和核都必须是二阶矩阵")
        if (matrixW<=kernalW) or (matrixH<=kernalH):
            raise ValueError("核矩阵的长和宽都必须小于源矩阵的长和宽")
        rowMax = matrixH - kernalH + 1
        colMax = matrixW-kernalW+1
        for row in range(rowMax):
            inf = f"\r进度:{row*100.0/rowMax:.2f}%"
            print(inf,end='')
            #sys.stdout.flush()
            for col in range(colMax):
                yield row+anchor[1],col+anchor[0],matrix[row:row+kernalH,col:col+kernalW]
        print(f"\n矩阵卷积处理完成")
    
    
    
    def matirxKernalOp(matrix,kernal,op='+'): #anchor
        """
        使用matrix和kernal两个相同大小的矩阵进行运算,返回运算结果,具体运算由运算符决定。
        运算时,先进行两个矩阵的乘法得到一个积矩阵,当为加法时,将积矩阵所有元素相加返回,当腐蚀时,取积矩阵所有元素非0值的最小值返回,
        当膨胀时,取积矩阵所有元素非0值的最大值返回。但上述运算过程如果积矩阵元素值为np.NaN无效值时(实际上由于matrix对应位置为无效
        值导致积矩阵对应位置元素无效,这种情况是用于卷积处理时对没有采用扩充边界模式计算源矩阵边界元素位置的卷积值的特殊处理),该元素则不参与运算。
        :param matrix: 源矩阵
        :param kernal: 核矩阵
        :param anchor: 该参数已废弃
        :param op: +为加法,&为腐蚀,|为膨胀
        :return: 锚点对应矩阵元素卷积处理结果
        """
    
        if op not in '&|+':raise ValueError("matirxKernalOp函数的运算符参数错误,运算符必须为:+、&、|")
        result = 0
        if op == '&':#腐蚀
            result = 999999999
        elif op=='|':#膨胀
            result = -1
    
        if matrix.shape!=kernal.shape:
            raise ValueError("matirxKernalOp函数中,参数两个矩阵大小不同")
        if kernal.shape[1]%2==0:
            raise ValueError("matirxKernalOp函数中,参数kernal矩阵宽不为奇数")
        if kernal.shape[0]%2==0:
            raise ValueError("matirxKernalOp函数中,参数kernal矩阵高不为奇数")
        """if anchor==(-1,-1):
            anchor = (int(kernal.shape[1]/2),int(kernal.shape[0]/2))
        elif (anchor[0]<0) or (anchor[1]<0):
            raise ValueError("matirxKernalOp函数中,锚点坐标非法")"""
        k = kernal.astype(matrix.dtype) #确保乘法处理时两个矩阵类型一致
        dest = cv2.multiply(matrix, k)
    
        for x in range(kernal.shape[0]):
            for y in range(kernal.shape[1]):
                if kernal[x,y]==0:continue #核位置无有效值
                if dest[x][y]==np.NaN:continue #不扩边情况下该位置已经超出源矩阵位置所以不参与运算
                if op=='+': #如果是卷积加则有效值相加
                    result += dest[x][y]
                elif op=='&':#如果腐蚀取所有有效值的最小值
                    result = min([result,dest[x][y]])
                elif op=='|': #如果膨胀取所有有效值最大值
                    result = max([result,dest[x][y]])
        if result in [-1,999999999]:#没有找到有效单元值
            #if kernal[anchor[0],anchor[1]]:return matrix[anchor[0],anchor[1]]
            if result==-1:#如果膨胀返回0
                return 0
            else:return 255#如果腐蚀返回255
    
        return result
    
    def extendMatrixKernalOp(matrix,kernal,anchor,op='+',bExtend=True):
        """
        :param matrix: 源矩阵
        :param kernal: 核矩阵
        :param anchor: 核的锚点
        :param op: 运算符,+表示kernal对matrix进行卷积得到的各像素值相加,&为腐蚀,|为膨胀
        :param bExtend:是否扩充边界
        :return:卷积处理结果矩阵
        """
        w = kernal.shape[1]-1
        h = kernal.shape[0]-1
        mh,mw = matrix.shape[0:2]
        if bExtend:
            extendMatrix = cv2.copyMakeBorder(matrix, h, h, w, w,borderType=cv2.BORDER_CONSTANT, value=0)
        else:
            shape = (mh+2*h,mw+2*w)
            extendMatrix = np.full(shape,np.NaN)
            extendMatrix[h:mh+h,w:mw+w] = matrix #np.array(matrix,extendMatrix.dtype)
    
        nh,nw = extendMatrix.shape[0:2]
    
        if op=='&':
            dest = np.array(extendMatrix)
        else:
            dest = np.zeros(extendMatrix.shape, extendMatrix.dtype)
        for row, col, m in movKernalGetNextCoverMatrix(extendMatrix, kernal, anchor):
            #print(row,col,m.shape,extendMatrix.shape)
            dest[row, col] = matirxKernalOp(m, kernal,  op)
        return dest[h:nh-h,w:nw-w].astype(np.uint8)
    
    
    
    
    def myErode(matrix,kernal,anchor=(-1,-1),bExtend=True):
        """
        自定义腐蚀运算函数
        :param matrix: 需要进行腐蚀处理的图像源矩阵
        :param kernal: 核矩阵
        :param anchor: 锚点
        :param bExtend: 是否扩充边界
        :return: 腐蚀处理结果矩阵
        """
        return extendMatrixKernalOp(matrix,kernal,anchor,'&',bExtend)
    
    def myDilate(matrix,kernal,anchor=(-1,-1),bExtend=True):
        """
        自定义膨胀运算函数
        :param matrix: 需要进行膨胀处理的图像源矩阵
        :param kernal: 核矩阵
        :param anchor: 锚点
        :param bExtend: 是否扩充边界
        :return: 膨胀处理结果矩阵
        """
    
        return extendMatrixKernalOp(matrix,kernal,anchor,'|',bExtend)
    
    def myConvolution(matrix,kernal,anchor=(-1,-1)):
        """
        自定义卷积加运算函数
        :param matrix: 需要进行卷积加处理的图像源矩阵
        :param kernal: 核矩阵
        :param anchor: 锚点
        :return: 卷积加处理结果矩阵
        """
    
        return extendMatrixKernalOp(matrix,kernal,anchor,'+',False)
    
    def kernalAndAnchorTest(img,kernal,anchor):
        """
        测试函数,对图像进行腐蚀和膨胀,处理分为扩边和不扩边两种模式,分别调用OpenCV函数和自定义函数进行处理,
        处理完之后对比两种模式处理结果看结果是否相同。
        :param img:
        :return:
        """
        if isinstance(img, str): img = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
        print("图像矩阵前10行10列内容如下:")
        print2DMatrix(img[0:10, 0:10])
        print("核矩阵内容如下:")
        print2DMatrix(kernal)
        print('anchor=',anchor)
        imgErode = cv2.erode(img, kernal, anchor=anchor, borderType=cv2.BORDER_CONSTANT, borderValue=0)
        myImgErode = myErode(img, kernal, anchor=anchor)
        cmpMatrix = myImgErode == imgErode
        if cmpMatrix.all():
            print("myImgErode=imgErode,扩充0边界腐蚀结果图像矩阵内容如下:")
            print2DMatrix(imgErode[0:10,0:10])
            cv2.imshow('imgErodeEdge', imgErode)
    
        else:
            print("myImgErode!=imgErode,扩充0边界腐蚀结果图像矩阵内容如下:")
            print2DMatrix(imgErode[0:10,0:10])
            print('扩充0边界自定义腐蚀结果图像矩阵内容如下:')
    
            print2DMatrix(myImgErode[0:10,0:10])
    
        imgDilate = cv2.dilate(img, kernal, anchor=anchor, borderType=cv2.BORDER_CONSTANT, borderValue=0)
        myImgDilate = myDilate(img, kernal, anchor=anchor)
        cmpMatrix = imgDilate == myImgDilate
        if cmpMatrix.all():
            print("imgDilate = myImgDilate,扩充0边界膨胀结果图像矩阵内容如下:")
            print2DMatrix(imgDilate[0:10,0:10])
            cv2.imshow('imgDilateEdge', imgDilate)
        else:
            print("imgDilate != myImgDilate,扩充0边界膨胀结果图像矩阵内容如下:")
            print2DMatrix(imgDilate[0:10,0:10])
    
            print('扩充0边界自定义膨胀结果图像矩阵内容如下:')
            print2DMatrix(myImgDilate[0:10,0:10])
        ###################################
    
        imgErode = cv2.erode(img, kernal, borderType=cv2.BORDER_ISOLATED, anchor=anchor)
    
        """for bordtype in [0,1,2,4,16]:
            imgErode = cv2.erode(img, rectElement, borderType=bordtype,anchor=anchor)
            print2DMatrix(imgErode)"""
    
        myImgErode = myErode(img, kernal, anchor,False)
        imgDilate = cv2.dilate(img, kernal,borderType=cv2.BORDER_ISOLATED, anchor=anchor)
        myImgDilate = myDilate(img, kernal, anchor,False)
    
        cmpMatrix = myImgErode==imgErode
        if cmpMatrix.all():
            print("不扩边myImgErode=imgErode,不扩边腐蚀结果图像矩阵内容如下:")
            print2DMatrix(imgErode[0:10,0:10])
            cv2.imshow('imgErodeNoEdge',imgErode)
        else:
            print("不扩边myImgErode!=imgErode,不扩边腐蚀结果图像矩阵内容如下:")
            print2DMatrix(imgErode[0:10,0:10])
            print('不扩边自定义腐蚀结果图像矩阵内容如下:')
            print2DMatrix(myImgErode[0:10,0:10])
    
        cmpMatrix = imgDilate == myImgDilate
        if cmpMatrix.all():
            print("不扩边imgDilate = myImgDilate,不扩边膨胀结果图像矩阵内容如下:")
            print2DMatrix(imgDilate[0:10,0:10])
            cv2.imshow('imgDilateNoEdge', imgDilate)
        else:
            print("不扩边imgDilate != myImgDilate,不扩边膨胀结果图像矩阵内容如下:")
            print2DMatrix(imgDilate[0:10,0:10])
            print('不扩边自定义膨胀结果图像矩阵内容如下:')
            print2DMatrix(myImgDilate[0:10,0:10])
        cv2.waitKey(0)
    
    def main():
        #构建图像源矩阵
        img = np.zeros((5, 5), dtype=np.uint8)
        img[2, 2] = img[3, 3] = img[3, 4] = 1
    
        #设定锚点
        anchor = (-1, -1)
    
        #设定核矩阵
    
        kernal = np.zeros((3, 3), np.uint8)
        kernal[0, 0] = kernal[1, 1] = 1
    
        kernalAndAnchorTest(img,kernal,anchor)  # (r'F:\pic\imgs.jpg')
    
    main()
    
    

    四、运行输出

    图像矩阵前1010列内容如下:
     
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   1	   0	   0	 
       0	   0	   0	   1	   1	 
       0	   0	   0	   0	   0	
    
    核矩阵内容如下:
     
       1	   0	   0	 
       0	   1	   0	 
       0	   0	   0	
    
    anchor= (-1, -1)
    开始处理矩阵卷积,矩阵大小:(9, 9)
    进度:85.71%
    矩阵卷积处理完成
    myImgErode=imgErode,扩充0边界腐蚀结果图像矩阵内容如下:
     
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   0	   1	   0	 
       0	   0	   0	   0	   0	
    
    开始处理矩阵卷积,矩阵大小:(9, 9)
    进度:85.71%
    矩阵卷积处理完成
    imgDilate = myImgDilate,扩充0边界膨胀结果图像矩阵内容如下:
     
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   1	   0	   0	 
       0	   0	   0	   1	   1	 
       0	   0	   0	   0	   1	
    
    开始处理矩阵卷积,矩阵大小:(9, 9)
    进度:85.71%
    矩阵卷积处理完成
    开始处理矩阵卷积,矩阵大小:(9, 9)
    进度:85.71%
    矩阵卷积处理完成
    不扩边myImgErode=imgErode,不扩边腐蚀结果图像矩阵内容如下:
     
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   0	   1	   0	 
       0	   0	   0	   0	   0	
    
    不扩边imgDilate = myImgDilate,不扩边膨胀结果图像矩阵内容如下:
     
       0	   0	   0	   0	   0	 
       0	   0	   0	   0	   0	 
       0	   0	   1	   0	   0	 
       0	   0	   0	   1	   1	 
       0	   0	   0	   0	   1	
    
    
    Process finished with exit code 0
    

    矩阵打印输出时,没有判断矩阵是否超过10行10列,都是按10行10列提示的。

    五、使用真正图像进行测试

    5.1、原始图像

    在这里插入图片描述

    5.2、测试代码修改

    def main():
        #设定锚点
        anchor = (-1, -1)
    
        #设定核矩阵
        kernal = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3),anchor)
    
        kernalAndAnchorTest(r'F:\pic\imgs.jpg',kernal,anchor)
    
    

    5.3、程序运行输出

    打印输出内容如下:

    图像矩阵前1010列内容如下:
     
     251	 253	 255	 254	 134	 255	 247	 255	 255	 255	 
     178	 154	 162	 186	 166	 255	 254	 249	 255	 255	 
     255	 246	 255	 244	 240	 253	 255	 252	 255	 255	 
     245	 252	 255	 247	 255	 254	 251	 254	 255	 255	 
     253	 254	 250	 254	 255	 252	 241	 254	 255	 255	 
     255	 250	 242	 252	 252	 255	 246	 253	 255	 255	 
     251	 255	 252	 255	 248	 252	 255	 254	 255	 255	 
     253	 255	 247	 255	 250	 250	 255	 246	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	
    
    核矩阵内容如下:
     
       1	   1	   1	 
       1	   1	   1	 
       1	   1	   1	
    
    anchor= (-1, -1)
    开始处理矩阵卷积,矩阵大小:(604, 724)
    进度:99.83%
    矩阵卷积处理完成
    myImgErode=imgErode,扩充0边界腐蚀结果图像矩阵内容如下:
     
       0	   0	   0	   0	   0	   0	   0	   0	   0	   0	 
       0	 154	 154	 134	 134	 134	 247	 247	 249	 255	 
       0	 154	 154	 162	 166	 166	 249	 249	 249	 255	 
       0	 245	 244	 240	 240	 240	 241	 241	 252	 255	 
       0	 242	 242	 242	 247	 241	 241	 241	 253	 255	 
       0	 242	 242	 242	 248	 241	 241	 241	 253	 255	 
       0	 242	 242	 242	 248	 246	 246	 246	 246	 255	 
       0	 247	 247	 247	 248	 248	 246	 246	 246	 255	 
       0	 247	 247	 247	 250	 250	 246	 246	 246	 255	 
       0	 255	 255	 255	 255	 255	 255	 255	 255	 255	
    
    开始处理矩阵卷积,矩阵大小:(604, 724)
    进度:99.83%
    矩阵卷积处理完成
    imgDilate = myImgDilate,扩充0边界膨胀结果图像矩阵内容如下:
     
     253	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	
    
    开始处理矩阵卷积,矩阵大小:(604, 724)
    进度:99.83%
    矩阵卷积处理完成
    开始处理矩阵卷积,矩阵大小:(604, 724)
    进度:99.83%
    矩阵卷积处理完成
    不扩边myImgErode=imgErode,不扩边腐蚀结果图像矩阵内容如下:
     
     154	 154	 154	 134	 134	 134	 247	 247	 249	 255	 
     154	 154	 154	 134	 134	 134	 247	 247	 249	 255	 
     154	 154	 154	 162	 166	 166	 249	 249	 249	 255	 
     245	 245	 244	 240	 240	 240	 241	 241	 252	 255	 
     245	 242	 242	 242	 247	 241	 241	 241	 253	 255	 
     250	 242	 242	 242	 248	 241	 241	 241	 253	 255	 
     250	 242	 242	 242	 248	 246	 246	 246	 246	 255	 
     251	 247	 247	 247	 248	 248	 246	 246	 246	 255	 
     253	 247	 247	 247	 250	 250	 246	 246	 246	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	
    
    不扩边imgDilate = myImgDilate,不扩边膨胀结果图像矩阵内容如下:
     
     253	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255	 
     255	 255	 255	 255	 255	 255	 255	 255	 255	 255
    

    从上述输出可以看出,自定义腐蚀和膨胀函数和OpenCV对应输入的腐蚀和膨胀函数的真正处理图像也是一致的。

    5.4、图像处理效果

    扩边腐蚀图像:

    在这里插入图片描述

    不扩边腐蚀图像:

    在这里插入图片描述

    扩边膨胀图像:

    在这里插入图片描述

    不扩边膨胀图像:

    在这里插入图片描述

    六、小结

    本文基于《OpenCV-Python图像矩阵不扩充边界腐蚀膨胀函数处理算法探究:https://blog.csdn.net/LaoYuanPython/article/details/109283825》介绍算法的基础上,用Python 的矩阵操作模拟实现了OpenCV灰度图的腐蚀和膨胀的自定义函数,并在图像处理中,使用OpenCV的膨胀和腐蚀函数和自定义函数的处理结果进行了对比,来验证了自定义函数的正确性。通过自定义函数的实现,结合上节介绍的算法,有助于大家深入理解OpenCV图像腐蚀和膨胀的机制。

    不过注意,本文的实现仅基于灰度图,另外对于核全0的情况没有考虑。

    写作不易,敬请支持:

    如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!可以通过点击博文下面的一键三连按钮实现对相关文章的点赞、收藏和对博客的关注,谢谢!

    更多OpenCV-Python的介绍请参考专栏《OpenCV-Python图形图像处理 》
    专栏网址https://blog.csdn.net/laoyuanpython/category_9979286.html

    关于老猿的付费专栏

    老猿的付费专栏《使用PyQt开发图形界面Python应用 》(https://blog.csdn.net/laoyuanpython/category_9607725.html)专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》 (https://blog.csdn.net/laoyuanpython/category_10232926.html)详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏都适合有一定Python基础但无相关知识的小白读者学习。

    付费专栏文章目录:《moviepy音视频开发专栏文章目录》(https://blog.csdn.net/LaoYuanPython/article/details/107574583)、《使用PyQt开发图形界面Python应用专栏目录 》(https://blog.csdn.net/LaoYuanPython/article/details/107580932)。

    对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》(https://blog.csdn.net/laoyuanpython/category_9831699.html)从零开始学习Python。

    如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

    跟老猿学Python、学OpenCV!

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython

    展开全文
  • 腐蚀膨胀是最基本的形态学运算。腐蚀膨胀是针对白色部分(高亮部分)而言的。膨胀就是对图像高亮部分进行“领域扩张”,效果图拥有比原图更大的高亮区域;腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的...
  • 分水岭算法+腐蚀膨胀
  • 图像预处理灰度二值自适应中值滤波腐蚀膨胀matlab基础毕设
  • 很好的区域联通标记区域腐蚀膨胀降噪文献参考资料
  • 本程序是关于图像的腐蚀膨胀以获得轮廓的简短程序段
  • 图像处理 腐蚀 膨胀 细化

    千次阅读 2015-10-24 13:28:34
    图像处理 腐蚀 膨胀 细化
  • 图像处理matlab的腐蚀膨胀

    热门讨论 2009-04-03 11:51:43
    不是直接的函数调用,老师不让直接调用是根据腐蚀膨胀的原理自己编的小程序.
  • 图象腐蚀膨胀细化

    2006-02-23 09:05:59
    图象腐蚀膨胀细化
  • 基于FPGA的图像腐蚀膨胀及实现

    千次阅读 2020-04-10 10:20:38
    图像腐蚀膨胀的FPGA实现项目简述腐蚀膨胀原理图像腐蚀代码图像膨胀代码下板现象总结 项目简述 膨胀是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程。可以用来填补物体中的空洞。腐蚀是一种消除...
  • 传统的腐蚀膨胀算法会在一定程度上改变图像,为消除这一影响,在该算法基础上又设计了一种对比采样的方法,将原图与初步处理过的图像进行对比,得到最终图像。结果表明:此方法能够在基本不改变原图的情况下有效地...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,921
精华内容 5,168
关键字:

腐蚀膨胀