形态变换是一些基于图像形状的简单操作。通常在二进制图像上执行。它需要两个输入,一个是我们的原始图像,第二个是决定操作性质的结构元素或内核。两种基本的形态学算子是侵蚀和膨胀。然后,它的变体形式(如“打开”,“关闭”,“渐变”等)也开始起作用
二值形态学
一、腐蚀
对图像的边缘进行侵蚀,原始图像中的一个像素(无论是1还是0)只有当内核下的所有像素都是1时才被认为是1,否则它就会被侵蚀(变成0)
这种方法是对物体边缘向内部收缩,并消除一些离群噪点
#kernel为卷积核
erosion = cv.erode(img,kernel,iterations = 1)
二、扩张
它与侵蚀正好相反,对图片的边缘。如果内核下的至少一个像素为“ 1”,则像素元素为“ 1”。因此,它会增加图像中的白色区域或增加前景对象的大小。通常,在消除噪音的情况下,腐蚀后会膨胀。因为腐蚀会消除白噪声,但也会缩小物体
这种方法是对物体边缘向外扩张,并连接一些距离较近的离群点
dilation = cv.dilate(img,kernel,iterations = 1)
三、开启
对图像先进行腐蚀操作,再进行扩张操作,它对于消除噪音很有用
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
四、关闭
对图像先进行扩张操作,在进行腐蚀操作,在关闭前景对象内部的小孔或对象上的小黑点时很有用。
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
对如下图进行操作:
import cv2
import numpy as np
img = cv2.imread(r'123.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
dilation = cv2.dilate(img,kernel,iterations = 1)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) #这里也可以对dilation进行erode运算
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) #同理可对erode进行dilation运算
展示效果:
cv2.imshow("img",erosion )
cv2.waitKey()
cv2.imshow("img",dilation )
cv2.waitKey()
cv2.imshow("img",opening )
cv2.waitKey()
cv2.imshow("img",closing )
cv2.waitKey()
五. 形态学梯度
梯度用于刻画目标边界或边缘位于图像灰度级剧烈变化的区域,形态学梯度根据膨胀或者腐蚀与原图作差组合来实现增强结构元素领域中像素的强度,突出高亮区域的外围。计算图像的形态学梯度是形态学重要操作,常常将膨胀和腐蚀基础操作组合起来一起使用实现一些复杂的图像形态学梯度
计算的梯度常见如下四种:
- 基本梯度
————基本梯度是用膨胀后的图像减去腐蚀后的图像得到差值图像,称为梯度图像也是OpenCV中支持的计算形态学梯度的方法,而此方法得到梯度有被称为基本梯度。 - 内部梯度
————是用原图像减去腐蚀之后的图像得到差值图像,称为图像的内部梯度。 - 外部梯度
————是用图像膨胀之后再减去原来的图像得到的差值图像,称为图像的外部梯度。 - 方向梯度
————方向梯度是使用X方向与Y方向的直线作为结构元素之后得到图像梯度,用X方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为X方向梯度,用Y方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为Y方向梯度。
以下为基本梯度的使用方式
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow("img",gradient )
cv2.waitKey()
六、 顶帽
它是输入图像和图像开运算之差
kernel = np.ones((5,5),np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
七、黑帽
这是输入图像和图像闭运算之差
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
八、不同形状的卷积核
我们上面使用的卷积核均为正方形的卷积核,我们也可能需要圆形,椭圆等其他卷积核,我们可以通过numpy来实现我们需要的卷积核。当然也可以使用OpenCV自带的卷积核生成器cv.getStructuringElement(),不过由于使用需要记住这些名字,我还是推荐大家手动使用numpy实现
# 矩形内核
>>> 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)