【基础】腐蚀与膨胀

1. 腐蚀

腐蚀操作

腐蚀是最基本的形态学操作之一,它能够将图像的边界点消除,使图像沿着边界向内收缩,也可以将小于指定结构体元素的部分去除

腐蚀用来“收缩”或者“细化”二值图像中的前景,借此实现去除噪声、元素分割等功能。例如,在下图中,左图是原始图像,右图是对其腐蚀的处理结果。

image.png

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

例如,在下图中,整幅图像的背景色是黑色的,前景对象是一个白色的圆形。图像左上角的深色小方块是遍历图像所使用的结构元。在腐蚀过程中,要将该结构元逐个像素地遍历整幅图像,并根据结构元与被腐蚀图像的关系,来确定腐蚀结果图像中对应结构元中心点位置的像素点的值。

image.png

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

下图中的两幅图像表示结构元与前景色的两种不同关系。根据这两种不同的关系来决定,腐蚀结果图像中的结构元中心点所对应位置像素点的像素值。

image.png

● 如果结构元完全处于前景图像中(左图),就将结构元中心点所对应的腐蚀结果图像中的像素点处理为前景色。

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

针对上图,腐蚀的结果就是前景色的白色圆直径变小,上述结构元也被称为

程序演示

在openCV中,使用函数cv2.erode()实现腐蚀操作,其语法格式为:

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

  • src:需要进行腐蚀的原始图像

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

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

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

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

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

import cv2
import numpy as np

image = np.zeros((5, 5), dtype=np.uint8)
image[1:4, 1:4] = 1

kernel = np.ones((3, 1), np.uint8)

erosion = cv2.erode(image, kernel)

print(f'image = \n {image} \n kernel = \n {kernel} \n erosion = \n {erosion}')

运行结果如下图所示:

image.png

可以看到,只有当核kernel的中心点位于image中的image[2,1]image[2,2]image[2,3]处时,核才完全处于前景图像中。所以,在腐蚀结果图像中,只有这三个点的值为1,其余点的值皆为0。

程序演示:对图像进行腐蚀操作

import cv2
import numpy as np

image = cv2.imread('my_name.jpg', cv2.IMREAD_GRAYSCALE)

kernel = np.ones((3, 3), dtype=np.uint8)

erosion = cv2.erode(image, kernel, 1)

image_stack = np.hstack((image, erosion))

cv2.imshow('image_stack', image_stack)

cv2.waitKey(0)
cv2.destroyAllWindows()

经过腐蚀操作后,其结果如下图所示:

image.png

其中,左图为原始图像,右图有腐蚀后的图像,可以看到腐蚀操作将原始图像内的毛刺腐蚀掉了。


2. 膨胀

膨胀操作

膨胀操作是形态学中另外一种基本的操作。膨胀操作和腐蚀操作的作用是相反的,膨胀操作能对图像的边界进行扩张。膨胀操作将与当前对象(前景)接触到的背景点合并到当前对象内,从而实现将图像的边界点向外扩张。如果图像内两个对象的距离较近,那么在膨胀的过程中,两个对象可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。二值图像的膨胀示例如下图所示。

image.png

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

例如,在下图中,整幅图像的背景色是黑色的,前景对象是一个白色的圆形。图像左上角的深色小块表示遍历图像所使用的结构元。在膨胀过程中,要将该结构元逐个像素地遍历整幅图像,并根据结构元与待膨胀图像的关系,来确定膨胀结果图像中与结构元中心点对应位置像素点的值。

image.png

下图中的两幅图像代表结构元与前景色的两种不同关系。根据这两种不同关系来决定膨胀结果图像中,与结构元中心像素重合的点的像素值。

image.png

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

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

针对上图中的图像,膨胀的结果就是前景对象的白色圆直径变大。

程序演示

在openCV中,使用函数cv2.dilate()实现膨胀操作,其语法格式为:

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

  • src:需要进行膨胀的原始图像

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

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

  • iterations:膨胀操作迭代的次数,该值默认为1,即只进行一次膨胀操作

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

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

import cv2
import numpy as np

image = np.zeros((5, 5), dtype=np.uint8)
image[2:3, 1:4] = 1

kernel = np.ones((3, 1), np.uint8)

dilate = cv2.dilate(image, kernel)

print(f'image = \n {image} \n kernel = \n {kernel} \n dilate = \n {dilate}')

运行结果如下图所示:

image.png

可以看到,只要当核kernel的任意一点处于前景图像中时,就将当前中心点所对应的膨胀结果图像内像素点的值置为1。

程序演示:对图像进行腐蚀操作

import cv2
import numpy as np

image = cv2.imread('my_name.jpg', cv2.IMREAD_GRAYSCALE)

kernel = np.ones((3, 3), dtype=np.uint8)

dilate = cv2.dilate(image, kernel, 1)

image_stack = np.hstack((image, dilate))

cv2.imshow('image_stack', image_stack)

cv2.waitKey(0)
cv2.destroyAllWindows()

经过膨胀操作后,其结果如下图所示:

image.png

其中,左图为原始图像,右图有膨胀后的图像,可以看到膨胀操作将原始图像“变粗”了。