OpenCV 4.12.0
开源计算机视觉
加载中...
搜索中...
无匹配项
形态学变换

目标

在本章中,

原理

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

image

1. 腐蚀

腐蚀的基本思想就像土壤侵蚀一样,它会腐蚀前景对象的边界(始终尝试将前景保持为白色)。那么它是如何工作的呢?内核在图像上滑动(如在 2D 卷积中)。原始图像中的像素(无论是 1 还是 0)只有当内核下的所有像素都为 1 时才被视为 1,否则它会被腐蚀(变为零)。

因此发生的情况是,所有靠近边界的像素都会根据内核的大小被丢弃。因此,前景对象的厚度或大小减小,或者图像中的白色区域简单地减小。它可用于去除小的白色噪点(正如我们在颜色空间章节中看到的那样),分离两个连接的对象等。

在这里,作为一个例子,我将使用一个 5x5 的内核,其中充满了 1。让我们看看它是如何工作的

import cv2 as cv
import numpy as np
img = cv.imread('j.png', cv.IMREAD_GRAYSCALE)
assert img is not None, "无法读取文件,请检查 os.path.exists()"
kernel = np.ones((5,5),np.uint8)
erosion = cv.erode(img,kernel,iterations = 1)
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件加载图像。
void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar &borderValue=morphologyDefaultBorderValue())
使用特定的结构元素对图像进行腐蚀。

结果

image

2. 膨胀

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

dilation = cv.dilate(img,kernel,iterations = 1)
void dilate(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar &borderValue=morphologyDefaultBorderValue())
使用特定的结构元素对图像进行膨胀。

结果

image

3. 开运算

开运算只是先腐蚀后膨胀的另一个名称。如上所述,它有助于去除噪声。在这里,我们使用函数 cv.morphologyEx()

opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
void morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar &borderValue=morphologyDefaultBorderValue())
执行高级形态学变换。

结果

image

4. 闭运算

闭运算是开运算的逆运算,先膨胀后腐蚀。它有助于闭合前景对象内部的小孔,或者对象上的小黑点。

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

结果

image

5. 形态学梯度

它是图像的膨胀和腐蚀之间的差异。

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

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

结果

image

6. 顶帽

它是输入图像和图像的开运算之间的差异。下面的示例是针对 9x9 内核完成的。

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

结果

image

7. 黑帽

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

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

结果

image

结构元素

我们在前面的示例中借助 Numpy 手动创建了一个结构元素。它是矩形形状。但在某些情况下,您可能需要椭圆形/圆形内核。因此,为此目的,OpenCV 有一个函数 cv.getStructuringElement()。您只需传递内核的形状和大小,即可获得所需的内核。

# 矩形内核
>>> 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)
# 椭圆内核
>>> 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)
# 十字形内核
>>> 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)
# 菱形内核
>>> cv.getStructuringElement(cv.MORPH_DIAMOND,(5,5))
array([[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0]], dtype=uint8)
Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))
返回指定大小和形状的结构元素,用于形态学操作。

补充资源

  1. 形态学操作 at HIPR2