导读
在使用opencv做图像处理的时候,我们经常会需要用到一些基础的图像形态学操作腐蚀 、膨胀 。通过这些基本的形态学操作我们可以实现去噪以及图像的切割等。
形态学变换是基于图像形状的基础变换,它只能在二值图像 上做处理。形态学操作需要两个输入,输入图像和structuring element或kernel,structuring element和kernel决定我们做何种形态学处理的操作。腐蚀 和膨胀 是形态学处理的基础操作,而开运算 和闭运算 是基于腐蚀 和膨胀 的变种操作。下面我们就介绍一下如何在实际中应用这些操作
注意 :在做图像的形态学处理的时候,需要对图像做二值化,且需要将处理的像素值改为255,因为图像的形态学处理操作都是基于白色像素 上处理的。 后面我们基于上面这张图片来做处理
腐蚀
import cv2
import numpy as np
import matplotlib.pyplot as plt
img_path = "img/demo.jpg"
img = cv2.imread(img_path)
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_,binary_img = cv2.threshold(gray_img,128,255,cv2.THRESH_BINARY_INV)
erode_kernel = np.ones((3,3),np.uint8)
erode_img =cv2.erode(binary_img,erode_kernel)
plt.figure()
plt.subplot(1,2,1)
plt.imshow(cv2.cvtColor(binary_img,cv2.COLOR_BGR2RGB))
plt.title("binary_img")
plt.subplot(1,2,2)
plt.imshow(cv2.cvtColor(erode_img,cv2.COLOR_BGR2RGB))
plt.title("erode_img")
plt.show()
通过上面图片的腐蚀 操作可以发现,白色的文字都完全被侵蚀了,除此之外我们还发现图片右下角白色区域周围的白色噪点也被侵蚀了。
下面我们来分析一下图像的腐蚀操作究竟发生了什么,下面我们看看这个例子
binary_img = np.array([ [0, 0, 0, 0, 0],
[0,255,255,255,0],
[0,255,255,255,0],
[0,255,255,255,0],
[0, 0, 0, 0, 0]],np.uint8)
erode_kernel = np.ones((3,3),np.uint8)
erode_img =cv2.erode(binary_img,erode_kernel)
print(erode_img)
"""
[[ 0 0 0 0 0]
[ 0 0 0 0 0]
[ 0 0 255 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 0]]
"""
通过上面的例子发现,经过3x3的kernel之后,最终只保留了中心的255像素,周边的255都变成了0。在进行腐蚀操作的时候,就是通过kernel大小的卷积在原图像上滑动,只有当kernel范围内的像素全为255时输出才为255,否则输出为0,所以kernel越大最终白色像素保留的会越少。
膨胀
dilate_kernel = np.ones((3,3),np.uint8)
dilate_img =cv2.dilate(binary_img,dilate_kernel)
plt.figure()
plt.subplot(1,2,1)
plt.imshow(cv2.cvtColor(binary_img,cv2.COLOR_BGR2RGB))
plt.title("binary_img")
plt.subplot(1,2,2)
plt.imshow(cv2.cvtColor(dilate_img,cv2.COLOR_BGR2RGB))
plt.title("dilate_img")
plt.show()
图像经过膨胀 之后,白色像素的范围变大了。在做膨胀的时候,只要当kernel范围内的像素有255时输出就为255,只有kernel范围内全为0时才输出0。
开闭运算
开运算其实就是先通过腐蚀操作后面再进行膨胀,闭运算和开运算恰好相反先通过膨胀操作后面再进行腐蚀。
kernel = np.ones((3,3),np.uint8)
open_img =cv2.morphologyEx(binary_img,cv2.MORPH_OPEN,kernel)
close_img = cv2.morphologyEx(binary_img,cv2.MORPH_CLOSE,kernel)
通过结合腐蚀 和膨胀 运算我们可以去除图像上的白色噪点
梯度运算
梯度运算等价于膨胀运算-腐蚀运算
kernel = np.ones((3,3),np.uint8)
gradient_img = cv2.morphologyEx(binary_img,cv2.MORPH_GRADIENT,kernel)
梯度运算主要是用来保留图像的轮廓
Top Hat和Black Hat运算
Top Hat运算等价于原始图像 - 开运算,Black Hat运算等价于闭运算 - 原始图像
kernel = np.ones((3,3),np.uint8)
tophat_img = cv2.morphologyEx(binary_img,cv2.MORPH_TOPHAT,kernel)
blackhat_img = cv2.morphologyEx(binary_img,cv2.MORPH_BLACKHAT,kernel)
Structuring Element
前面我们使用的都是方形的kernel ,除此之外我们也可以使用矩形的kernel 来实现我们的目的,例如在做文本的行分割时,我们需要将文字的行连在一起以检测出文本行的位置,此时我们就可以采用矩形的kernel来达到我们的目的。 opencv库还提供了椭圆的kernel 以及圆形的kernel
ellipse_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
print(ellipse_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_kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
print(cross_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]]
"""
|