数学形态学(Mathematical morphology)是一门 建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:腐蚀和膨胀、开运算和闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换等。
膨胀、腐蚀、开运算和闭运算是数学形态学的四个基本运算,它们在二值图像和灰度图像中各有特点。基于这些运算还可推导和组合成各种数学形态学实用算法,用它们可以进行图像形状和结构的分析和处理,包括图像分割、特征提取、边缘检测、图像滤波、图像增强和恢复等。有关数学形态学更多的介绍,可以查看百度词条:数学形态学。
定义结构元素是数学形态学处理的核心,在OpenCV中可以使用其自带的getStructuringElemet函数,也可以直接使用numpy数组来定义一个结构元素。
先进行腐蚀操作
img = cv2.imread('luotuo.jpg', 0)
# 先对图像进行一个二值化处理
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 用numpy定义结构元素
npKernel = np.uint8(np.zeros((5, 5)))
for i in range(5):
npKernel[2, i] = 1
npKernel[i, 2] = 1
print(npKernel)
# 用OpenCV中的getStructuringElement()函数定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 进行腐蚀操作
npKernel_eroded = cv2.erode(th2, npKernel)
kernel_eroded = cv2.erode(th2, kernel)
cv2.imshow('img', th2)
cv2.imshow('npKernel Eroded Image', npKernel_eroded)
cv2.imshow('kernel Eroded Image', kernel_eroded)
cv2.waitKey(0)
cv2.destroyAllWindows()
[[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]]
Process finished with exit code 0
然后进行膨胀操作
img = cv2.imread('4.jpg', 0)
# 先对图像进行一个二值化处理
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 用numpy定义结构元素
npKernel = np.uint8(np.zeros((5, 5)))
for i in range(5):
npKernel[2, i] = 1
npKernel[i, 2] = 1
# 用OpenCV中的getStructuringElement()函数定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 进行膨胀操作
npKernel_dilated = cv2.dilate(th2, npKernel)
kernel_dilated = cv2.dilate(th2, kernel)
cv2.imshow('img', th2)
cv2.imshow('npKernel Dilated Image', npKernel_dilated)
cv2.imshow('kernel Dilated Image', kernel_dilated)
cv2.waitKey(0)
cv2.destroyAllWindows()
关于图像的腐蚀和膨胀,就两个函数cv2.erode(),cv2.dilate(),都需要传入两个参数,一个是需要处理的二值化图像,第二个是结构元素,返回处理好的图像。
开运算就是指图像先进行腐蚀再膨胀的运算,腐蚀可以使图像外的小点点去掉,再膨胀就可以去除掉图像外的噪声。
# 开运算操作
img = cv2.imread('luotuo.jpg', 0)
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
for i in range(2000): # 添加椒盐噪声
_x = np.random.randint(0, th2.shape[0])
_y = np.random.randint(0, th2.shape[1])
th2[_x][_y] = 255
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.morphologyEx(th2, cv2.MORPH_OPEN, kernel) # 开运算函数
cv2.imshow('th2', th2)
cv2.imshow('morph_open', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
从结果来看,骆驼之外的小白点全部填充为黑色了,去除骆驼之外的白色噪声。
与开运算相反,闭运算是指先进行膨胀运算再进行腐蚀运算,膨胀可以将图像内的小白点去掉,然后把主图像腐蚀回来,实现对图像内噪声的去除。
# 闭运算
img = cv2.imread('luotuo.jpg', 0)
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
for i in range(20000): # 添加椒盐噪声
_x = np.random.randint(0, th2.shape[0])
_y = np.random.randint(0, th2.shape[1])
th2[_x][_y] = 0
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.morphologyEx(th2, cv2.MORPH_CLOSE, kernel)
cv2.imshow('th2', th2)
cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
重点:对图像的膨胀和腐蚀操作是对二值化后的白色图像区域的膨胀和腐蚀。
通过利用对图像的膨胀和腐蚀的组合使用,使得处理后的图像如同提取了物体的轮廓。
# 形态学梯度
img = cv2.imread('luotuo.jpg', 0)
ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((5, 5), np.uint8)
# morphology 形态学
gradient = cv2.morphologyEx(th, cv2.MORPH_GRADIENT, kernel) # morph gradient 形态梯度
cv2.imshow('th', th)
cv2.imshow('gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()
礼帽指的是原始图像与其进行开运算后的图像进行一个差,对于差别之处显示其原有图色。
# 礼帽
img = cv2.imread('4.jpg', 0)
ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((5, 5), np.uint8)
tophat = cv2.morphologyEx(th, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('th', th)
cv2.imshow('tophat', tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()
黑帽指的是原始图像与其进行闭运算后的图像进行一个差,对于差别之处显示原有图色的反颜色。
# 黑帽
img = cv2.imread('4.jpg', 0)
ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((5, 5), np.uint8)
blackhat = cv2.morphologyEx(th, cv2.MORPH_BLACKHAT, kernel) # blackhat
cv2.imshow('th', th)
cv2.imshow('blackhat', blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()