腐蚀与膨胀
- 前言
- 膨胀
- 腐蚀
- 开运算与闭运算
- 礼帽与黑帽
- 运用膨胀和腐蚀获得图像轮廓
前言
有些时候图片上会有一些划痕或者污渍,会影响图片的质量,假设我有一张写有“艾醒”的图片,但是有花花绿绿的划痕和污渍,这时我们就可以运用腐蚀与膨胀消除这些划痕和污渍
膨胀
腐蚀的本质就是白吃黑,即数值较大的(较白的)吃掉数值较小的(较黑的)
我们可以用cv2.dilate进行膨胀,参数为图片,卷积核,膨胀次数
其原理就是在卷积核范围内,如果周围颜色浅的(数值较大的)多,那么当前点就应该是颜色浅的,否则应该是颜色深的
假设我们有一张图片名称为aixing.png
img = cv2.imread('aixing.png')
kernel = np.ones((5,5),np.uint8)
dilate = cv2.dilate(dige_erosion,kernel,iterations = 3)
cv2.imshow('dilate', dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
我们用5x5的卷积核来进行3次膨胀
可以看到虽然划痕和污渍几乎没有了,但是这个图片上的字比之前小不少,为了还原字的大小我们还需要进行腐蚀操作,注意腐蚀操作需要跟膨胀操作卷积核和执行次数相同才能还原之前的大小
腐蚀
腐蚀的本质就是黑吃白,即数值较小的(较黑的)吃掉数值较大的(较白的)
我们可以用cv2.erode进行腐蚀,参数为图片,卷积核,腐蚀次数
其原理就是在卷积核中,如果周围颜色深的(数值较小的)多,那么当前点就应该是颜色深的,否则应该是颜色浅的
我们进行腐蚀
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(dilate,kernel,iterations = 3)
cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
现在我们可以看到划痕和污渍已经去掉了
开运算与闭运算
实际上这两个功能很鸡肋,开运算就是先腐蚀,再膨胀;闭运算就是先膨胀,再腐蚀
opencv中cv2.morphologyEx函数可以实现开闭运算,参数为图片,操作类型,卷积核
操作类型参数
cv2.MORPH_OPEN | cv2.MORPH_CLOSE |
---|---|
开运算 | 闭运算 |
很明显,我们刚刚的问题需要进行闭运算 |
img = cv2.imread('aixing.png')
kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow('closing', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到效果并不好,这是为什么呢,因为闭运算只进行了一次膨胀一次腐蚀,而我们得到的较好的结果是进行了3次膨胀和3次腐蚀
开运算的代码也放在这里,但要说明当前问题并不适合开运算,如果画面背景是偏深色的,我们需要侧重的部分或者文字是偏浅色的较为适合开运算,如果要尝试我们可以将图片反色,如何反色呢?令255减去图片就好了
img = cv2.imread('aixing.png')
kernel = np.ones((5,5),np.uint8)
reverse = 255 - img # 反色
cv2.imshow('opening', reverse)
cv2.waitKey(0)
cv2.destroyAllWindows()
opening = cv2.morphologyEx(reverse, cv2.MORPH_OPEN, kernel)
cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到效果也不好,所以这个函数了解即可。
礼帽与黑帽
没有什么需要解释的,了解下面的操作就可以了
礼帽 = 原始输入-开运算结果
黑帽 = 闭运算-原始输入
#礼帽
img = cv2.imread('aixing.png')
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('tophat', tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()
#黑帽
img = cv2.imread('aixing.png')
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('blackhat ', blackhat )
cv2.waitKey(0)
cv2.destroyAllWindows()
运用膨胀和腐蚀获得图像轮廓
假设我们有这样一个名为yan.jpg的岩元素图标
为了获取它的轮廓,我们先要将他二值化,即进行前几篇文章提到过的阈值操作,很显然我们应该选用cv2.THRESH_BINARY参数
pie = cv2.imread('yan.jpg', cv2.IMREAD_GRAYSCALE)
ret, img = cv2.threshold(pie, 220, 255, cv2.THRESH_BINARY)
cv_show(img, 'threshold')
然后分别进行一次膨胀和一次腐蚀
kernel = np.ones((5,5),np.uint8)
dilate = cv2.dilate(img,kernel,iterations = 1)
erosion = cv2.erode(img,kernel,iterations = 1)
res = np.hstack((dilate,erosion))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
左侧是膨胀,右侧是腐蚀的结果
然后膨胀减去腐蚀
cv2.imshow('res', cv2.convertScaleAbs(dilate-erosion))
cv2.waitKey(0)
cv2.destroyAllWindows()
那么为什么是膨胀减腐蚀呢,因为膨胀的白色的区域多,白色的是非0值,所以实际上白色轮廓曾是膨胀后的一部分