Python-OpenCV中的图像处理-形态学转换
形态学转换
- 形态学操作:腐蚀,膨胀,开运算,闭运算,形态学梯度,礼帽,黑帽等
- 主要涉及函数:cv2.erode(), cv2.dilate(), cv2.morphologyEx()
- 原理:形态学操作是根据图像形状进行的简单操作。一般情况下对二值化图像进行的操作。需要输入两个参数,一个是原始图像,第二个被称为结构化元素或核,它是用来决定操作的性质的。两个基本的形态学操作是腐蚀和膨胀。他们的变体构成了开运算,闭运算,梯度等。
腐蚀
就像土壤侵蚀一样,这个操作会把前景物体的边界腐蚀掉(但是前景仍然是白色)。这是怎么做到的呢?卷积核沿着图像滑动,如果与卷积核对应的原图像的所有像素值都是 1,那么中心元素就保持原来的像素值,否则就变为零。这回产生什么影响呢?根据卷积核的大小靠近前景的所有像素都会被腐蚀掉(变为 0),所以前景物体会变小,整幅图像的白色区域会减少。这对于去除白噪声很有用,也可以用来断开两个连在一块的物体等。
python
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('./resource/opencv/image/Morphology_1_Tutorial_Theory_Dilation.png', cv2.IMREAD_GRAYSCALE)
kernel = np.ones((5,5), np.uint8)
erosion = cv2.erode(img, kernel=kernel, iterations=1)
plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('origin'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv2.cvtColor(erosion, cv2.COLOR_BGR2RGB)), plt.title('erode'), plt.xticks([]), plt.yticks([])
plt.show()
膨胀
与腐蚀相反,与卷积核对应的原图像的像素值中只要有一个是 1,中心元素的像素值就是 1。所以这个操作会增加图像中的白色区域(前景)。一般在去噪声时先用腐蚀再用膨胀。因为腐蚀在去掉白噪声的同时,也会使前景对象变小。所以我们再对他进行膨胀。这时噪声已经被去除了,不会再回来了,但是前景还在并会增加。膨胀也可以用来连接两个分开的物体。
python
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 膨胀
img = cv2.imread('./resource/opencv/image/Morphology_1_Tutorial_Theory_Original_Image.png', cv2.IMREAD_GRAYSCALE)
kernel = np.ones((5,5), np.uint8)
dilation = cv2.dilate(img, kernel=kernel, iterations=1)
plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('origin'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv2.cvtColor(dilation, cv2.COLOR_BGR2RGB)), plt.title('dilate'), plt.xticks([]), plt.yticks([])
plt.show()
开运算
先腐蚀再膨胀就叫做开运算。它被用来去除噪声。这里我们用到的函数是 cv2.morphologyEx()
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
闭运算
先膨胀再腐蚀就叫做闭运算。它经常被用来填充前景物体中的小洞,或者前景物体上的小黑点
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
形态学梯度
其实就是一幅图像膨胀与腐蚀的差别,结果看上去就像前景物体的轮廓。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
礼帽
原始图像与进行开运算之后得到的图像的差。下面的例子是用一个 9x9 的核进行礼帽操作的结果。
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
黑帽
进行闭运算之后得到的图像与原始图像的差
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
形态学操作之间的关系
形态学转换
- Opening:
dst = open(src, element) = dilate(erode(src, element), element) - Closing:
dst = close(src, element) = erode(dilate(src, element), element) - Morphological gradient:
dst = morph_grad(src, element) = dilate(src, element) - erode(src, element) - "Top hat":
dst = tophat(src, element) = src - open(src, element) - "Black hat":
dst = blackhat(src, element) = close(src, element) - src
形态学代码例程
python
import numpy as np
import cv2
from matplotlib import pyplot as plt
'''
形态学转换
Opening:
dst = open(src, element) = dilate(erode(src, element), element)
Closing:
dst = close(src, element) = erode(dilate(src, element), element)
Morphological gradient:
dst = morph_grad(src, element) = dilate(src, element) - erode(src, element)
"Top hat":
dst = tophat(src, element) = src - open(src, element)
"Black hat":
dst = blackhat(src, element) = close(src, element) - src
'''
# 开运算
# 先进行腐蚀在进行膨胀叫做开运算。用来去除噪音
# opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
# 闭运算
# 先进行膨胀再进行腐蚀叫做闭运算。用来填充前景物体中的小洞,或者全景上的小黑点。
# closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# 形态学梯度
# 就是一副图像膨胀与腐蚀的差别,结果看上去就像前景物体的轮廓。
# gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
# 礼帽
# 原始图像与进行开运算之后得到的图像的差
# tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
# 黑帽
# 原始图像与进行闭运算之后得到的图像的差
# blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
# 结构化元素
kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)) # 矩形核
kernel_elli = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) # 椭圆核
kernel_cros = cv2.getStructuringElement(cv2.MORPH_CROSS, (5,5)) # 十字核
# 卷积核
# kernel = kernel_rects
# kernel = kernel_elli
# kernel = kernel_cros
kernel = np.ones((5,5), np.uint8)
kernel9x9 = np.ones((15,15), np.uint8)
img_origin = cv2.imread('./resource/opencv/image/Morphology_1_Tutorial_Theory_Dilation.png', cv2.IMREAD_COLOR)
img_gray = cv2.imread('./resource/opencv/image/Morphology_1_Tutorial_Theory_Dilation.png', cv2.IMREAD_GRAYSCALE)
# 开运算 腐蚀=>膨胀
opening = cv2.morphologyEx(img_gray, cv2.MORPH_OPEN, kernel)
# 闭运算 膨胀=>腐蚀
closing = cv2.morphologyEx(img_gray, cv2.MORPH_CLOSE, kernel)
# 梯度 膨胀-腐蚀
gradient = cv2.morphologyEx(img_gray, cv2.MORPH_GRADIENT, kernel)
# 礼帽 原始图像与进行开运算之后得到的图像的差
tophat = cv2.morphologyEx(img_gray, cv2.MORPH_TOPHAT, kernel9x9)
# 黑帽 进行闭运算之后与原始图像的图像的差
blackhat = cv2.morphologyEx(img_gray, cv2.MORPH_BLACKHAT, kernel9x9)
# 腐蚀
erosion = cv2.erode(img_gray, kernel=kernel, iterations=1)
# 膨胀
dilation = cv2.dilate(img_gray, kernel=kernel, iterations=1)
plt.subplot(331), plt.imshow(cv2.cvtColor(img_origin,cv2.COLOR_BGR2RGB), 'gray'), plt.title('origin'), plt.xticks([]), plt.yticks([])
plt.subplot(332), plt.imshow(img_gray, 'gray'), plt.title('gray'), plt.xticks([]), plt.yticks([])
plt.subplot(333), plt.imshow(opening, 'gray'), plt.title('open'), plt.xticks([]), plt.yticks([])
plt.subplot(334), plt.imshow(closing, 'gray'), plt.title('close'), plt.xticks([]), plt.yticks([])
plt.subplot(335), plt.imshow(gradient, 'gray'), plt.title('gradient'), plt.xticks([]), plt.yticks([])
plt.subplot(336), plt.imshow(tophat, 'gray'), plt.title('tophat'), plt.xticks([]), plt.yticks([])
plt.subplot(337), plt.imshow(blackhat, 'gray'), plt.title('blackhat'), plt.xticks([]), plt.yticks([])
plt.subplot(338), plt.imshow(erosion, 'gray'), plt.title('erode'), plt.xticks([]), plt.yticks([])
plt.subplot(339), plt.imshow(dilation, 'gray'), plt.title('dilate'), plt.xticks([]), plt.yticks([])
plt.show()