【分水岭算法实现过程】

在做项目中用到了有种子像素的图像分割问题,找到了古老的分水岭算法,看了很多博客,都是直接调用了opencv的函数,对原算法的原理实现与原理解释的很不到位。因此,研究了opencv中分水岭函数的实现原理,参考了阿里云开发者麦克老狼的博客。

原始图像和Mark图像,它们的大小都是32*32,分水岭算法的结果是得到两个连通域的轮廓图。

   【分水岭算法实现过程】_第1张图片

 

初始的mark图像数据如下,黄色的部分为我们的第一个mark区域,值为255,用来标记背景区域,第二个区域为褐红色的区域,值为128,第三个绿色的区域,值为64

【分水岭算法实现过程】_第2张图片

 opencv分水岭算法描述如下:

初始化mark矩阵,生成最初的注水区域。

1.设置mark图像的边框值为-1(标记背景区域)

2. 标记每个mark区域的边界为-2(初始填充点)

3. 对于mark图像一个像素值,如果它本身值为0,但上下左右四邻域有一个像素值不为0,则把该点按照(最小邻域灰度差值)放入相应的队列。

      举例说明:如下图像素点,它的mark值为0,但左和上像素值不为0,此时,我们求原始图像中对应像素的灰度差值,计算方式如下面公式,其中I原图像的灰度值,彩色图像为三个颜色值,OpenCV中使用三个通道差分的最大值,下标L表示左,R表示右,T表示上,B表示下,abs表示取绝对值

min(abs(I-IL),abs(I-IT)abs(I-RR),abs(I-IB)

【分水岭算法实现过程】_第3张图片

 上图中指定的像素,它的高度值显然为0,所以我们把(22)点放入高度为0的队列中(总共有256个队列,对应0-255的高度)

【分水岭算法实现过程】_第4张图片

    初始化阶段完成后,我们得到下面的mark图,并把-2对应的边界像素点,按照其对应的灰度差值放入相应的队列。

【分水岭算法实现过程】_第5张图片  之后就进入了递归注水过程,递归过程描述如下:

for(; ; )

{

    1、从0255扫描灰度差值队列,找到一个像素,则弹出该标记,并退出扫描。从低处填充,邻域像素的高度用与已标记点的灰度差表示,故优先填充所有种子点差值最小的像素。

    2、如果该像素的四邻域中存在两个不同的非0值,表示该点为两个注水盆地的边缘,即分水岭线,在mark图像中标记该点为-1。(两个区域的交汇处,标记为区域之间的分界线)

3、扫描该点的四邻域,是否存在为0mark域,存在的话这把该邻域点按照与该点的灰度差值,放入相应的队列。

4、直到队列中无像素,退出。

}

经过上述的递归过程,最后我们得到的mark图像如下所示,其中绿色格子的-1即为所有的分水岭边界: 

【分水岭算法实现过程】_第6张图片

上述递归过程总是从最小的灰度差0到最大255扫描的,因此总能够保证与已标记像素灰度差最小的邻域像素参与标记。 

参考:

OpenCV学习(9) 分水岭算法(3)-阿里云开发者社区 (aliyun.com)

你可能感兴趣的:(图像处理,算法,opencv,图像处理)