分水岭算法将图像比喻为地理学上的地形表面,实现图像分割,该算法十分有效。本节简要介绍其原理。部分借鉴知乎里的资料。
文章主要借鉴知乎答主程序员阿德的回答以及OpenCV官网分水岭算法的资料。
分水岭(Watershed)是基于地理形态的分析的图像分割算法,模仿地理结构(比如山川、沟壑,盆地)来实现对不同物体的分类。
分水岭算法中会用到一个重要的概念——测地线距离。
测地线距离(Geodesic Distance)
测地线距离就是地球表面两点之间的最短路径(可执行路径)的距离,在图论中,Geodesic Distance 就是图中两节点的最短路径的距离,这与平时在几何空间通常用到的 Euclidean Distance(欧氏距离),即两点之间的最短距离有所区别。
在下图中,两个黑点的 Euclidean Distance 是用虚线所表示的线段的长度d15,而 Geodesic Distance 作为实际路径的最短距离,其距离应为沿途实线段距离之和的最小值,即:d12+d23+d34+d45
在三维曲面空间中两点间的测地距离就是两点间沿着三维曲面的表面走的最短路径。
分水岭算法
图像的灰度空间很像地球表面的整个地理结构,每个像素的灰度值代表高度。其中的灰度值较大的像素连成的线可以看做山脊,也就是分水岭。其中的水就是用于二值化的gray threshold level,二值化阈值可以理解为水平面,比水平面低的区域会被淹没,刚开始用水填充每个孤立的山谷(局部最小值)。
当水平面上升到一定高度时,水就会溢出当前山谷,可以通过在分水岭上修大坝,从而避免两个山谷的水汇集,这样图像就被分成2个像素集,一个是被水淹没的山谷像素集,一个是分水岭线像素集。最终这些大坝形成的线就对整个图像进行了分区,实现对图像的分割。
在该算法中,空间上相邻并且灰度值相近的像素被划分为一个区域。
分水岭算法的整个过程:
- 把梯度图像中的所有像素按照灰度值进行分类,并设定一个测地距离阈值。
- 找到灰度值最小的像素点(默认标记为灰度值最低点),让threshold从最小值开始增长,这些点为起始点。
- 水平面在增长的过程中,会碰到周围的邻域像素,测量这些像素到起始点(灰度值最低点)的测地距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。
- 随着水平面越来越高,会设置更多更高的大坝,直到灰度值的最大值,所有区域都在分水岭线上相遇,这些大坝就对整个图像像素的进行了分区。
整个过程可以查看下面这个动图:
用上面的算法对图像进行分水岭运算,由于噪声点或其它因素的干扰,可能会得到密密麻麻的小区域,即图像被分得太细(over-segmented,过度分割),这因为图像中有非常多的局部极小值点,每个点都会自成一个小区域。
其中的解决方法:
- 对图像进行高斯平滑操作,抹除很多小的最小值,这些小分区就会合并。
- 不从最小值开始增长,可以将相对较高的灰度值像素作为起始点(需要用户手动标记),从标记处开始进行淹没,则很多小区域都会被合并为一个区域,这被称为基于图像标记(mark)的分水岭算法。
下面三个图分别是原图,分水岭过分割的图以及基于标记的分水岭算法得到的图:
其中标记的每个点就相当于分水岭中的注水点,从这些点开始注水使得水平面上升,但是如上图所示,图像中需要分割的区域太多了,手动标记太麻烦,我们可是使用距离转换的方法进行标记,OpenCV中就是使用的这种方法。