OpenCV分水岭watershed的应用注意

来源:互联网 发布:python 提取文件路径 编辑:程序博客网 时间:2024/06/05 19:15

在VS2010,OpenCV进行分水岭的实现时。我遇到了一个问题:
在做好种子图和背景图后,也无法分隔开同一个背景框内的多个种子点。网上给的方法都是将背景点设置为灰度128,种子点设置为255,其他为0。然后前景背景叠加作为mark图。再调用watershed(原图,蒙版)。
但是,按照这个结果做出来的话,同一个128灰度的区域包围的多个255灰度的种子区域无法被区分开。通过阅读OpenCV源码,我发现了原因。

/*-----划分:如果其4邻域只有一个集水区那就归入其中,如果有多个那就标记为分水岭------*/          if( q[active_queue].first == 0 )    //当前层级处理完或无像素入队,换下一层          {              for( i = active_queue+1; i < NQ; i++ )                  if( q[i].first )    //换这层                      break;              if( i == NQ )   //退出大循环                  break;              active_queue = i;   //下面给这一层的像素分配标号          }          //取一个点          ws_pop( active_queue, mofs, iofs );           m = mask + mofs;    //mask的值          ptr = img + iofs;   //img的值          //4邻域只有一个区域,确定区域归属,要是处在多个集水区,成为分水岭          t = m[-1];          if( t > 0 )            lab = t;          t = m[1];          if( t > 0 )          {              if( lab == 0 )                lab = t;              else if( t != lab )                lab = WSHED;          }          t = m[-mstep];          if( t > 0 )          {              if( lab == 0 )                lab = t;              else if( t != lab )                lab = WSHED;          }          t = m[mstep];          if( t > 0 )          {              if( lab == 0 )                lab = t;              else if( t != lab )                lab = WSHED;          }          assert( lab != 0 );          m[0] = lab;          if( lab == WSHED )              continue;   //继续  

在这一部分可以看出,在设置分水岭位置时,是通过比较上下左右四个点,是否有不为0且不同的两个灰度点,如果有,那么设置为WSHED(-1),也就是分水岭位置。
引用一个比较易懂专业的描述:如果mask图像中该像素的四邻域中存在两个不同的非0值,表示该点为两个注水盆地的边缘,即分水岭线,在mark图像中标记该点为-1;否则在mask图像中标记该点为四邻域中大于0的那个值(如果有多个大于0的值,则按照左右上下的顺序取)。
同理,对于同一个128灰度区域包围的几个不同的种子点区域,他们的灰度值要设置的不同,那样在扩张不同水区域接触的时候才能够分开。
其实,什么前景背景对于watershed函数来说根本就没有区别,就是不同灰度值能够表示不同的注水点。以这些注水点为起点开始分水岭算法的实现,而不是之前所想的128的背景图部分是不动的。

同样需要注意的还有,opencv自带的分水岭算法的涨水方式和传统的涨水方式不同,在一片论文上我看到有对OpenCV分水岭算法进行改进,指出OpenCV分水岭算法在判断下一步对何种像素点进行涨水时,依据的是已经被标记为-2,也就是mark边缘和mark边缘的像素差的绝对值的大小。将其放入q队列(0-255个位置分别记录对应灰度值大小的点的位置)中,再从小到大搜寻q队列,对找到的第一个灰度进行涨水。这个就会导致一些过漫水的问题。
那篇论文名称为:《OpenCV分水岭算法的改进及其在细胞分割中的应用_张羽》,我按照这篇论文中提出的方法进行对源码的修改了,效果也不尽人意,如果哪位看到这篇文章并成功修改,效果也不错,请务必联系我。(如果这篇论文的作者看到了,也请帮助一下我这个初学者,具体应该如何修改。)
以下附上不同灰度种子改前改后的结果

这里写图片描述

这里写图片描述
其实最后的结果也不是很好,很有可能是我种子点的给出以及原图像有点太差。不过意思到位了,大家看懂就行。
错误定义mark图展示
这里写图片描述
这里就是把所有的种子点的像素都设置成了255,就会出现上面第一幅图的结果。也就是没分开。

阅读全文
0 0