定义
形态学操作,例如腐蚀,膨胀,开运算,闭运算等
形态学操作是根据图像形状进行的简单操作 一般情况下对二值化图像进行的操作。
需要输入两个参数: 一个是原始图像, 一个被称为结构化元素或核,它是用来决定操作的性质的
原理
形态变换是基于图像形状的一些简单操作。它通常在二进制图像上执行。它需要两个输入,一个是原始图像,第二个是结构元素或核structuring element or kernel ,它决定我们操作的性质。两个基本的形态操作运算符是侵蚀和扩张。然后,是它们的变体形式,如开放,关闭,梯度等。我们将看到他们一个接一个的帮助以下这张图片,“j”,进行形态变换:
腐蚀 Erosion
正如这个名字表面上的意思,侵蚀的基本思想就像土壤侵蚀一样,它侵蚀了前景物体foreground object 的边界(在这,我们会让前景保持为白色)。那么侵蚀的作用是什么呢?这样内核可以在图像中滑动(在二维卷积中)。只有当内核下的所有像素都为1时,原始图像中的像素(要么为1,要么为0)才会被认为是1,否则会被侵蚀(变成0)。
这样的结果就是,取决于内核的大小,边界附近的所有像素都会被丢弃。因此,前景对象的厚度或大小会减少,或者只是简单地让图像中的白色区域减少。它对于去除小的白色噪音(正如我们在颜色空间colorspace 疑问中看到的那样),分离两个连接的物体等都很有用。
腐蚀作用:可以用来消除小且无意义的物体。在这里,作为一个例子,我将使用一个包含内部全都是1的5x5内核。让我们看看它是如何工作的:
import cv2
import numpy as np
img = cv2.imread('j.jpg', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
cv2.imshow('j',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
膨胀 Dilation
膨胀操作正好与腐蚀相反。这里,如果内核下至少有一个像素是“1”,那么该像素元素就是“1”。因此,它增加了图像中的白色区域,或则说增加了前景目标对象的尺寸大小。通常情况下,在去除噪声以后,在腐蚀操作之后就是膨胀。因为,腐蚀消除了白色的噪音,但它也缩小了我们的前景物体,所以我们需要扩大回它。因为当噪音消失了,原本应该存在的白色面积也不会自主回来。而且膨胀在连接物体的破碎部分时也很有用。
import cv2
import numpy as np
img = cv2.imread('j.jpg', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.dilate(img, kernel, iterations=1)
cv2.imshow('j',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
开运算
先进行腐蚀,再进行膨胀就叫做开运算。 通常情况下,含有噪声的图像二值化后,得到的边界是不平滑的,物体区域具有一些错判的孔洞,背景区域散布着一些小的噪声物体。对一个图像先进行腐蚀运算然后再膨胀的操作过程称为开运算,它可以消除细小的物体、在纤细点处分离物体、平滑较大物体的边界时不明显的改变其面积。
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
结果:
闭运算
先膨胀再腐蚀。它经常被用来填充前景物体中的小洞,或者前景物体上面的小黑点。
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
结果:
形态学梯度
其实就是一幅图像膨胀和腐蚀的差别。
结果看上去就像前景物体的轮廓。
import cv2
import numpy as np
img = cv2.imread('j.jpg', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('j',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
礼帽 Top Hat
原始图像与开运算之后得到的图像的差。下面的例子是用一个 9x9 的核进行礼帽操作的结果。
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
结果:
黑帽 Black Hat
进行闭运算之后得到的图像与原始图像的差。
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
结构化元素 Structuring Element
在Numpy 的帮助下,我们可以手动创建一个结构化元素。它是矩形的形状。但是在某些情况下,我们可能需要椭圆/圆形形状的内核。所以为此,OpenCV 专门有一个函数,cv2.getStructuringElement ()。我们只需要确定内核的形状和大小,就可以得到所需的内核。
如果要得到长方形的核,我们导入想要的形状和大小,代码如下:
import cv2
import numpy as np
# 矩形/长方形
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
print(kernel)
# 得到结果如下
[[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]]
# 椭圆
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
print(kernel)
# 得到结果如下
[[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]]
# 十字形 Cross-shaped Kernel
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
print(kernel)
# 得到结果如下
[[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]]