OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
未找到匹配项
形态学变换

目标

在本章中,

理论

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

图像

1. 腐蚀

腐蚀的基本思想就像土壤侵蚀一样,它会侵蚀掉前景对象的边界(始终尝试将前景保持为白色)。那么它做了什么?内核在图像上滑动(如在二维卷积中)。只有当内核下的所有像素都为 1 时,原始图像中的像素(1 或 0)才会被认为是 1,否则它会被腐蚀(设置为零)。

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

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

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())
使用特定的结构元素腐蚀图像。

结果

图像

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())
使用特定的结构元素膨胀图像。

结果

图像

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())
执行高级形态学变换。

结果

图像

4. 闭运算

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

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

结果

图像

5. 形态学梯度

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

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

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

结果

图像

6. 顶帽

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

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

结果

图像

7. 黑帽

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

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

结果

图像

结构元素

在前面的示例中,我们借助 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))
数组([[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))
数组([[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)
Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))
返回用于形态学运算的指定大小和形状的结构元素。

额外资源

  1. HIPR2上的形态学运算