目标

  • 我们将学习不同的形态学操作,如腐蚀膨胀开运算闭运算等。
  • 我们将看到不同的函数,如:cv.erode()、cv.dilate()、cv.morphologyEx() 等。

理论知识

形态变换是一些基于图像形状的简单操作。它通常在二进制图像上执行。它需要两个输入,一个是我们的原始图像,第二个称为结构元素或内核,它决定了操作的性质。两个基本的形态学算子是侵蚀膨胀。然后它的变体形式如开、闭、梯度等也开始发挥作用。我们将在下图的帮助下一一看到它们:

opencv 矩形外扩 opencv 变形_opencv

腐蚀

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

所以发生的事情是,根据内核的大小,边界附近的所有像素都将被丢弃。因此,前景对象的厚度大小减少,或者图像中的白色区域会减少。它对于去除小的白噪声(正如我们在色彩空间章节中看到的)、分离两个连接的对象等很有用

在这里,作为一个例子,我会使用一个 5x5 的内核。让我们看看它是如何工作的:

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

结果如下:

opencv 矩形外扩 opencv 变形_opencv_02

膨胀

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

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

opencv 矩形外扩 opencv 变形_计算机视觉_03

开运算

开运算只是先腐蚀后膨胀的别名。正如我们上面所解释的,它在去除噪声方面很有用。这里我们使用函数 cv.morphologyEx()

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

opencv 矩形外扩 opencv 变形_色彩空间_04

闭运算

闭运算与开运算相反,先膨胀后腐蚀。它对于关闭前景对象内的小孔或对象上的小黑点很有用。

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

opencv 矩形外扩 opencv 变形_学习_05

形态梯度

这是图像膨胀和腐蚀之间的区别。结果将看起来像对象的轮廓。

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

opencv 矩形外扩 opencv 变形_色彩空间_06

顶帽运算(Top Hat)

这是输入图像和图像的Opening之间的区别。顶帽运算就是将原图减去开运算后的图像,放大了裂痕或局部低亮度区域,下面的示例是针对 9x9 内核完成的。

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

opencv 矩形外扩 opencv 变形_计算机视觉_07

黑帽运算(Black Hat)

它是输入图像和输入图像的闭运算之间的差异。与顶帽运算相反。

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

opencv 矩形外扩 opencv 变形_计算机视觉_08

内核创造函数

在 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)