这节课小木给大家来介绍一下啥叫分水岭算法。书上写着,算法叫做分水岭是因为它里面有水的概念。我们把图像的低密度区域想象成山谷,图像高密度区域我们想象成山峰。接下来我们往山谷里面注水,然后这些水在山峰之间开始汇聚,等一开始汇聚,我们就用一个水坝给阻挡了,阻挡的东西就叫做分割线。我们最后把所有水坝挑出来,作为图像分割的依据。具体的推导过程我下几节课会给大家讲解,这节课还是一样,教的是怎么用。
首先,我们导入一张图片:
图1
还是小熊。如果大家觉得烦了的话,不要着急,因为我们讲到人脸识别的时候,我会换成本人的帅照的,哈哈哈哈哈哈!
接下来我们把图片转换为灰度图:
图2
然后我们利用大津算法把灰度图二值化处理。这里简单说一下啥叫大津算法。它有一个优化函数,然后我们从1这个数字开始,把大于1的分为一组,小于等于1的分为另一组。我们把所有组数据带入优化函数中,得到一个数据。然后我们把1+1=2,然后把大于2的分为1组,其余的分为另一组,再算得到一个优化数据。最后我们会得到254组优化数据,我们看一眼哪个值最优就选哪个值作为二值化的阈值。
图3
我们二值化之后,我们进行一下先开后闭运算来去除噪声。
图4
之后,我们膨胀操作,提取部分的背景区域
图5
背景提取之后,我们还有前景区域。我们运用距离变换法莱提取。在我们腐蚀膨胀后的图3中,越是远离背景区域的边界点越可能是前景。我们应用一个阈值来进行选择,一般选取CV_DIST_L2,也就是欧氏距离(直角坐标点之间的距离),还有一个参数是蒙版选择,数值为3,也就是一个,也就是一个3*3的蒙版。具体的算法细节流程我在这里面不介绍,等下次课统一介绍,以免大家看着懵B。我们把腐蚀膨胀得到的图片,也就是图3,带入到距离变换算法中,计算出可能的前景。
图6
在前后景的计算完毕后,我们看图5和图6会发现,背景和前景有好多重合的部分,那么我们需要去除重合的部分。方法是用背景-前景。就是把背景的矩阵里面,既在背景中,又在前景中的地方,也就是它们的交集作为未知的区域。这样背景中的重合部分就被去掉了。最后区分出来的背景和前景如下图所示。
图7
因为前景部分有些是相连的有些是不相连的,所以我们设定刚才我们说的水坝,把所有的前景图片给分割开来,并且将前景的值设定为-1。
接着我们把背景值设定为1,最后把它们的交集设定为0。
设定之后,我们就开始注水了。往前景注水,也就是为-1的地方注水。水满了的区域就是我们的前景了。
代码如下:
#导入类库
import numpy as np
import cv2
from matplotlib import pyplot as plt
#导入图片
img = cv2.imread('D:/xiaomu/opencv1-1.png')
#转换为灰度图
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#二值化处理
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 去除噪声
kernel = np.ones((5,5))
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel)
opening=cv2.morphologyEx(opening,cv2.MORPH_CLOSE,kernel)
#提取部分背景区域
sure_bg = cv2.dilate(opening,kernel,iterations=5)
#提取部分前景区域
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,3)
ret, sure_fg = cv2.threshold(dist_transform,0.1*dist_transform.max(),255,0)
cv2.imshow("orgin",sure_fg)
#找到前景背景的交集
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)
#画水坝
ret, markers = cv2.connectedComponents(sure_fg)
#cv2.imshow("orgin",markers)
#令背景为1
markers = markers+1
#令未知区域为0
markers[unknown==255] = 0
#注水
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]
#显示图像
plt.imshow(img)
plt.show()
#等待按键退出
cv2.waitKey()
cv2.destroyAllWindows()
结果如下所示:
被红色线圈包裹的地方就是前景,我们这张图用分水岭算法的话,需要调整的参数太多了,很难实现,所以用GRABCUT算法才是解决问题的最好算法。
下一节我们讲讲这两种方法是如何实现的。
———————————————
如果对我的课程感兴趣的话,欢迎关注小木希望学园-微信公众号:
mutianwei521
也可以扫描二维码哦!