什么是分水岭
它是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
但是这种方法会由于图像中的噪声或其他不规则性因素而导致过度分割的结果。OpenCV实现了一种基于标记的分水岭算法,你可以指定哪些是要合并的谷点,哪些不是。我们所做的是给我们所知道的对象赋予不同的标签(marker)。用一种颜色(或强度)标记我们确定的为前景或对象的区域,用另一种颜色标记我们确定为背景或非对象的区域,最后用0标记我们不确定的区域。然后应用分水岭算法,其将使用我们给出的标签进行更新(填水),对象的边界值将为-1。
代码:
dst.jpgimport cv2
import numpy as np
# Step1. 加载图像
img = cv2.imread('sources/Road.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Step2.阈值分割,将图像分为黑白两部分
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
cv2.imshow("sure_bg", sure_bg)
# 前景区域
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) # DIST_L1 DIST_C只能 对应掩膜为3 DIST_L2 可以为3或者5
ret, sure_fg = cv2.threshold(dist_transform, 0.1 * dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknow = cv2.subtract(sure_bg, sure_fg)
# 连通区域处理
ret, markers = cv2.connectedComponents(sure_fg,connectivity=8) #对连通区域进行标号 序号为 0 - N-1
markers = markers + 1 #OpenCV 分水岭算法对物体做的标注必须都 大于1 ,背景为标号 为0 因此对所有markers 加1 变成了 1 - N
markers[unknow==255] = 0
# 分水岭算法
markers = cv2.watershed(img, markers) #分水岭算法后,所有轮廓的像素点被标注为 -1
print(markers)
img[markers == -1] = [0, 0, 255]
cv2.namedWindow(' dst ', 0)
cv2.imshow("dst", img)
cv2.waitKey(0)
网友评论