翻译及二次校对:cvtutorials.com
目标
在本章中:
- • 我们将学习不同的形态学操作,如腐蚀、膨胀、开运算、闭运算等。
- • 我们将看到不同的函数,如:cv.erode(), cv.dilate(), cv.morphologyEx() 等。
理论
形态学变换是基于图像形状的一些简单操作。它通常是在二进制图像上进行的。它需要两个输入,一个是我们的原始图像,第二个被称为结构化元素或核,它决定了操作的性质。两个基本的形态学运算符是腐蚀和膨胀。然后,它的变体形式,如开运算、闭运算、梯度等也开始发挥作用。我们将在以下图片的帮助下逐一看到它们。
- 1. 腐蚀
腐蚀的基本概念就像土壤腐蚀一样,只是它腐蚀了前景物体的边界(总是尽量保持前景为白色)。那么它是怎么做的呢?核在图像中滑动(如二维卷积)。原始图像中的一个像素(1或0)只有在核下的所有像素都是1时才会被认为是1,否则就会被腐蚀(变成0)。
因此,发生的情况是,根据核的大小,所有靠近边界的像素将被丢弃。因此,前景物体的厚度或大小减少了,或者说是图像中的白色区域减少了。这对于去除小的白色噪音(正如我们在色彩空间一章中所看到的),分离两个相连的物体等很有用。
这里,作为一个例子,我将使用一个充满1的5x5核。让我们看看它是如何工作的。
代码语言:javascript复制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)
结果如下:
2. 膨胀
它与腐蚀刚好相反。这里,一个像素元素是 "1",如果核心下至少有一个像素是 "1"。因此,它增加了图像中的白色区域或增加了前景物体的大小。通常情况下,在去除噪声等情况下,腐蚀之后是膨胀。因为,腐蚀可以去除白色噪音,但它也会缩小我们的物体。所以我们要膨胀它。由于噪音已经消失,它们不会再出现,但我们的对象面积会增加。它在连接一个物体的破碎部分时也很有用。
代码语言:javascript复制dilation = cv.dilate(img,kernel,iterations = 1)
结果如下:
3. 开运算
开运算只是腐蚀和膨胀的另一个名称。正如我们上面解释的那样,它在去除噪音方面很有用。在这里,我们使用函数cv.morphologyEx()
代码语言:javascript复制opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
结果如下:
- 4. 闭运算
闭运算是开运算的反面,膨胀之后是腐蚀。它在关闭前景物体内部的小孔,或物体上的小黑点时很有用。
代码语言:javascript复制closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
结果如下:
5. 形态学梯度
它是图像的膨胀和腐蚀之间的区别。
其结果将看起来像物体的轮廓。
代码语言:javascript复制gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
结果如下:
6. 高帽
它是输入图像和图像开运算之间的差异。下面的例子是针对一个9x9的核做的。
代码语言:javascript复制tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
结果如下:
7. 黑帽
它是指输入图像和输入图像的闭运算度之差。
代码语言:javascript复制blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
结果如下:
结构化元素
在前面的例子中,我们在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)
其他资源
- • HIPR2的形态学操作