Advertisement

2019-7-17 opencv图像处理5-形态学变换(Morphological Transformations)

阅读量:

官网参见https://docs.opencv.org/3.4.1/d9/d61/tutorial_py_morphological_ops.html

形态学变化可以用来解决抑制噪声、特征提取、边缘检测、图像分割、形状识别、纹理分析、图像恢复与重建、图像压缩等图像处理问题。

内容概要

  • 腐蚀, cv2.erode(),去白色噪音,分离连接物体
  • 膨胀, cv2.dilate(),扩大前景区域,连接物体被断开部分
  • 开运算,cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel),先腐蚀再膨胀。用于去除噪音,同时保持前景不缩小
  • 闭运算,cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel),先膨胀再腐蚀。用于填充前景物体小洞,或者去除前景小黑点
  • 形态学梯度,cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel),膨胀图和腐蚀图只差。用于获得物体边缘。
  • 顶帽,cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel),原始图像和开运算后图像之差,往往用来分离比临近点亮一些的斑块。
  • 黑帽, cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel),闭运算后的图像和原始图像之差,用来分离比临近点暗一些的斑块,效果图有着非常完美的轮廓。
  • 结构化元素,矩形核,圆形核,椭圆核

形态学变换是基于图像形状的一些简单操作,通常是对二值化图像进行操作。
它需要2个参数,一个是原始图像,另外一个被称为结构化元素或者核,它决定了操作的性质。有2个基本的形态学操作:腐蚀和膨胀。它们的变化形式有开运算,闭运算,梯度等。

1.腐蚀

形态学腐蚀的基本概念和土壤腐蚀一样,会把图像中前景物体的边界腐蚀掉(通常会保持前景为白色)。它是怎么做到的呢?

以2D卷积为例,参见
这样做的结果就是,靠近边界的图像元素会根据卷积核的大小决定是否被抛弃(或者说腐蚀掉,也就是变为0)。

腐蚀会让前景物体的厚度或者说大小在整个图像中变小,也可以说图像中的白色区域减少(因为前景是白色的)。

腐蚀可以去除图像中的小白色噪音,也可以用于分离2个连接在一起的物体。

例1,简单的腐蚀,5x5核

复制代码
    # -*- coding: cp936 -*-
    import cv2 
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('j.png',0)
    kernel = np.ones((5,5),np.uint8)
    erosion = cv2.erode(img,kernel,iterations = 1)
    
    plt.subplot(121),plt.imshow(img,'gray'),plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(erosion,'gray'),plt.title('Erosion')
    plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述
本例图片来自官网,运行结果如上图。右边是腐蚀结果,白色区域明显减少。

2.膨胀

膨胀与腐蚀相反,卷积核对应图像元素只要有1个值为1,那么中心元素的值就是1。所以膨胀会增加图像前景物体的尺寸,或者说增加图像的白色区域。

通常去除噪音时,会先腐蚀然后再膨胀,因为腐蚀在去除白色噪音的同时,还会缩小前景对象,所以我们还需要膨胀它。

膨胀可以扩大前景物体,还可以用于连接一个物体被断开部分。

例,简单的膨胀

复制代码
    # -*- coding: cp936 -*-
    import cv2 
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('j.png',0)
    kernel = np.ones((5,5),np.uint8)
    dilation = cv2.dilate(img,kernel,iterations = 1)
    
    plt.subplot(121),plt.imshow(img,'gray'),plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(dilation,'gray'),plt.title('Dilation')
    plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述
运行结果如上图。右边是膨胀结果,白色区域明显增加。

3.开运算

先腐蚀再膨胀的过程,我们就称为开运算。上面已经解释过了,主要用于去除噪音。
opencv中提供cv.morphologyEx()用于开运算。

例,开运算

复制代码
    # -*- coding: cp936 -*-
    import cv2 
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('j-1.png',0)
    kernel = np.ones((5,5),np.uint8)
    opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    
    plt.subplot(121),plt.imshow(img,'gray'),plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(opening,'gray'),plt.title('Opening')
    plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述
运行结果如上图。右边是开运算结果,白色噪音被去除了,但是白色区域没有减少。

4.闭运算

闭运算是和开运算相反的操作,先膨胀再腐蚀。用于填充前景物体的小洞,或者去除前景物体的小黑点。
cv.morphologyEx()也可以用于闭运算。

复制代码
    closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

5.形态学梯度

梯度 用于刻画目标边界或边缘位于图像灰度级剧烈变化的区域。
形态学梯度是一幅图像的膨胀图和腐蚀图之差,结果看上去就是物体的轮廓。

所以对图像的二值图(灰度图)进行形态学梯度操作可以将团块(blob)的边缘突出出来,实现保留物体的边缘轮廓。

opencv梯度操作也是使用cv.morphologyEx()函数

复制代码
    # -*- coding: cp936 -*-
    import cv2 
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('j.png')
    kernel = np.ones((5,5),np.uint8)
    gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
    
    plt.subplot(121),plt.imshow(img,'gray'),plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(gradient,'gray'),plt.title('Gradient')
    plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述
结果如上图。

6.顶帽

原始图像和开运算后图像之差,往往用来分离比临近点亮一些的斑块。
在一幅图像具有大幅的背景,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。

代码,9x9核

复制代码
    # -*- coding: cp936 -*-
    import cv2 
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('j.png')
    kernel = np.ones((9,9),np.uint8)
    tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
    
    plt.subplot(121),plt.imshow(img,'gray'),plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(tophat,'gray'),plt.title('Tophat')
    plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述
运行结果如上

7.黑帽
闭运算后的图像和原始图像之差,用来分离比临近点暗一些的斑块,效果图有着非常完美的轮廓。

代码

复制代码
    # -*- coding: cp936 -*-
    import cv2 
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('j.png')
    kernel = np.ones((9,9),np.uint8)
    blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
    
    plt.subplot(121),plt.imshow(img,'gray'),plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(blackhat,'gray'),plt.title('Blackhat')
    plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述
运行结果如上图。

结构化元素

在上面的例子中我们使用Numpy 构建了结构化元素(卷积核),它是正方形的。

复制代码
    kernel = np.ones((9,9),np.uint8)

但有时我们需要构建一个椭圆形或者圆形的核。为了实现这种要求,opencv提供了函数cv2.getStructuringElement()。你只需要告诉他你需要的核的形状和大小。

代码参考如下

复制代码
    # Rectangular Kernel
    >>> cv.getStructuringElement(cv.MORPH_RECT,(5,5))
    array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
    # Elliptical Kernel
    >>> cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
    array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
    # Cross-shaped Kernel
    >>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5))
    array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)

全部评论 (0)

还没有任何评论哟~