【OpenCV 学习笔记】第八章: 形态学操作

第八章: 形态学操作

  • 什么是形态学操作?
    形态学,morphology, 形态学最初是生物学中研究动物和植物结构的一个分支,被引入图像处理领域后,图像形态学就指以形态为基础对图像进行分析的一种方法或技术。

  • 图像形态学操作的核心思想是:从图像中提取 用于表达或描绘图像形状 的信息。

  • 图像形态学操作的目的是:使计算机更够更好的对图像进行识别和理解。因为图像形态学处理后可以简化图像数据,同时保存了它们基本的形状特性,去除了不相干的结构。

  • 关键点:图像形态学操作主要是对二值图像进行操作的,来连接相邻的元素或分离成独立的元素。其次是灰度图像,但处理彩色图像几乎没有意义!

  • 图像形态学操作主要有:膨胀、腐蚀、开运算、闭运算、梯度运算、礼帽运算、黑帽运算,击中与击不中变换 等等。
    其中膨胀和腐蚀是基本操作,后面的操作都是在膨胀和腐蚀的基础上延申而来的。

  • 图像形态学操作有哪些应用领域?由于对图像进行形态学操作后,可以实现比如消除噪声、提取边界、填充区域、提取连通分量、凸壳、细化、粗化等; 还可以分割出独立的图像元素,或者图像中相邻的元素;求取图像中明显的极大值区域和极小值区域;求取图像梯度等等, 所以在视觉检测、图像理解、文字识别、医学图像处理、图像压缩编码等领域有非常重要的应用。

一、图像腐蚀

顾名思义,是将物体的边缘加以腐蚀。具体的操作是拿一个宽m高n的矩形作为kernel,对图像中的每一个像素进行扫描,扫描后的图像的每个像素点和原图的位置对应,同时和扫描时kernel的中心点对应。用kernel遍历原图的所有像素,每遍历一次就将对应位置的像素点更改为kernel中的最小值。这样原图所有像素遍历一轮后,原图中突出的像素点就会被置为最小值,人类视觉看起来就是图像被腐蚀了。

思考题:为什么上面右图腐蚀后的效果是字变胖了?

  • API: cv2.erode(img, kernel [, anchor, iterations, borderType ])
    #例8.1 观察cv2.erode()函数效果  
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = cv2.imread(r'C:\Users\25584\Desktop\erode.bmp', -1)
    kernel1 = np.ones((5,5), np.uint8)
    kernel2 = np.ones((9,9), np.uint8)
    img_erode_kernel1 = cv2.erode(img, kernel1)
    img_erode_kernel2 = cv2.erode(img, kernel2)
    
    fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100)
    axes[0].imshow(img)
    axes[1].imshow(img_erode_kernel1)
    axes[2].imshow(img_erode_kernel2)
    plt.show()

    二、图像膨胀

    膨胀和腐蚀是一对儿相反的操作,膨胀能对图像的边界进行扩展,就是将图像的轮廓加以膨胀。
    操作方法与腐蚀操作一样,也是拿一个kernel,对图像的每个像素做遍历处理。不同之处在于生成的像素值不是所有像素中最小的值,而是最大的值。这样操作的结果会将图像外围的突出点连接并向外延伸。

    思考题:为什么上面右图膨胀后的效果是字变瘦了?

  • API: cv2.dilate(img, kernel [, anchor, iterations, borderType ])
    #例8.2 观察cv2.dilate()函数效果  
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = cv2.imread(r'C:\Users\25584\Desktop\dilation.bmp', -1)
    kernel1 = np.ones((5,5), np.uint8)
    kernel2 = np.ones((9,9), np.uint8)
    img_dilate_kernel1 = cv2.dilate(img, kernel1)
    img_dilate_kernel2 = cv2.dilate(img, kernel2)
    
    fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100)
    axes[0].imshow(img)
    axes[1].imshow(img_dilate_kernel1)
    axes[2].imshow(img_dilate_kernel2)
    plt.show()

    三、图像开运算、闭运算、梯度运算、礼帽运算、黑帽运算、击中不击中变换

    腐蚀和膨胀是图像形态学运算的基础,将膨胀和腐蚀进行组合就得出开闭运算、梯度、礼帽、黑帽等不同形式的运算:

  • 开运算cv2.MORPH_OPEN:先腐蚀后膨胀--dilate(erode(img))
  • 闭运算cv2.MORPH_CLOSE:先膨胀后腐蚀--erode(dilate(img))
  • 形态学梯度cv2.MORPH_GRADIENT:膨胀图-腐蚀图--dilate(img)-erode(img)
  • 礼帽运算cv2.MORPH_TOPHAT:也叫顶帽运算,原始图像-开运算结果 -- img-open(img)
  • 黑帽运算cv2.MORPH_BLACKHAT: 闭运算结果-原始图像 -- close(img)-img
  • 击中不击中cv2.MORPH_HITMISS: 前景、背景腐蚀运算的交集 -- intersection(erode(img), erode(notimg))
     

    API: cv2.morphologyEx(img, op, kernel, anchor, iterations, borderType)
    其中参数op就是上面的几种类型。

    1、开运算:

  • #例8.3 使用函数cv2.morphologyEx()实现开运算
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img1 = cv2.imread(r'C:\Users\25584\Desktop\opening.bmp')
    img2 = cv2.imread(r'C:\Users\25584\Desktop\opening2.bmp')
    
    kernel = np.ones((10,10), np.uint8)
    img_open1 = cv2.morphologyEx(img1, cv2.MORPH_OPEN, kernel)
    img_open2 = cv2.morphologyEx(img2, cv2.MORPH_OPEN, kernel)
    
    fig, axes = plt.subplots(1,4, figsize=(10,5), dpi=100)
    axes[0].imshow(img1)
    axes[1].imshow(img2)
    axes[2].imshow(img_open1)
    axes[3].imshow(img_open2)
    plt.show()

    说明:开运算可以去噪、计数等。比如识别一张图像中有几个人,要先把人和人重叠的部分分开,然后再计数。

    2、闭运算:

  • #例8.4 使用函数cv2.morphologyEx()实现闭运算
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img1 = cv2.imread(r'C:\Users\25584\Desktop\closing.bmp')
    img2 = cv2.imread(r'C:\Users\25584\Desktop\closing2.bmp')
    
    kernel = np.ones((10,10), np.uint8)
    img_close1 = cv2.morphologyEx(img1, cv2.MORPH_CLOSE, kernel, iterations=3)
    img_close2 = cv2.morphologyEx(img2, cv2.MORPH_CLOSE, kernel, iterations=3)
    
    fig, axes = plt.subplots(1,4, figsize=(10,5), dpi=100)
    axes[0].imshow(img1)
    axes[1].imshow(img2)
    axes[2].imshow(img_close1)
    axes[3].imshow(img_close2)
    plt.show()

    说明:闭运算可以去除前景物内部的黑点,还可以将不同前景图像进行连接,就是实现前景图像的连接。

    3、形态学梯度运算: 该操作可以获取前景图像的边缘
    用膨胀图像(扩张亮度)-腐蚀图像(收缩亮度),就可以获取原始图像中的前景图像的边缘。

    #例8.5 使用函数cv2.morphologyEx()实现梯度运算
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = cv2.imread(r'C:\Users\25584\Desktop\gradient.bmp')
    
    kernel = np.ones((10,10), np.uint8)
    img_gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
    
    plt.subplot(121), plt.imshow(img)
    plt.subplot(122), plt.imshow(img_gradient)
    plt.show()

     4、礼帽运算:
    礼帽运算是原图-开运算图,所以礼帽运算可以获得图像的噪声信息,或者得到比原始图的边缘更亮的边缘信息。

    #例8.6 使用函数cv2.morphologyEx()实现礼帽运算
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img1 = cv2.imread(r'C:\Users\25584\Desktop\tophat.bmp')
    img2 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    
    kernel = np.ones((10,10), np.uint8)
    img1_tophat = cv2.morphologyEx(img1, cv2.MORPH_TOPHAT, kernel)
    img2_tophat = cv2.morphologyEx(img2, cv2.MORPH_TOPHAT, kernel)
    
    fig, axes = plt.subplots(1,4, figsize=(10,5), dpi=100)
    axes[0].imshow(img1)
    axes[1].imshow(img2)
    axes[2].imshow(img1_tophat)
    axes[3].imshow(img2_tophat)
    plt.show()

     5、黑帽运算:
    黑帽运算是闭运算图像-原始算图,所以黑帽运算可以获得图像内部的噪音,或者得到比原始图的边缘更暗的边缘信息。

    #例8.7 使用函数cv2.morphologyEx()实现黑帽运算
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img1 = cv2.imread(r'C:\Users\25584\Desktop\blackhat.bmp')
    img2 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp')
    
    kernel = np.ones((10,10), np.uint8)
    img1_blackhat = cv2.morphologyEx(img1, cv2.MORPH_BLACKHAT, kernel)
    img2_blackhat = cv2.morphologyEx(img2, cv2.MORPH_BLACKHAT, kernel)
    
    fig, axes = plt.subplots(1,4, figsize=(10,5), dpi=100)
    axes[0].imshow(img1)
    axes[1].imshow(img2)
    axes[2].imshow(img1_blackhat)
    axes[3].imshow(img2_blackhat)
    plt.show()

    四、自定义核进行形态操作

  • 自定义核的API: cv2.getStructuringElement(shape, ksize, anchor)
    shape:表示核的形状。
       shape=cv2.MORPH_RECT,表示生成一个矩形结构的核,所有元素值都是1。
       shape=cv2.MORPH_CROSS,表示生成一个十字形结构元素,对角线元素值为1。
       shape=cv2.MORPH_ELLIPSE表示生成一个椭圆形结构的核。
    ksize:核的尺寸
    anchor:核的锚点位置。
    #例8.8 使用函数cv2.getStructuringElement()生成不同的核,并观察不同核对图像的处理效果
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = cv2.imread(r'C:\Users\25584\Desktop\kernel.bmp')
    
    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\n', kernel2, '\n\n', kernel3)
    
    img_dilate1 = cv2.dilate(img, kernel1, iterations=17)
    img_dilate2 = cv2.dilate(img, kernel2, iterations=8)
    img_dilate3 = cv2.dilate(img, kernel3, iterations=20)
    
    fig, axes = plt.subplots(1,4, figsize=(10,5), dpi=100)
    axes[0].imshow(img)
    axes[1].imshow(img_dilate1)
    axes[2].imshow(img_dilate2)
    axes[3].imshow(img_dilate3)
    plt.show()
    [[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]] 
    
     [[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]] 
    
     [[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]]

猜你喜欢

转载自blog.csdn.net/friday1203/article/details/125066373