OpenCV: 形态变换



Goal

  • 学习不同的形态学操作, 如侵蚀, 膨胀, 开放, 关闭等
  • 学习不同的函数, 如: cv.erode(), cv.dilate(), cv.morphologyEx() 等


Theory

形态学转换是基于图像形状的一些简单操作。

一般被用在二值图像(二进制图像)上. 它需要两个输入, 一个是我们的原始图片, 另一个是被叫做结构元素或者是核, 用来决定运算的类型.

两个基本的形态运算是腐蚀和膨胀. 其他的变形如开、闭、梯度等. 我们将在以下图片的帮助下逐一看到它们:

Input Image


腐蚀 (Erosion)

腐蚀具有收缩和细化图像前景的作用。

腐蚀的基本思想就像土壤侵蚀一样,它会腐蚀前景物体的边界(总是试图保持前景为白色)。它是如何做到的呢?卷积核在图像中滑动(如在2D卷积中),只有当卷积核下的所有像素都是1时,原始图像中的像素(1或0)才会被认为是1,否则它会被腐蚀(变为零)。

所以腐蚀作用后,边界附近的所有像素都将被丢弃,具体取决于卷积核的大小。因此,前景对象的厚度或大小减小,或者图像中的白色区域减小。它有助于消除小的白噪声(正如我们在色彩空间章节中看到的那样),或者分离两个连接的对象等。


其原理是定义一个结构元素,用这个结构元素去遍历整个图像,只有图像能够包含整个结构元素,该图像中心的点才会被保留。

腐蚀操作通过 cv2.erode(src,kernel,iterations) 函数来实现。其中腐蚀用的结构元素 kernel 需要自己事先定义好。不同的结构元素对腐蚀的效果也有很大的影响。iterations 是指腐蚀迭代的次数,默认为1.


在这里,作为一个例子,我将使用一个5x5卷积核,其中包含完整的卷积核。让我们看看它是如何工作的:

import cv2
import numpy as np

img = cv2.imread('j.png', 0)
kernel = np.ones((5,5), np.uint8)
erosion = cv2.erode(img, kernel, iterations = 1)

Erosion


膨胀 (Dilation)

膨胀的效果与腐蚀恰恰相反,具有扩大图像的作用(但不是腐蚀的逆操作)。

它恰好与腐蚀相反。这里,如果卷积核下的像素至少一个像素为“1”,则像素元素为“1”。因此它增加了图像中的白色区域或前景对象的大小。通常,在去除噪音的情况下,侵蚀之后是扩张。因为,侵蚀会消除白噪声,但它也会缩小我们的物体,所以我们扩大它。由于噪音消失了,它们不会再回来,但我们的物体区域会增加。它也可用于连接对象的破碎部分。


也是通过选择一个结构元素,使其在图像中滑动,当结构元素覆盖区域内有1,则该覆盖的中心点被保留。

膨胀操作通过 cv2.dilate(src, kernel, iterations) 函数来实现,用法与腐蚀相近。

在 opencv 中我们定义结构元素可以通过 cv2.getStructuringElement(shape, size, point) 函数来实现,其中形状有三种:

  • 矩形:MORPH_RECT;
  • 交叉形:MORPH_CROSS;
  • 椭圆形:MORPH_ELLIPSE;


dilation = cv.dilate(img,kernel,iterations = 1)

image16


开运算 (Opening)

开运算是先腐蚀后膨胀的合成步骤。如上所述,它有助于消除噪音。这里我们使用函数 cv.morphologyEx()

opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)

image17


闭运算 (Closing)

闭运算与开运算相反,他是先膨胀后腐蚀的操作。它可用于过滤前景对象内的小孔或对象上的小黑点。

closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)


Closing


形态学梯度 (Morphological Gradient)

它的处理结果是显示膨胀和腐蚀之间的差异。

结果看起来像对象的轮廓。

gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)

image19


礼帽 (Top Hat)

它的处理结果是输入图像和开运算之间的区别。下面的示例是针对9x9卷积核完成的。

tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)

Top Hat


黑帽 (Black Hat)

它是输入图像闭运算和输入图像之间的差异。

blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)

Black Hat


结构元素 (Structuring Element)

我们在 Numpy 的帮助下手动创建了前面示例中的结构元素。它是正方形的,但在某些情况下可能需要椭圆或圆形卷积核。所以为此,OpenCV 有一个函数 cv.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)