传统图像分割——分水岭算法(watershed)

传统图像分割——分水岭算法(watershed)



前言

本篇文章主要梳理分水岭算法的原理,不涉及编程实现
一些经典的分水岭算法文献:

  • [1] Vincent L, Soille P. Watersheds in digital spaces: an efficient algorithm based on immersion simulations[J]. IEEE Transactions on Pattern Analysis & Machine Intelligence, 1991, 13(06): 583-598.
  • [2] Roerdink J B T M, Meijster A. The watershed transform: Definitions, algorithms and parallelization strategies[J]. Fundamenta informaticae, 2000, 41(1, 2): 187-228.
  • [3] Najman L, Schmitt M. Watershed of a continuous function[J]. Signal Processing, 1994, 38(1): 99-112.

Matlab代码可参考使用教程:

  • https://ww2.mathworks.cn/help/images/marker-controlled-watershed-segmentation.html?s_tid=gn_loc_drop

一、什么是分水岭算法?

传统分水岭算法是一种基于拓扑理论的形态学分割方法。通常在基于形态学分割的方法中,会将图片视作地形表面,将图片的每一个灰度级与等高线相对应。由此,图片的每一个局部最小值都会有一个影响区域(influence zone)这些影响区域的边界被称为“分水岭”(相当于是寻找波峰线)这样做的好处在于对于图片梯度的估计非常直接,便于寻找图像的梯度波峰,用于分割。
下图所示为分水岭的一维示意图。更直观一点来讲,首先戳漏每一个局部最小值点,然后水从下到上漫延会逐渐淹没 B V i BV_i BVi这些影响区域(图(a),也被称为吸水盆地,注意这些不同的吸水盆地内水的高度是一致的);而随着水位继续上涨中间的小峰值也会被淹没,为了不让两个不同的影响区域合并会建立一个水坝(图(b)中Barrage),这些水坝就是“地形图”的分水岭,也可以想象为图形的边缘。
分水岭算法一维示意图
而对于图像分割任务这种二维的情况,分水岭更难获取,二维的情况如下图所示(分水岭为图中Dam)
在这里插入图片描述


二、经典的分水岭求解算法

1.定义

  • 测地线距离(geodesic distance):对于一个集合 A A A a a a, b b b A A A中的两个元素,则定义在 A A A中连接 a a a b b b的路径长度的最小值为测地线距离,记作 d A ( a , b ) d_A(a,b) dA(a,b)。具体来讲,如下图所示两个黑点之间的测地线距离为 d 12 + d 23 + d 34 + d 45 d_{12}+d_{23}+d_{34}+d_{45} d12+d23+d34+d45。在三维曲面空间中两点间的测地距离就是两点间沿着三维曲面的表面走的最短路径。
    在这里插入图片描述

  • 测地线影响区域(geodesic influence zone):对于 A A A中的一个点 B i B_i Bi,所有与点 B i B_i Bi的测地线距离小于距离其他点 B j B_j Bj距离的点的集合,即 i z A ( B i ) = { p ∈ A , ∀ j ∈ [ 1 : i − 1 , i + 1 : k ] , d A ( p , B i ) < d A ( p , B j ) } iz_A(B_i)=\{p \in A,\forall j \in [1:i-1,i+1:k],d_A(p,B_i)<d_A(p,B_j)\} izA(Bi)={pA,j[1:i1,i+1:k],dA(p,Bi)<dA(p,Bj)}

  • 集水盆地(catchment basins):对于数值图像 I I I,定义 h m i n h_{min} hmin是图像 I I I最小的灰度级, T h ( I ) T_{h}(I) Th(I)是图像 I I I中所有灰度级小于等于 h h h的像素点, M i n h Min_{h} Minh是图像 I I I在灰度级 h h h处区域最小值的集合,进而可以通过递归求解得到集合 X h m a x X_{h_{max}} Xhmax X h m i n = T h m i n ( I ) X_{h_{min}}=T_{h_{min}}(I) Xhmin=Thmin(I) ∀ h ∈ [ h m i n , h m a x − 1 ] , X h + 1 = M i n h + 1 ∪ I Z T h + 1 ( I ) ( X h ) \forall h\in [h_{min},h_{max}-1],X_{h+1}=Min_{h+1}\cup IZ_{T_{h+1}(I)}(X_h) h[hmin,hmax1],Xh+1=Minh+1IZTh+1(I)(Xh)

2.算法流程

  • 首先,把梯度图像中所有的像素按照灰度值分类,并设定一个测地线距离阈值
  • 其次,找到灰度值最小的像素点(即 h m i n h_{min} hmin),让阈值从最小值开始增长( h m i n + 1 h_{min}+1 hmin+1,…, h m a x h_{max} hmax),在增长的过程中计算 h m i n h_{min} hmin与像素点的测地线距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。

示意图如下[4]
在这里插入图片描述

[4]摘自https://zhuanlan.zhihu.com/p/67741538
[5]一个讲的比较清晰的视频:https://www.bilibili.com/video/BV1fk4y167Gv?spm_id_from=333.337.search-card.all.click&vd_source=4242990e0fbe2c9c04876ca373dbce12


总结

可以看到传统分水岭算法计算量大,并且阈值的选取与灰度级的数量都会影响到分割效果,另外分水岭算法处理复杂图像的效果可能会差。

  • 21
    点赞
  • 127
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分水岭算法是一种基于图像的分割方法,它可以将图像分成若干个不同的区域。下面是使用OpenCV库中的分水岭算法实现图像分割的Python代码示例: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 灰度化处理 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 对灰度图像进行阈值处理 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) # 寻找前景区域 dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0) # 找到未知区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) # 标记分水岭 ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown==255] = 0 # 进行分水岭变换 markers = cv2.watershed(img, markers) # 给分割后的区域上色 img[markers == -1] = [255, 0, 0] # 显示分割结果 cv2.imshow('Segmented Image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在这个代码中,首先读入图像,并将其转换为灰度图像。然后对灰度图像进行阈值处理,得到二值图像。接下来对二值图像进行开运算操作,以去除图片中的噪声。然后对开运算后的图像进行膨胀操作,以找到图像的背景。接着使用距离变换算法找到前景区域,并将其与背景区域合并,得到分水岭算法需要的标记。最后进行分水岭变换并给分割后的区域上色,即可得到图像分割的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值