精华内容
下载资源
问答
  • opencv 形态学操作(python)
    千次阅读
    2022-05-06 19:15:52

    形态学操作

    形态学,即数学形态学(Mathematical Morphology),是图像处理过程中一个非常重要的研究方向。

    形态学主要从图像内提取分量信息,该分量信息通常对于表达和描绘图像的形状具有重要意义,通常是图像理解时所使用的最本质的形状特征。

    形态学操作主要包含:腐蚀、膨胀、开运算、闭运算、形态学梯度(Morphological Gradient)运算、顶帽运算(礼帽运算)、黑帽运算等操作。

    腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行结合,就可以实现开运算、闭运算、形态学梯度运算、顶帽运算、黑帽运算、击中击不中等不同形式的运算。

    腐蚀

    它能够将图像的边界点消除,使图像沿着边界向内收缩,也可以将小于指定结构体元素的部分去除。

    腐蚀用来“收缩”或者“细化”二值图像中的前景,借此实现去除噪声、元素分割等功能。

    在腐蚀过程中,通常使用一个结构元来逐个像素地扫描要被腐蚀的图像,并根据结构元和被腐蚀图像的关系来确定腐蚀结果。

    腐蚀操作等形态学操作是逐个像素地来决定值的,每次判定的点都是与结构元中心点所对应的点。

    • 如果结构元完全处于前景图像中,就将结构元中心点所对应的腐蚀结果图像中的像素点处理为前景色(白色,像素点的像素值为1)。
    • 如果结构元未完全处于前景图像中(可能部分在,也可能完全不在),就将结构元中心点对应的腐蚀结果图像中的像素点处理为背景色(黑色,像素点的像素值为0)。

    在kernel完全位于前景图象中时,将其中心点所对应的rst中像素点的值置为1;当kernel不完全位于前景图像中时,将其中心点对应的rst中像素点的值置为0。

    使用函数cv2.erode()实现腐蚀操作,其语法:

    dst = cv2.erode( src, kernel[, anchor[, iterations[, borderType[,borderValue]]]] ) 
    
    • dst是腐蚀后所输出的目标图像,该图像和原始图像具有同样的类型和大小。

    • src是需要进行腐蚀的原始图像,图像的通道数可以是任意的。但是要求图像的类型必须是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一种。

    • kernel代表腐蚀操作时所采用的结构类型。它可以自定义生成,也可以通过函数cv2.getStructuringElement()生成。

    • anchor代表element结构中锚点的位置。该值默认为(-1, -1),在核的中心位置。

    • iterations是腐蚀操作迭代的次数,该值默认为1,即只进行一次腐蚀操作。

    • borderType代表边界样式,一般采用其默认值BORDER_CONSTANT。

      image-20220506184737557

    • borderValue是边界值,一般采用默认值。

      在C++中提供了函数morphologyDefaultBorderValue()来返回腐蚀和膨胀的“魔力(magic)”边界值,Python不支持该函数。

    使用数组演示腐蚀的基本原理

    import cv2 
    import numpy as np 
    img=np.zeros((5,5), np.uint8) 
    img[1:4,1:4]=1 
    kernel = np.ones((3,1), np.uint8) 
    erosion = cv2.erode(img, kernel) 
    print("img=\n", img) 
    print("kernel=\n", kernel) 
    print("erosion=\n", erosion) 
    

    使用函数cv2.erode()完成图像腐蚀

    import cv2 
    import numpy as np 
    o=cv2.imread("erode.bmp", cv2.IMREAD_UNCHANGED) 
    kernel = np.ones((5,5), np.uint8) 
    erosion = cv2.erode(o, kernel) 
    cv2.imshow("orriginal", o) 
    cv2.imshow("erosion", erosion) 
    cv2.waitKey() 
    cv2.destroyAllWindows()
    

    处理图像是: 二值图像

    膨胀

    膨胀操作和腐蚀操作的作用是相反的,膨胀操作能对图像的边界进行扩张。膨胀操作将与当前对象(前景)接触到的背景点合并到当前对象内,从而实现将图像的边界点向外扩张。

    如果图像内两个对象的距离较近,那么在膨胀的过程中,两个对象可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。

    在膨胀过程中,也是使用一个结构元来逐个像素地扫描要被膨胀的图像,并根据结构元和待膨胀图像的关系来确定膨胀结果。

    • 如果结构元中任意一点处于前景图像中,就将膨胀结果图像中对应像素点处理为前景色。
    • 如果结构元完全处于背景图像外,就将膨胀结果图像中对应像素点处理为背景色。

    采用函数cv2.dilate()实现对图像的膨胀操作:

    dst = cv2.dilate( src, kernel[, anchor[, iterations[, borderType[, borderValue]]]]) 
    
    • dst代表膨胀后所输出的目标图像,该图像和原始图像具有同样的类型和大小。

    • src代表需要进行膨胀操作的原始图像。图像的通道数可以是任意的,但是要求图像的类型必须是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一种。

    • element代表膨胀操作所采用的结构类型。它可以自定义生成,也可以通过函数cv2.getStructuringElement()生成。

    • 参数kernel、anchor、iterations、borderType、borderValue与函数cv2.erode()内相应参数的含义一致。

    使用数组演示膨胀的基本原理

    import cv2 
    import numpy as np 
    img=np.zeros((5,5), np.uint8) 
    img[2:3,1:4]=1 
    kernel = np.ones((3,1), np.uint8) 
    dilation = cv2.dilate(img, kernel) 
    print("img=\n", img) 
    print("kernel=\n", kernel) 
    print("dilation\n", dilation) 
    

    使用函数cv2.dilate()完成图像膨胀操作

    import cv2 
    import numpy as np 
    o=cv2.imread("dilation.bmp", cv2.IMREAD_UNCHANGED) 
    kernel = np.ones((9,9), np.uint8) 
    dilation = cv2.dilate(o, kernel) 
    # dilation = cv2.dilate(o, kernel, iterations = 9) # iterations = 9对迭代次数进行控制,让膨胀重复9次
    cv2.imshow("original", o) 
    cv2.imshow("dilation", dilation) 
    cv2.waitKey() 
    cv2.destroyAllWindows() 
    
    通用形态学函数

    腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行组合,就可以实现开运算、闭运算(关运算)、形态学梯度(Morphological Gradient)运算、礼帽运算(顶帽运算)、黑帽运算、击中击不中等多种不同形式的运算。

    函数cv2.morphologyEx()来实现上述形态学运算,其语法结构如下:

    dst = cv2.morphologyEx( src, op, kernel[, anchor[, iterations[, borderType[, borderValue]]]]] )
    
    • dst代表经过形态学处理后所输出的目标图像,该图像和原始图像具有同样的类型和大小

    • src代表需要进行形态学操作的原始图像。图像的通道数可以是任意的,但是要求图像的类型必须是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一种。

    • op代表操作类型,各种形态学运算的操作规则均是将腐蚀和膨胀操作进行组合而得到的。

      image-20220506185826344

    • 参数kernel、anchor、iterations、borderType、borderValue与函数cv2.erode()内相应参数的含义一致。

    开运算

    开运算进行的操作是先将图像腐蚀,再对腐蚀的结果进行膨胀。开运算可以用于去噪、计数等。

    通过将函数cv2.morphologyEx()中操作类型参数op设置为“cv2.MORPH_OPEN”,可以实现开运算。

    opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    
    import cv2 
    import numpy as np 
    img1=cv2.imread("opening.bmp") 
    img2=cv2.imread("opening2.bmp") 
    k=np.ones((10,10), np.uint8) 
    r1=cv2.morphologyEx(img1, cv2.MORPH_OPEN, k) 
    r2=cv2.morphologyEx(img2, cv2.MORPH_OPEN, k) 
    cv2.imshow("img1", img1) 
    cv2.imshow("result1", r1) 
    cv2.imshow("img2", img2) 
    cv2.imshow("result2", r2) 
    cv2.waitKey() 
    cv2.destroyAllWindows() 
    
    闭运算

    闭运算是先膨胀、后腐蚀的运算,它有助于关闭前景物体内部的小孔,或去除物体上的小黑点,还可以将不同的前景图像进行连接。

    内部闭合的闭运算

    原始图像在经过膨胀、腐蚀后,实现了闭合内部小孔的目的

    闭运算还可以实现前景图像的连接。

    通过将函数cv2.morphologyEx()中操作类型参数op设置为“cv2.MORPH_CLOSE”,可以实现闭运算。

    closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    
    import cv2 
    import numpy as np 
    img1=cv2.imread("closing.bmp") 
    img2=cv2.imread("closing2.bmp") 
    k=np.ones((10,10), np.uint8) 
    r1=cv2.morphologyEx(img1, cv2.MORPH_CLOSE, k, iterations=3) 
    r2=cv2.morphologyEx(img2, cv2.MORPH_CLOSE, k, iterations=3) 
    cv2.imshow("img1", img1) 
    cv2.imshow("result1", r1) 
    cv2.imshow("img2", img2) 
    cv2.imshow("result2", r2) 
    cv2.waitKey() 
    cv2.destroyAllWindows()
    
    形态学梯度运算

    形态学梯度运算是用图像的膨胀图像减腐蚀图像的操作,该操作可以获取原始图像中前景图像的边缘。

    通过将函数cv2.morphologyEx()的操作类型参数op设置为“cv2.MORPH_GRADIENT”,可以实现形态学梯度运算。

    result = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
    
    import cv2 
    import numpy as np 
    o=cv2.imread("gradient.bmp", cv2.IMREAD_UNCHANGED) 
    k=np.ones((5,5), np.uint8) 
    r=cv2.morphologyEx(o, cv2.MORPH_GRADIENT, k) 
    cv2.imshow("original", o) 
    cv2.imshow("result", r) 
    cv2.waitKey() 
    cv2.destroyAllWindows() 
    
    礼帽运算

    礼帽运算是用原始图像减去其开运算图像的操作。

    礼帽运算能够获取图像的噪声信息,或者得到比原始图像的边缘更亮的边缘信息。

    通过将函数cv2.morphologyEx()中操作类型参数op设置为“cv2.MORPH_TOPHAT”,可以实现礼帽运算。

    result = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) 
    
    import cv2 
    import numpy as np 
    o1=cv2.imread("tophat.bmp", cv2.IMREAD_UNCHANGED) 
    o2=cv2.imread("lena.bmp", cv2.IMREAD_UNCHANGED) 
    k=np.ones((5,5), np.uint8) 
    r1=cv2.morphologyEx(o1, cv2.MORPH_TOPHAT, k) 
    r2=cv2.morphologyEx(o2, cv2.MORPH_TOPHAT, k) 
    cv2.imshow("original1", o1) 
    cv2.imshow("original2", o2) 
    cv2.imshow("result1", r1) 
    cv2.imshow("result2", r2) 
    cv2.waitKey() 
    cv2.destroyAllWindows() 
    
    黑帽运算

    黑帽运算是用闭运算图像减去原始图像的操作。黑帽运算能够获取图像内部的小孔,或前景色中的小黑点,或者得到比原始图像的边缘更暗的边缘部分

    通过将函数cv2.morphologyEx()中操作类型参数op设置为“cv2.MORPH_BLACKHAT”,可以实现黑帽运算。

    result = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) 
    
    import cv2 
    import numpy as np 
    o1=cv2.imread("blackhat.bmp", cv2.IMREAD_UNCHANGED) 
    o2=cv2.imread("lena.bmp", cv2.IMREAD_UNCHANGED) 
    k=np.ones((5,5), np.uint8) 
    r1=cv2.morphologyEx(o1, cv2.MORPH_BLACKHAT, k) 
    r2=cv2.morphologyEx(o2, cv2.MORPH_BLACKHAT, k) 
    cv2.imshow("original1", o1) 
    cv2.imshow("original2", o2) 
    cv2.imshow("result1", r1) 
    cv2.imshow("result2", r2) 
    cv2.waitKey() 
    cv2.destroyAllWindows() 
    
    核函数

    在进行形态学操作时,必须使用一个特定的核(结构元)。

    该核可以自定义生成,也可以通过函数cv2.getStructuringElement()构造。

    函数cv2.getStructuringElement()能够构造并返回一个用于形态学处理所使用的结构元素。

    该函数的语法格式为:

    retval = cv2.getStructuringElement( shape, ksize[, anchor])
    

    该函数用来返回一个用于形态学操作的指定大小和形状的结构元素。

    • shape代表形状类型

      image-20220506190946161

    • ksize代表结构元素的大小

    • anchor代表结构元素中的锚点位置。默认的值是(-1, -1),是形状的中心。

    • 只有十字星型的形状与锚点位置紧密相关。在其他情况下,锚点位置仅用于形态学运算结果的调整。

    除了使用该函数,用户也可以自己构建任意二进制掩码作为形态学操作中所使用的结构元素。

    使用函数cv2.getStructuringElement()生成不同结构的核。

    import cv2 
    kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)) 
    kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS,  (5,5)) 
    kernel3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,  (5,5)) 
    print("kernel1=\n", kernel1) 
    print("kernel2=\n", kernel2) 
    print("kernel3=\n", kernel3) 
    

    不同的核对形态学操作的影响:

    import cv2 
    o=cv2.imread("kernel.bmp", cv2.IMREAD_UNCHANGED) 
    kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT, (59,59)) 
    kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (59,59)) 
    kernel3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (59,59)) 
    dst1 = cv2.dilate(o, kernel1) 
    dst2 = cv2.dilate(o, kernel2) 
    dst3 = cv2.dilate(o, kernel3)#膨胀 
    cv2.imshow("orriginal", o) 
    cv2.imshow("dst1", dst1) 
    cv2.imshow("dst2", dst2) 
    cv2.imshow("dst3", dst3) 
    cv2.waitKey() 
    cv2.destroyAllWindows() 
    
    更多相关内容
  • 该文通过对各种苗木形态指标之间、苗木形态指标与造林成活及初期生长之间相互关系的回归分析,得出苗木形态指标之间存在着很强的相关性。因此,苗木形态所提供的信息大部分是重迭的。考虑到形态指标反映苗木质量的信息...
  • 数学形态学滤波学习

    千次阅读 2021-11-26 11:30:04
    对数学形态学滤波进行学习,并介绍了简单应用

    一、概述

            数学形态学是建立在集合论基础上了一门学科。具体在图像处理领域,它把形态学和数学中的集合论结合起来,描述二值或灰度图像中的形态特征,来达到图形处理的目的。形态学主要是通过结构元素和图像的相互作用对图像进行拓补变换从而获得图像结构信息,通过对结构信息的分析,获取图像更本质的形态。

            数学形态学的方法要比空间域或者频率域滤波处理图像的方法有明显的优势。例如,在图像复原处理中,数学形态学滤波器可以利用先验的几何特征信息通过形态学滤波器对图像中的噪声进行有效的滤除,同时,它又能保留图像中的一些细节信息,而且形态学的算法简单,运算速度快,对硬件的要求不高。采用数学形态学在对图像的边缘检测中也表现出了特别好的效果,相比微分运算的边缘检测算法,形态学对噪声的敏感度低,同时,所提取出来的边缘光滑度高。

            数学形态学属于图像处理中的非线性滤波方法,通过数学形态学的算法对图像进行处理的步骤如下:

    1. 提取图像的几何特征,通过所提取的几何特征来找到相应的结构模式。
    2. 根据步骤1 所找出的结构模式来选择适当的结构元素,它的选取主要针对结构元素的形状以及结构元素的大小等,结构元素选取时应当尽量从简。
    3. 为了得到具有更显著的物体特征信息的图像,利用步骤2 所选取的结构元素对图像进行相应的形态学变换。
    4. 通过对步骤3 所处理得到的图像进行各种平滑变换,通过所需要的图像特征适当的进行增加对比度处理,使目标图像变得更加清晰、明了,并且更有利于我们对相应的图像信息进行提取。

    二、二值图像形态学

            数学形态学将二值图像看成是集合, 并用结构元素进行“探测”。结构元素是一个可以在图像上平移、且尺寸比图像小的集合。

            基本的数学形态学运算是将结构元素在图像范围内平移, 同时施加交、并等基本集合运算。数学形态学的实质是通过图像集合与结构元素间的相互作用来提取有意义的图像信息, 不同的结构元素可以提取不同层面的图像信息。

            数学形态学算子的性能主要以几何方式进行刻画, 而几何描述的特点更适合视觉信息的处理和分析, 其基本思想如图:

    1、数字图像的表示及基本操作

            集合可以表示图像中的目标,以二值图像为例,我们可以用一个二维数组的集合来描述它。用(x,y)可以表示一个二维图像中灰度值为1 的点,剩下的灰度值为0,只要能确定像素点的位置,就能表示该二值图像;对于一个灰度图像,我们可以用一个三维数组的集合来描述,其中集合中每个元素为(x,y,z),x,y 表示像素点的位置,而z 表示该灰度点的灰度值;同时,对于彩色图像,可以用一个更高维的数组集合表示,该高维数组分别表示灰度值,位置,颜色特征量。下面,讨论一些集合论的基本概念。

            数学形态学最初应用在二值图像当中,可以用作图像的预处理及后续处理中。所谓二值图像是指灰度只有0 和1 两个像素值,而没有过度像素值的图像。像素的灰度值为1 的点的集合叫做“前景”,而取值为0 的点的集合为“背景” 。

             还有两个广泛应用于形态学的附加定义, 在集合中定义为如下:

           下图说明了这两个定义, (a)是将集合平移到点, (b)是集合对于原点的反射。

     2、二值图像膨胀与腐蚀

    1)二值图像膨胀

           膨胀是指一个给定的集合在二值图像中“加长”或“变粗”的操作。而该目标加长的方式和变粗的程度是由结构元素所决定的。

            膨胀的过程与卷积非常相似,结构元素的原点在目标图像上从上到下,从左到右的方式移动。在结构元素移动的过程中,结构元素与目标图像中像素值为1 的点会存在重叠,如果有存在重叠的点,那么结构元素的原点所在位置的像素会被标为1。

            假设A 为原二值图像,B为结构元素,膨胀的过程可定义为如下运算:

            A被B膨胀是所有位移的集合, 这样和A至少有一个元素是重叠的。根据这种解释, 还可以写为:

             膨胀可以通过相对结构元素的所有点遍历输入图像进行平移,然后计算其并集得到:

            该方程所定义的膨胀, 历史上叫做明克夫斯基和。可以证明膨胀满足交换律,所以膨胀还可以等效的表示为

            膨胀操作的结果实例如下图:

            而膨胀运算由于使得图像边缘的像素灰度值增加,造成图像的边缘向外扩张,会使连接较近的前景逼近甚至粘连起来,最终达到所需要的视觉效果。

    2)二值图像腐蚀

            腐蚀可以看做是膨胀的逆运算,腐蚀通常是“收缩”或“细化”了二值图像中的对象,而收缩的方式和程度也是由结构元素所决定的。

            结构元素和膨胀的结构元素选取的原则一样,一般选取比目标要的形状对称的结构元素,结构元素越小,腐蚀运算所需的时间越少。腐蚀操作也是将结构元素从左到右,从上到下遍历整
    个图像,检验图像周围的像素是否和结构元素中的点有重合,如果没有重合,则该中心点像素值被标为0

            假设A 为原图像,B 为所选取的结构元素,腐蚀的过程可以定义为如下运算:

            腐蚀除了可以用填充形式定义外, 还有一种更重要的表达形式:

            一般地, 可以得到下列性质:如果原点在结构元素的内部, 则腐蚀后的图像为输入图像的一个子集, 这就是称作“腐蚀” 的原因;如果原点在结构元素的外部, 那么腐蚀后的图像可能不在输入图像的内部。

            腐蚀操作的结果实例如下图:

     

    3)膨胀与腐蚀运算的性质

            

     

     

            其中,结合律非常重要,它表明采用一个较大结构元素的形态学运算可以由两个采用较小结构元素和的形态学运算的级联来实现。这在实际应用中对提高算法效率和硬件实现意义极大。

    3、二值图像开运算和闭运算

    1)二值图像开运算

            假设A 为原图像,B 为结构元素,那么结合A 被结构元素B 做开运算,记为:

            用结构元素对集合进行开操作就是用对腐蚀, 然后用对结果进行膨胀。为了更好地理解开运算在图像处理中的作用, 讨论下面的等价方程:

            表示了先腐蚀后膨胀所描述的开运算。开运算一般可以平滑图像的轮廓,消弱狭窄的部分,去除细小的点和毛刺,总的位置和形状不变。我们可以利用开运算的此特点来去除图像中的噪声。如

             如图,X 为原始图像,B 为结构元素,由实验结果可以看出,原图中的两块正方形链接处的点和第二块正方形上面的一个孤立的点被去除掉了,而图像的整体形状和结构并没有发生变化。

    2)二值图像闭运算

            假设A 为原图像,B 为结构元素,那么结合A 被结构元素B 做闭运算,记为:

            闭运算是先膨胀后腐蚀, 也可以利用对偶性, 即沿图像的外边缘填充或滚动结构元素, 闭运算磨光了凸向图像内部的尖角, 即对图像外部滤波。

            闭运算与开运算是一对相反的操作,它能填充图像中的狭窄和凹陷的部分,消除小洞,磨光图像中凸起的内部尖角,使图像得到一定程度的平滑。我们同样可以利用此性质对图像进行去噪。

    3)二值图像开闭运算的性质

            

    三、灰度图像形态学

    1、基本概念

            在定义灰度级形态学之前, 先介绍一下与二值形态学平移、子集和并相对应的概念。

             下面的图表示了一个信号的移位平移及相应的形态学平移。

     

            极大极小实例如下:

             反射的定义是参照集合在平面内相对原点的旋转而提出来的。

    2、灰度图像膨胀与腐蚀

    1)灰度图像膨胀

            用g对f进行灰度膨胀,公式如下:

             这一定义对灰度膨胀提供了一种重要的几何描述, 即灰度膨胀可以通过将结构元的原点平移到与信号重合, 然后计算信号上的每一点与结构元对应各点和的最大值得到。

            因此,通常对灰度图像进行膨胀处理后,会造成图像中像素值本身较大的部分得到进一步扩张,会得到双重效果:

    1. 如果所有结构元素的值都为正,则得到的处理图像亮度会高于原始图像的亮度;
    2. 结构元素的形状和大小以及相关的值会使图像中的细节部分受到一定的影响:减少,或者有可能消失。

    2)灰度图像腐蚀

              用g对f进行灰度腐蚀,公式如下:

             通常对灰度图像进行腐蚀处理后,会使图像中像素值本身较小的部分得到进一步的缩小,会得到双重效果:

    1. 如果所有结构元素的值都为正,则得到的处理后图像会低于原始图像的亮度;
    2. 在输入图像中,如果亮的细节的面积小于结构元素的大小,则亮的部分将会削弱。削弱的亮度取决于结构元素的形状和幅值以及亮度区域周围的灰度值。

    3)膨胀与腐蚀运算的性质

    3、灰度图像开闭运算

            通常情况下,开运算一般能够平滑图像的轮廓,去除较小的亮点(相对于结构元素而言),消减图像中狭窄的部分,同时保留图像中灰度值较大的部分。腐蚀操作先将图像中较小的亮的部分去除,使图像变暗,而膨胀操作能够增加图像的亮度并且不再引入由腐蚀所去除的部分。

            灰度闭运算的结果基本上与灰度开运算相反,它通常能够去除图像中较小的暗点(相对于结构元素而言),填补狭窄以及凹陷的部分,消除小洞,使图像得到平滑,并且保留图像原有的亮度特征。膨胀操作能够将图像中较小的暗部分去除,使图像变亮,而腐蚀操作能调暗图像,并且不再引入由膨胀所去除的部分。

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

    千次阅读 2021-07-29 09:19:11
    形态学的操作主要是去除影响图像形状和信息的噪声。形态学运算在图像分割中非常有用,可以得到无噪声的二值图像。 基本的形态操作是侵蚀和膨胀。下面对这两种操作进行说明: 膨胀 在放大操作中,如果物体是白色的,...

    形态学方法

    当图像经过预处理进行增强和阈值等性能操作时,图像就有可能得到一些噪声。从而导致图像中存在像素信息不平衡的问题。

    形态学的操作主要是去除影响图像形状和信息的噪声。形态学运算在图像分割中非常有用,可以得到无噪声的二值图像。

    基本的形态操作是侵蚀和膨胀。下面对这两种操作进行说明:

    膨胀

    在放大操作中,如果物体是白色的,那么白色像素周围的像素就会增大。它增加的区域取决于物体像素的形状。膨胀过程增加了对象的像素数,减少了非对象的像素数。

    具有不同内核大小和迭代的膨胀的Python代码

    import numpy as np
    import imutils
    import cv2#reading the input image
    img = cv2.imread('thumb.png') #reads the image
    
    #cv2.imwrite('Input_image.jpg',image)
    
    #Resizing the image
    scale_percent = 70
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
      
    # resize the input image
    image = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
    
    kernel = np.ones((1,1), dtype = "uint8")/9
    dilation = cv2.dilate(image,kernel,iterations = 1)
    cv2.imwrite('dilation.jpg', dilation)
    
    kernel = np.ones((2,2), dtype = "uint8")/9
    dilation = cv2.dilate(image,kernel,iterations = 1)
    cv2.imwrite('dilation.jpg', dilation)
    
    kernel = np.ones((2,2), dtype = "uint8")/9
    dilation = cv2.dilate(image,kernel,iterations = 3)
    cv2.imwrite('dilation.jpg', dilation)
    
    kernel = np.ones((2,2), dtype = "uint8")/9
    dilation = cv2.dilate(image,kernel,iterations = 5)
    cv2.imwrite('dilation.jpg', dilation)
    
    kernel = np.ones((3,3), dtype = "uint8")/9
    dilation = cv2.dilate(image,kernel,iterations = 2)
    cv2.imwrite('dilation.jpg', dilation)
    

    侵蚀

    侵蚀函数正好与膨胀功函数相反。侵蚀作用使物体体积变小。侵蚀过程增加了非目标像素,减少了目标像素。

    具有不同内核大小和迭代的侵蚀的Python代码

    import numpy as np
    import imutils
    import cv2
    
    #reading the input image
    img = cv2.imread('thumb.png')
    #cv2.imwrite('Input_image.jpg',image)
    
    #Resizing the image
    scale_percent = 70
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
    
    # resize the input image
    image = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
    
    kernel = np.ones((1,1), dtype = "uint8")/9
    erosion = cv2.erode(image, kernel, iterations = 1)
    cv2.imwrite('erosion.jpg', erosion)
    
    kernel = np.ones((2,2), dtype = "uint8")/9
    erosion = cv2.erode(image, kernel, iterations = 2)
    cv2.imwrite('erosion.jpg', erosion)
    
    kernel = np.ones((2,2), dtype = "uint8")/9
    erosion = cv2.erode(image, kernel, iterations = 3)
    cv2.imwrite('erosion.jpg', erosion)
    
    kernel = np.ones((2,2), dtype = "uint8")/9
    erosion = cv2.erode(image, kernel, iterations = 5)
    cv2.imwrite('erosion.jpg', erosion)
    
    kernel = np.ones((5,5), dtype = "uint8")/9
    erosion = cv2.erode(image, kernel, iterations = 2)
    cv2.imwrite('erosion.jpg', erosion)
    

    开操作

    此方法可用于从图像中去除噪声。 该方法的工作功能是先腐蚀再膨胀,以保持物体像素的原始性,去除背景中的小噪声。

    import numpy as np
    import imutils
    import cv2
    #reading the input image
    img = cv2.imread('11.png')
    
    kernel = np.ones((5,5), dtype = "uint8")/9
    opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    cv2.imwrite('opening.jpg', opening)
    

    闭操作

    此方法可用于从图像中去除噪声。 这种方法的工作功能是先膨胀再腐蚀,去除内部的小噪声。

    import numpy as np
    import imutils
    import cv2
    #reading the input image
    img = cv2.imread('thumb.png')
    
    kernel = np.ones((9,9), dtype = "uint8")/9
    closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    cv2.imwrite('closing.jpg', closing)
    

    形态学梯度

    这种方法是膨胀图与腐蚀图之差。

    import numpy as np
    import imutils
    import cv2
    
    #reading the input image
    img = cv2.imread('g1.png')
    
    kernel = np.ones((6,6), dtype = "uint8")/9
    gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
    cv2.imwrite('gradient.jpg', gradient)
    

    总结

    这些操作是处理二进制图像的一种非常简单的方法,也是图像处理应用程序中预处理的一部分。

    作者:Amit Chauhan

    展开全文
  • 图像处理——形态

    千次阅读 2017-06-05 15:53:00
    形态学一般是使用二值图像,进行边界提取,骨架提取,孔洞填充,角点提取,图像重建。 基本的算法:膨胀腐蚀,开操作,闭操作,击中击不中变换 几种算法进行组合,就可以实现一些非常复杂的功能,而且逻辑严密...
    形态学一般是使用二值图像,进行边界提取,骨架提取,孔洞填充,角点提取,图像重建。

    基本的算法:膨胀腐蚀,开操作,闭操作,击中击不中变换

    几种算法进行组合,就可以实现一些非常复杂的功能,而且逻辑严密。

    这里给出形态学的一般原理,以及用形态学进行边界提取,角点提取好骨架提取的原代码

    一    引言
            数学形态学是一门建立在集论基础上的学科,是几何形态学分析和描述的有力工具。数学形态学的历史可回溯到19世纪。1964年法国的Matheron和Serra在积分几何的研究成果上,将数学形态学引入图像处理领域,并研制了基于数学形态学的图像处理系统。1982年出版的专著《Image Analysis and Mathematical Morphology》是数学形态学发展的重要里程碑,表明数学形态学在理论上趋于完备及应用上不断深入。数学形态学蓬勃发展,由于其并行快速,易于硬件实现,已引起了人们的广泛关注。目前,数学形态学已在计算机视觉、信号处理与图像分析、模式识别、计算方法与数据处理等方面得到了极为广泛的应用。
            数学形态学可以用来解决抑制噪声、特征提取、边缘检测、图像分割、形状识别、纹理分析、图像恢复与重建、图像压缩等图像处理问题。该文将主要对数学形态学的基本理论及其在图像处理中的应用进行综述。

    二    数学形态学的定义和分类
            数学形态学是以形态结构元素为基础对图像进行分析的数学工具。它的基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的。数学形态学的应用可以简化图像数据,保持它们基本的形状特征,并除去不相干的结构。数学形态学的基本运算有4个:膨胀、腐蚀、开启和闭合。它们在二值图像中和灰度图像中各有特点。基于这些基本运算还可以推导和组合成各种数学形态学实用算法。

    (1)二值形态学
            数学形态学中二值图像的形态变换是一种针对集合的处理过程。其形态算子的实质是表达物体或形状的集合与结构元素间的相互作用,结构元素的形状就决定了这种运算所提取的信号的形状信息。形态学图像处理是在图像中移动一个结构元素,然后将结构元素与下面的二值图像进行交、并等集合运算。
            基本的形态运算是腐蚀和膨胀。
            在形态学中,结构元素是最重要最基本的概念。结构元素在形态变换中的作用相当于信号处理中的“滤波窗口”。用B(x)代表结构元素,对工作空间E中的每一点x,腐蚀和膨胀的定义为:
           
            用B(x)对E进行腐蚀的结果就是把结构元素B平移后使B包含于E的所有点构成的集合。用B(x)对E进行膨胀的结果就是把结构元素B平移后使B与E的交集非空的点构成的集合。先腐蚀后膨胀的过程称为开运算。它具有消除细小物体,在纤细处分离物体和平滑较大物体边界的作用。先膨胀后腐蚀的过程称为闭运算。它具有填充物体内细小空洞,连接邻近物体和平滑边界的作用。
            可见,二值形态膨胀与腐蚀可转化为集合的逻辑运算,算法简单,适于并行处理,且易于硬件实现,适于对二值图像进行图像分割、细化、抽取骨架、边缘提取、形状分析。但是,在不同的应用场合,结构元素的选择及其相应的处理算法是不一样的,对不同的目标图像需设计不同的结构元素和不同的处理算法。结构元素的大小、形状选择合适与否,将直接影响图像的形态运算结果。因此,很多学者结合自己的应用实际,提出了一系列的改进算法。如梁勇提出的用多方位形态学结构元素进行边缘检测算法既具有较好的边缘定位能力,又具有很好的噪声平滑能力。许超提出的以最短线段结构元素构造准圆结构元素或序列结构元素生成准圆结构元素相结合的设计方法,用于骨架的提取,可大大减少形态运算的计算量,并可同时满足尺度、平移及旋转相容性,适于对形状进行分析和描述。

    (2)灰度数学形态学
            二值数学形态学可方便地推广到灰度图像空间。只是灰度数学形态学的运算对象不是集合,而是图像函数。以下设f(x,y)是输入图像,b(x,y)是结构元素。用结构元素b对输入图像y进行膨胀和腐蚀运算分别定义为:

    对灰度图像的膨胀(或腐蚀)操作有两类效果:
    (1)如果结构元素的值都为正的,则输出图像会比输入图像亮(或暗);
    (2)根据输入图像中暗(或亮)细节的灰度值以及它们的形状相对于结构元素的关系,它们在运算中或被消减或被除掉。灰度数学形态学中开启和闭合运算的定义与在二值数学形态学中的定义一致。用b对f进行开启和闭合运算的定义为:

    (3)模糊数学形态学
            将模糊集合理论用于数学形态学就形成了模糊形态学。模糊算子的定义不同,相应的模糊形态运算的定义也不相同。在此,选用Shinba的定义方法。模糊性由结构元素对原图像的适应程度来确定。用有界支撑的模糊结构元素对模糊图像的腐蚀和膨胀运算按它们的隶属函数定义为:

     

    其中,x,y∈Z2代表空间坐标,ua,ub分别代表图像和结构元素的隶属函数。从(7),(8)式的结果可知,经模糊形态腐蚀膨胀运算后的隶属函数均落在[0,1]的区间内。模糊形态学是传统数学形态学从二值逻辑向模糊逻辑的推广,与传统数学形态学有相似的计算结果和相似的代数特性。模糊形态学重点研究n维空间目标物体的形状特征和形态变换,主要应用于图像处理领域,如模糊增强、模糊边缘检测、模糊分割等。

     

    三 数学形态学在图像处理中的主要应用

    近年来,数学形态学在图像处理方面得到了日益广泛的应用。下面主要就数学形态学在边缘检测、图像分割、图像细化以及噪声滤除等方面的应用做简要介绍。

    (1)       边缘检测

    边缘检测是大多数图像处理必不可少的一步,提供了物体形状的重要信息。对于二值图像,边缘检测是求一个集合A的边界,记为B(A):

     

    对于灰度图像,边缘检测是求一幅图像的形态学梯度,记为g:

    数学形态学运算用于边缘检测,存在着结构元素单一的问题。它对与结构元素同方向的边缘敏感,而与其不同方向的边缘(或噪声)会被平滑掉,即边缘的方向可以由结构元素的形状确定。但如果采用对称的结构元素,又会减弱对图像边缘的方向敏感性。所以在边缘检测中,可以考虑用多方位的形态结构元素,运用不同的结构元素的逻辑组合检测出不同方向的边缘。

    梁勇等人构造了8个方向的多方位形态学结构元素,应用基本形态运算,得到8个方向的边缘检测结果,再把这些结果进行归一化运算、加权求和,得到最终的图像边缘。该算法在保持图像细节特征和平滑边缘等方面,取得了较好的效果。

    边缘检测源代码:

    [cpp]  view plain  copy
    1. /******************************************************************** 
    2. 形态学基本操作采用二值图像  
    3. ***********************************************************************/  
    4. #include<cv.h>  
    5. #include <highgui.h>  
    6. int main(){  
    7.     IplImage * image,*image2,*image3;  
    8.     image = cvLoadImage("E:\\image\\mapleleaf.tif", 0);  
    9.     cvNamedWindow("image",1);  
    10.     cvShowImage("image",image);  
    11.       
    12.   
    13.     /*边界提取*/  
    14.    image2 = cvCreateImage(cvSize(image->width, image->height),image->depth ,1);  
    15.     image3 = cvCreateImage(cvSize(image->width, image->height),image->depth ,1);  
    16.    int  i , j ;  
    17.    int left,right, up , down;  
    18.    int n = 2;//窗口大小为5*5  
    19.    int r,s,flag;  
    20.    unsigned char * ptr, *dst;  
    21.    for (i = 0 ; i< image->height; i++)  
    22.    {  
    23.        for (j = 0 ; j< image->width; j++)  
    24.        {  
    25.            //窗口设定  
    26.            left = j - n;  
    27.            right = j +n;  
    28.            up = i -n;  
    29.            down = i+n;  
    30.            //窗口出界处理  
    31.            if(left< 0){left = 0;}  
    32.            if(right >= image->width){right = image->width-1;}  
    33.            if(up< 0){up =0;}  
    34.            if(down >= image->height){down = image->height -1;}  
    35.   
    36.            //腐蚀处理  
    37.            dst = (unsigned char *)image2->imageData + image2->widthStep*i + j;  
    38.            flag = 1;  
    39.            for (r = up;r <= down;r++)  
    40.            {  
    41.                for (s = left ; s<= right; s++)  
    42.                {  
    43.                   ptr = (unsigned char *)image->imageData + r*image->widthStep + s;  
    44.   
    45.                   if(*ptr != 255){  
    46.                         flag = 0;  
    47.                   }  
    48.                }  
    49.            }  
    50.            if (flag == 1)  
    51.            {  
    52.                *dst = 255;  
    53.            }  
    54.            else{  
    55.                *dst = 0;  
    56.            }  
    57.   
    58.        }  
    59.    }  
    60.    cvSub(image,image2,image3,0);  
    61.    cvNamedWindow("image3",1);  
    62.    cvShowImage("image3",image3);  
    63.    cvSaveImage("mapleleafboard.bmp", image3);  
    64.    cvWaitKey(0);  
    65.     cvReleaseImage(&image);  
    66.     cvReleaseImage(&image2);  
    67.     cvReleaseImage(&image3);  
    68.     cvDestroyAllWindows();  
    69.     return 0 ;  
    70. }  
    原图:

    

    边界提取:


     

    (2)       图像分割

    基于数学形态学的图像分割算法是利用数学形态学变换,把复杂目标X分割成一系列互不相交的简单子集X1,X2,…,XN,即:

    对目标X的分割过程可按下面的方法完成:首先求出X的最大内接“圆”X1,然后将X1从X中减去,再求X-X1的最大内接“圆”X2,…,依此类推,直到最后得到的集合为空集为止。下面以二值图像为例,介绍用数学形态学方法求解子集X1,X2,…,XN的过程。

    设B为结构元素,B可以是圆、三角形、正方形等简单的几何基元,那么“简单”形状集合Xi可以用下面的公式来定义:

    式中ni为一整数,用上式定义Xi分割目标,有时会产生分割过程不唯一的现象。为此可采用下面公式来定义简单集合Xi

    其中Li为一个点或一条线,当Li为点时,则与(12)式定义等价。(13)式定义的简单形状Xi可由niB沿线Li移动而产生。即将“产生器”niB的中心沿“脊骨”Li移动产生。如果niB为圆,则得到的Xi称Blum带。它具有一些特殊的性质,如Xi的边界是光滑的,Xi的最大圆与其边界相切,Xi的脊骨与产生器都是唯一的等等。

    有了简单形状集合Xi的定义,则目标X可按下面方法分割。首先按式(14)求出X的最大内切结构元素Xi

    数学形态学用于图像分割的缺点是对边界噪声敏感。为了改善这一问题,刘志敏等人提出了基于图像最大内切圆的数学形态学形状描述图像分割算法和基于目标最小闭包结构元素的数学形态学形状描述图像分割算法,并使用该算法对二值图像进行了分割,取得了较好的效果。邓世伟等人提出一种基于数学形态学的深度图像分割算法。作者首先利用形态学算子获得分别含有阶跃边缘与屋脊边缘的凸脊和凹谷图像,然后利用控制区域生长过程得到最终的分割结果。与传统方法相比,该方法速度快,抗噪性能好。

     

    (3)       形态骨架提取

    形态骨架描述了物体的形状和方向信息。它具有平移不变性、逆扩张性和等幂性等性质,是一种有效的形状描述方法。二值图像A的形态骨架可以通过选定合适的结构元素B,对A进行连续腐蚀和开启运算来求取,设S(A)代表A的骨架,定义为:

    蒋刚毅等人运用数学形态学方法,对交通标志的内核形状提取形态骨架函数,将其作为用于模式匹配的形状特征。A的形态骨架函数SKF(A)表示为:

    SKF(X)中值较大的点对应大的n,并代表了形态骨架的主要成分,即表达了形状的主体结构;而SKF(X)中值较小的点对应小的n,是形态骨架的细节成分,与形状的边缘信息相联系。

    形态骨架函数完整简洁地表达了形态骨架的所有信息,因此,根据形态骨架函数的模式匹配能够实现对不同形状物体的识别。算法具有位移不变性,因而使识别更具稳健性。

     骨架提取原代码:

    [cpp]  view plain  copy
    1. /************************************************************************/  
    2. /* 骨架提取*/  
    3. /************************************************************************/  
    4. #include<cv.h>  
    5. #include <highgui.h>  
    6. int main(){  
    7.     IplImage* image = cvLoadImage("E:\\image\\bone.tif",0);  
    8.     cvNamedWindow("image",1);  
    9.     cvNamedWindow("image2",1);  
    10.     cvNamedWindow("image3",1);  
    11.     cvNamedWindow("image4",1);  
    12.     cvNamedWindow("image5",1);  
    13.     cvNamedWindow("image6",1);  
    14.   
    15.     cvNamedWindow("result",1);  
    16.     cvShowImage("image", image);  
    17.     //cvWaitKey(0);  
    18.     //当前图片image2  当前被腐蚀后的图片image3 被腐蚀开操作之后的图片 image5   
    19.     //image4 作为开操作的中间值 作差后的图片image6  并之后的图片result    
    20.     IplImage *image2, *image3 , *image4, *image5,*image6,*result;  
    21.     image2 = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);  
    22.     image3 = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);  
    23.     image5 = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);  
    24.     image4 = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);  
    25.     image6 = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);  
    26.     result = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);  
    27.       
    28.     //循环标志 flag  
    29.     bool flag = true;  
    30.     //腐蚀判断标志 flag2  
    31.     bool flag2  = true;  
    32.     int i,j,r,s;  
    33.     unsigned char * ptr,*dst;  
    34.     unsigned char B[9] = {255 ,255,255,255,255,255,255,255,255};  
    35.     //对result进行赋值 全部为0   
    36.     for (i = 0 ; i< result->height; i++)  
    37.     {  
    38.         for (j = 0 ; j< result->width ; j++)  
    39.         {  
    40.             dst = (unsigned char *)(result->imageData + result->widthStep *i +j);  
    41.             *dst = 0;  
    42.         }  
    43.     }  
    44.     image2 = cvCloneImage(image);  
    45.     cvShowImage("image2", image2);  
    46.     //cvWaitKey(0);  
    47.     while (flag)  
    48.     {  
    49.         //flag = false;  
    50.         cvShowImage("image2",image2);  
    51.         //进行腐蚀操作,开环操作 作差 并  
    52.         for (i = 0 ; i< image3->height; i++)  
    53.         {  
    54.             for (j = 0 ; j< image3->width ; j++)  
    55.             {  
    56.             dst =  (unsigned char *)(image3->imageData + i*image3->widthStep + j);  
    57.                 if ((i == 0 )|| (j == 0) ||( i == image->height -1 ) || (j == image->width -1 ))  
    58.                 {  
    59.                     *dst = 0;  
    60.                     //break;  
    61.                 }  
    62.                 else{  
    63.                 flag2 = true;  
    64.                 for (r = i-1 ; r<= i+1 ; r++)  
    65.                 {  
    66.                     for (s = j -1 ; s<= j+1 ; s++)  
    67.                     {  
    68.                         ptr  = (unsigned char *)(image2->imageData + r*image2->widthStep + j);  
    69.                         if(*ptr != 255){  
    70.                             flag2 =false;  
    71.                         }  
    72.                     }  
    73.                 }  
    74.                   
    75.                 if (flag2)  
    76.                 {  
    77.                     *dst = 255;  
    78.                 }  
    79.                 else {*dst = 0;}  
    80.                 }  
    81.             }  
    82.         }  
    83.         cvShowImage("image3",image3);  
    84.           
    85.   
    86.     //开操作 先腐蚀 后膨胀   
    87.         for (i = 0 ; i< image4->height; i++)  
    88.         {  
    89.             for (j = 0 ; j< image4->width ; j++)  
    90.             {  
    91.                 dst =  (unsigned char *)(image4->imageData + i*image4->widthStep + j);  
    92.                 if ((i == 0 )|| (j == 0) ||( i == image->height -1 ) || (j == image->width -1 ))  
    93.                 {  
    94.                     *dst = 0;  
    95.                     //break;  
    96.                 }  
    97.                 else{  
    98.                 flag2 = true;  
    99.                 for (r = i-1 ; r<=  i+1 ; r++)  
    100.                 {  
    101.                     for (s = j -1 ; s<= j+1 ; s++)  
    102.                     {  
    103.                         ptr  = (unsigned char *)(image3->imageData + r*image3->widthStep + s);  
    104.                         if(*ptr != 255){  
    105.                             flag2 =false;  
    106.                         }  
    107.                     }  
    108.                 }  
    109.                   
    110.                 if (flag2)  
    111.                 {  
    112.                     *dst = 255;  
    113.                 }  
    114.                 else {*dst = 0;}  
    115.                 }  
    116.             }  
    117.         }  
    118.         cvShowImage("image4",image4);  
    119.         //膨胀操作  
    120.         for (i = 0 ; i< image5->height; i++)  
    121.         {  
    122.             for (j = 0 ; j< image5->width ; j++)  
    123.             {  
    124.                 dst =  (unsigned char *)(image5->imageData + i*image5->widthStep + j);  
    125.                 if ((i == 0 )|| (j == 0) ||( i == image5->height -1 ) || (j == image5->width -1 ))  
    126.                 {  
    127.                     *dst = 0;  
    128.                     //break;  
    129.                 }  
    130.                 else{  
    131.                 flag2 = false;  
    132.                 for (r = i-1 ; r<= i+1 ; r++)  
    133.                 {  
    134.                     for (s = j -1 ; s<= j+1 ; s++)  
    135.                     {  
    136.                         ptr  = (unsigned char *)(image4->imageData + r*image4->widthStep + s);  
    137.                         if(*ptr == 255){  
    138.                             flag2 = true;  
    139.                         }  
    140.                     }  
    141.                 }  
    142.                   
    143.                 if (flag2)  
    144.                 {  
    145.                     *dst = 255;  
    146.                 }  
    147.                 else {*dst = 0;}  
    148.                 }  
    149.             }  
    150.         }  
    151.             cvShowImage("image5",image5);  
    152.   
    153.   
    154.      //作差  
    155.       cvSub(image3,image5,image6,0);  
    156.       //并运算  
    157.       for (i = 0 ; i< result->height; i++)  
    158.       {  
    159.           for (j = 0 ; j< result->width ; j++)  
    160.           {  
    161.               dst = (unsigned char *)(result->imageData + result->widthStep *i +j);  
    162.               ptr = (unsigned char *)(image6->imageData + image6->widthStep *i +j);  
    163.               if (*ptr == 255)  
    164.               {  
    165.   
    166.                   *dst = 255;  
    167.               }  
    168.           }  
    169.       }  
    170.         cvShowImage("image6",image6);  
    171.       //将腐蚀后的图像复制给当前图像image2  
    172.      image2 =  cvCloneImage(image3);  
    173.   
    174.       //循环标志判定  
    175.       flag = false;  
    176.       for (i = 0 ; i< image2->height; i++)  
    177.       {  
    178.           for (j = 0 ; j< image2->width ; j++)  
    179.           {  
    180.                
    181.               ptr = (unsigned char *)(image2->imageData + image2->widthStep *i +j);  
    182.               if (*ptr == 255)  
    183.               {  
    184.                   flag = true;  
    185.               }  
    186.           }  
    187.       }  
    188.       cvShowImage("result", result);  
    189.       cvWaitKey(40);  
    190.     }  
    191.       
    192.     cvShowImage("image2", image2);  
    193.     cvShowImage("image3", image3);  
    194.     //cvShowImage("image4", image4);  
    195.     //cvShowImage("image5", image5);  
    196.     //cvShowImage("image6", image6);  
    197.     cvShowImage("result",result);  
    198.     cvSaveImage("E:\\image\\bonegujia.bmp",result);  
    199.     cvWaitKey(0);  
    200.     cvReleaseImage(&image);  
    201.     cvDestroyAllWindows();  
    202.     return 0;  
    203. }  

    原图:


    提取的骨架:


    DNA原图:


    骨架:


    形态学算法对于提取交叉的物体,会产生断裂,一般会在提取之后紧跟连接操作。




    角点提取源代码:采用击中击不中变换

    [cpp]  view plain  copy
    1. /******************************************************************** 
    2. 形态学基本操作采用二值图像 形态学方法在边界获取和形状检测中有很多应用 寻找角点 
    3. ***********************************************************************/  
    4. #include<cv.h>  
    5. #include <highgui.h>  
    6. int main(){  
    7.     IplImage * image,*image2,*image3,*image4,*result;  
    8.     image = cvLoadImage("E:\\image\\jiaodian.bmp", 0);  
    9.     cvNamedWindow("image",1);  
    10.     cvShowImage("image",image);  
    11.   
    12.   
    13.     /*击中击不中变换 寻找角点*/   
    14.     /************************************************************************/  
    15.     /*   最终结果为(79, 85 )和 (129 ,134)两个符合要求的角点  在结果图像中可以看到两个白点*/  
    16.     /************************************************************************/  
    17.     image2 = cvCreateImage(cvSize(image->width, image->height),image->depth ,1);  
    18.     image3 = cvCreateImage(cvSize(image->width, image->height),image->depth ,1);  
    19.     image4 = cvCreateImage(cvSize(image->width, image->height),image->depth ,1);  
    20.     result = cvCreateImage(cvSize(image->width, image->height),image->depth ,1);  
    21.   
    22.     int  i,j,r,s ;  
    23.     unsigned char B1[9] ={ 255,255,255,255,0,0,255,0,0};  
    24.     unsigned char B2[9] = {0,0,0,0,255,255,0,255,255 };  
    25.     int flag;  
    26. //iamge2 是对image进行求补的结果  
    27.     unsigned char *ptr, *dst,*ptr2;  
    28.     for (i = 0 ; i< image2->height; i++)  
    29.     {  
    30.         for (j = 0 ; j< image2->width; j++)  
    31.         {  
    32.             ptr = (unsigned char*)image->imageData + i * image->widthStep+ j;  
    33.             dst = (unsigned char*)image2->imageData + i*image2->widthStep + j;  
    34.             *dst = 255- (*ptr);  
    35.   
    36.         }  
    37.     }  
    38.   
    39.     //对源图像进行腐蚀  
    40.     for (i = 0 ; i< image3->height; i++)  
    41.     {  
    42.         for (j = 0 ; j< image3->width; j++)  
    43.         {  
    44.             flag = 1;  
    45.             dst = (unsigned char*)image3->imageData + i*image3->widthStep +j;  
    46.             //边界判断  
    47.             if (( i == 0) || (j == 0) || (i == image3->height-1) || (j == image3->width -1 ))  
    48.             {  
    49.                 *dst = 0;  
    50.             }  
    51.             else{  
    52.                     for (r = i -1 ; r<= i+1; r++)  
    53.                     {  
    54.                         for (s = j-1 ; s <= j +1 ; s++)  
    55.                         {  
    56.                             ptr = (unsigned char*)image->imageData + r * image->widthStep+ s;  
    57.                             if (*ptr != B1[3*(r-i+1) + s-j+1])  
    58.                             {  
    59.                             flag = 0;  
    60.                             break;  
    61.                             }  
    62.                         }  
    63.                     }  
    64.                     if (flag == 1)  
    65.                     {  
    66.                         ptr = (unsigned char*)image->imageData + i * image->widthStep+ j;  
    67.                         *dst = 255;  
    68.                     }  
    69.                     else{  
    70.                         *dst = 0;  
    71.                     }  
    72.   
    73.                 }  
    74.   
    75.         }  
    76.     }  
    77.   
    78.     //显示腐蚀结果  
    79.   
    80.     for (i = 0 ; i< image2->height; i++)  
    81.     {  
    82.         for (j = 0 ; j< image2->width; j++)  
    83.         {  
    84.             ptr = (unsigned char*)image->imageData + i * image->widthStep+ j;  
    85.             ptr2 = (unsigned char*)image3->imageData + i*image3->widthStep + j;  
    86.             if (*ptr2  == 255)  
    87.             {  
    88.                 printf("x, %d  y: %d   %d\n",j, i, *ptr2 - *ptr);  
    89.             }  
    90.               
    91.         }  
    92.     }  
    93.     //对补图像进行腐蚀  
    94.     for (i = 0 ; i< image4->height; i++)  
    95.     {  
    96.         for (j = 0 ; j< image4->width; j++)  
    97.         {  
    98.             flag = 1;  
    99.             dst = (unsigned char*)image4->imageData + i*image4->widthStep +j;  
    100.             //边界判断  
    101.             if (( i == 0) || (j == 0) || (i == image4->height-1) || (j == image4->width -1 ))  
    102.             {  
    103.                 *dst = 0;  
    104.             }  
    105.             else{  
    106.                 for (r = i -1 ; r<= i+1; r++)  
    107.                 {  
    108.                     for (s = j-1 ; s <= j +1 ; s++)  
    109.                     {  
    110.                         ptr = (unsigned char*)image2->imageData + r * image2->widthStep+ s;  
    111.                         if ((*ptr) != B2[3*(r- i+1) + s-j +1])  
    112.                         {  
    113.                             flag = 0;  
    114.                         }  
    115.                     }  
    116.                 }  
    117.                 if (flag == 1)  
    118.                 {  
    119.                     ptr = (unsigned char*)image2->imageData + i * image2->widthStep+ j;  
    120.                     *dst = 255;  
    121.                 }  
    122.                 else{  
    123.                     *dst = 0;  
    124.                 }  
    125.   
    126.             }  
    127.   
    128.         }  
    129.     }  
    130.     //显示腐蚀结果  
    131.   
    132.     for (i = 0 ; i< image4->height; i++)  
    133.     {  
    134.         for (j = 0 ; j< image4->width; j++)  
    135.         {  
    136.             ptr = (unsigned char*)image2->imageData + i * image->widthStep+ j;  
    137.             ptr2 = (unsigned char*)image4->imageData + i*image3->widthStep + j;  
    138.             if (*ptr2  == 255)  
    139.             {  
    140.                 printf("x, %d  y: %d   %d\n",j,i, *ptr2 - *ptr);  
    141.             }  
    142.   
    143.         }  
    144.     }  
    145.     //二者求交集  
    146.     for (i = 0 ; i< result->height; i++)  
    147.     {  
    148.         for (j = 0 ; j< result->width; j++)  
    149.         {  
    150.             ptr = (unsigned char *)image3->imageData + image3->widthStep * i + j;  
    151.             ptr2 = (unsigned char *)image4->imageData + image4->widthStep * i + j;  
    152.             dst = (unsigned char *)result->imageData +  result->widthStep*i + j;  
    153.             if (((*ptr) == 255) && ((*ptr2) == 255))  
    154.             {  
    155.                 *dst = 255;  
    156.                 printf("x : %d\n" , j);  
    157.                 printf("y : %d\n" , i);  
    158.   
    159.             }  
    160.             else{  
    161.                   
    162.                 *dst = 0;  
    163.             }  
    164.   
    165.         }  
    166.     }  
    167.     cvNamedWindow("image3",1);  
    168.     cvNamedWindow("image4",1);  
    169.     cvNamedWindow("result",1);  
    170.     cvShowImage("image3",image3);  
    171.     cvShowImage("image4",image4);  
    172.     cvShowImage("result",result);  
    173.     //cvSaveImage("mapleleafboard.bmp", image3);  
    174.     cvWaitKey(0);  
    175.     cvReleaseImage(&image);  
    176.     cvReleaseImage(&image2);  
    177.     cvReleaseImage(&image3);  
    178.     cvDestroyAllWindows();  
    179.     return 0 ;  
    180. }  
    原图:


    提取的角点:


    如果要提取十字型角点只需换用十字型的模板即可

    (4)       噪声滤除

    对图像中的噪声进行滤除是图像预处理中不可缺少的操作。将开启和闭合运算结合起来可构成形态学噪声滤除器。

    对于二值图像,噪声表现为目标周围的噪声块和目标内部的噪声孔。用结构元素B对集合A进行开启操作,就可以将目标周围的噪声块消除掉;用B对A进行闭合操作,则可以将目标内部的噪声孔消除掉。该方法中,对结构元素的选取相当重要,它应当比所有的噪声孔和噪声块都要大。

    对于灰度图像,滤除噪声就是进行形态学平滑。实际中常用开启运算消除与结构元素相比尺寸较小的亮细节,而保持图像整体灰度值和大的亮区域基本不变;用闭合运算消除与结构元素相比尺寸较小的暗细节,而保持图像整体灰度值和大的暗区域基本不变。将这两种操作综合起来可达到滤除亮区和暗区中各类噪声的效果。同样的,结构元素的选取也是个重要问题。


     

     

    四 选取结构元素的方法

    分析表明,各种数学形态学算法的应用可分解为形态学运算和结构元素选择两个基本问题,形态学运算的规则已由定义确定,于是形态学算法的性能就取决于结构元素的选择,亦即结构元素决定着形态学算法的目的和性能。因此如何自适应地优化确定结构元素,就成为形态学领域中人们长期关注的研究热点和技术难点。目前较多采用多个结构元素对图像进行处理的方法。

     

    (1)       多结构元素运算

    在许多形态学应用中,往往只采用一个结构元素,这通常不能产生满意的结果。在模式识别中,如果要提取某个特定的模式,只采用一个结构元素,那么,只有与结构元素形状、大小完全相同的模式才能被提取,而与此结构元素表示的模式即使有微小差别的其他模式的信息都不能获取。

    解决此问题的一个有效方法之一就是将形态学运算与集合运算结合起来,同时采用多个结构元素,分别对图像进行运算,然后将运算后的图像合并起来,即多结构元素形态学运算。

     

    (2)       用遗传算法选取结构元素

    遗传算法的思想来源于自然界物竞天择、优胜劣汰、适者生存的演化规律和生物进化原理,并引用随机统计理论而形成,具有高效并行全局优化搜索能力,能有效地解决机器学习中参数的复杂优化和组合优化等难题。

    近年来不少国外学者已进行了这方面的探索与研究,Ehrgardt设计了形态滤波的遗传算法,用于二值图像的去噪和根据二值纹理特性消除预定目标;Huttumen利用遗传算法构造了软式形态滤波器及其参数优化的设计方法,以实现灰度图像的降噪功能。余农、李予蜀等人用遗传算法在自然景象的目标检测与提取方面进行了研究,通过自适应优化训练使结构元素具有图像目标的形态结构特征,从而赋予结构元素特定的知识,使形态滤波过程融入特有的智能,以实现对复杂变化的图像具有良好的滤波性能和稳健的适应能力。其实质是解决滤波器设计中知识获取和知识精炼的机器学习问题。

     

    五 数学形态学存在的问题与进一步的研究方向

    数学形态学是一门建立在集论基础之上的学科,是几何形状分析和描述的有力工具。近年来,数学形态学在数字图像处理、计算机视觉与模式识别等领域中得到了越来越广泛的应用,渐渐形成了一种新的数字图像分析方法和理论,引起了国内外相关领域研究人员的广泛关注。目前,数学形态学存在的问题及研究方向主要集中在以下几个方面:

    (1)            形态运算实质上是一种二维卷积运算,当图像维数较大时,特别是用灰度形态学、软数学形态学、模糊形态学等方法时,运算速度很慢,因而不适于实时处理。

    (2)            由于结构元素对形态运算的结果有决定性的作用,所以,需结合实际应用背景和期望合理选择结构元素的大小与形状。

    (3)             软数学形态学中关于结构元素核心、软边界的定义,及对加权统计次数*的选择也具有较大的灵活性,应根据图像拓扑结构合理选择,没有统一的设计标准。

    (4)           为达到最佳的滤波效果,需结合图像的拓扑特性选择形态开、闭运算的复合方式。

    (5)            对模糊形态学,不同的模糊算子会直接影响模糊形态学的定义及其运算结果。

    (6)           有待进一步将数学形态学与神经网络、模糊数学结合研究灰度图像、彩色图像的处理和分析方法。

    (7)            有待进一步研究开发形态运算的光学实现及其它硬件实现方法。

    (8)            有待将形态学与小波、分形等方法结合起来对现有图像处理方法进行改进,进一步推广应用。所以如何实现灰度形态学、软数学形态学、模糊软数学形态学的快速算法,如何改善形态运算的通用性,增强形态运算的适应性,并结合数学形态学的最新应用进展,将其应用到图像处理领域,丰富和发展利用数学形态学的图像处理与分析方法,成为数学形态学今后的发展方向。

     

    六 结论

    数学形态学对图像的处理具有直观上的简明性和数学上的严谨性,在定量描述图像的形态特征上具有独特的优势,为基于形状细节进行图像处理提供了强有力的手段。建立在集合理论基础上的数学形态学,主要通过选择相应的结构元素采用膨胀、腐蚀、开启、闭合#种基本运算的组合来处理图像。数学形态学在图像处理中的应用广泛,有许多实用的算法,但在每种算法中结构元素的选取都是一个重要的问题。


    文章转自:http://blog.csdn.net/renshengrumenglibing/article/details/7177695


    展开全文
  • 基于Python-Opencv,使用图像形态学和算子处理实现事项轮廓处理
  • 数字图像处理第九章——形态学图像处理

    万次阅读 多人点赞 2019-05-11 08:31:12
    数字图像处理第九章数字图像处理---形态学图像处理(一)预备知识1.1 预备知识1.1.1 集合理论中的基本概念1.2 二值图像、集合及逻辑算子(二)膨胀和腐蚀2.1 膨胀2.2 结构元的分解2.3 strel函数2.4 腐蚀(三) 膨胀...
  • (2)受理与调查:银行在收到借款人的借款申请后,应由客户经理收集相关信息并对其资质、信用、财务等情况进行分析。进行初步洽谈。形成书面报告 (3)风险评价:将书面报告交给银行审批部,由审批部进行风险【评价...
  • [MATLAB] 常用形态学操作函数

    千次阅读 2018-04-14 20:41:15
    形态主要是为了获取物体的拓扑和结构信息,通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。当形态学运用到图像处理中,它的主要作用是利用形态学的基本运算,如腐蚀和膨胀运算,对图像进行观察和...
  • 二值图像与数学形态学处理

    千次阅读 2020-12-17 15:54:13
    数学形态学处理 引言:数学形态学的主要研究内容是图像形态几何特征,结构特征的定量描述与分析,是线性向非线性处理的延拓。形态变换最大的特点就是能将大量复杂的影像处理运算转化成最基本的移位与逻辑运算的复合...
  • 多年以前,这一系列相关的概念主要是物联网领域,当时主要的入口点是设备孪生(device twins) —— 我还翻译过一系列的相关文章。在 2017 年时,Azure IoT 就提供了设备孪生的服务,它用于: 将设备特定的元数据...
  • 文章目录前言一、相关背景1.1 数据类型(本文介绍常见的两种)1.2 建树流程二、数据问题2.1数据集缺失2.2 数据...注:不论是古生物形态学数据或DNA数据,就建树方法来说是一样的,所以本文中也用DNA数据的例子。 一、
  • 形态学及边缘角点检测

    千次阅读 2018-07-10 20:36:38
    形态学滤波理论于上世纪90年代提出,目前被广泛用于分析及处理离散图像。其基本运算有4个: 膨胀、腐蚀、开启和闭合, ...数学形态学方法利用一个称作结构元素的“探针”收集图像的信息,当探针在图像中不断移动时,...
  • 腐蚀与膨胀( Erosion 与 Dilation) 是OpenCV提供的两种最基本的形态学操作。 1.形态学操作 简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将 结构元素 作用于输入图像来产生输出图像。 最基本的形态学...
  • 形态主要从图像内提取分量信息,该分量信息通常对于表达和描绘图像的形状具有重要意义,通常是图像理解时所使用的最本质的形状特征。形态学操作主要包含:腐蚀、膨胀、开运算、闭运算、形态学梯度运算、礼帽运算、...
  • 2020电子设计竞赛G题 非接触物体尺寸形态测量 OpenMV部分总结比赛总结OpenMV部分总结问题一 OpenMV本身运算能力问题问题二 OpenMV IDE bug问题三 OpenMV 感光元器件偶尔发红问题四 OpenMV 和32通信问题 比赛总结 ...
  • 形态学图像处理(一)基础知识(1)集合论中的基本概念(2)二值图像、集合及逻辑算子(二)膨胀与腐蚀(1)膨胀(2)结构元的分解(3)strel函数(4)腐蚀(三)膨胀与腐蚀的结合(1)开操作和闭操作(2)击中和或...
  • 01引言在股票市场上,一切交易行为的成功皆为概率事件,交易获利的核心在于选择了上涨概率较高的股票。因此,利用高概率的上升形态来选股,是技术分析的重要方法之一。威廉·欧奈尔在《笑傲股市》中...
  • 如果说 《网络安全法》 是对企业端单方面的数据的存取进行监管, 那么 《个人信息保护法》 就是加强对数据定级和授权的监管, 而且形态不再是企业一方行为, 而是企业和个人的双方行为. GRC的实施将是对现有数据形态的...
  • 信息检索与利用(第三版)第一章

    千次阅读 2020-04-07 15:39:35
    第一章 基础知识 1.1 信息、知识、文献、情报 1. 信息 (1)信息的含义 信息的含义是十分广泛的。世间万物的运动,人间万象的更迭,都离不开信息的作用。...信息是物质存在的一种方式、形态或运动状态,也是事...
  • 一般来说,信息法由信息资源管理法、政府信息公开法、信息保密法、大众传播法、知识产权法、网络信息法等组成,涉及宪法、法律、行政法规、部门规章、地方行政和规章在内的所有关于信息活动和信息工作的法律法规。...
  • 广告商业形态与应用架构

    万次阅读 2021-11-13 19:40:32
    文章目录广告商业形态深思广告到底是什么?互联网广告市场形态互联网平台角色流量售卖方式非合约式合约式平台流量收益最大化广告位分配流量分配广告样式实时竞价第二竞价广告应用架构全局链路架构Adapter 适配ADX ...
  • 信息检索习题

    千次阅读 2021-06-30 16:49:44
    二次文献、三次文献、一次文献 6、( B )的主要功能是检索、通报、控制一次文献,帮助人们在较短时间内获取较多的文献信息。 A.零次文献 B.二次文献 C.一次文献 D.三次文献 7、一次文献、二次文献、三次文献是按照...
  • 信息化知识-1.1信息化知识

    千次阅读 2020-11-18 19:46:50
    信息是客观事物状态和运动特征的一种普遍形式,客观世界中大量地存在、产生和传递着以这些方式表示出来的各种各样的信息。 维纳:信息就是信息,既不是物质也不是能量; 香农:信息就是能够用来消除不确定性的东西;...
  • 农业信息技术复习题

    千次阅读 2020-06-25 15:36:26
    1.信息传递技术,即通信技术,不包括(B) (A)数字程控交换技术(B)定位遥感技术 (C)光纤通讯(D)综合业务数字通信网" 2.信息技术的四大基本技术是计算机技术、传感技术、控制技术和( C ) (A)生物技术...
  • 大学生信息检索概论练习题

    千次阅读 2021-07-16 15:35:20
    二次文献、三次文献、一次文献 6、( B )的主要功能是检索、通报、控制一次文献,帮助人们在较短时间内获取较多的文献信息。 A.零次文献 B.二次文献 C.一次文献 D.三次文献 7、一次文献、二次文献、三次文献是按照...
  • 形态学图像处理(二)

    万次阅读 2016-12-31 21:38:10
    本文主要包括以下内容 二值形态学的经典应用, 细化和像素化, 以及凸壳 灰度图像的形态学运算, 包括灰度腐蚀、灰度膨胀、灰度开和灰度闭 本章的典型案例分析 在人脸局部图像中定位嘴的中心 显微镜下图像的细菌...
  • 文章目录信息资源的理解按信息的加工和集约程度划分信息源?缩微文献的优点?文献信息的性质?各类信息源的特点信息采集的原则?联机信息检索的特点? 信息资源的理解 广义的理解,认为信息资源是社会信息活动中积累...
  • 网络信息安全第二讲 信息加密技术基础 一 信息加密理论基础 1.信息熵基本知识 信息熵(information entropy)是对信息状态“无序”与“不确定”的度量(从本质上讲,熵不是对信息的度量,但信息的增加而使产生的熵...
  • 【OpenCV学习】(八)图像形态

    千次阅读 2022-01-11 17:18:31
    【OpenCV学习】(八)图像形态学 背景 形态学处理方法是基于对二进制图像进行处理的,卷积核决定图像处理后的效果;形态学的处理哦本质上相当于对图像做前处理,提取出有用的特征,以便后续的目标识别等任务; 一、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,241
精华内容 21,296
关键字:

信息的主要存在形态