但是这种方法通常都会得到过度分割的结果,这是由噪声或者图像中其他不规律的因素造成的。为了减少这种影响,OpenCV 采用了基于掩模的分水岭算法,在这种算法中我们要设置那些山谷点会汇合,那些不会。这是一种交互式的图像分割。我们要做的就是给我们已知的对象打上不同的标签。如果某个区域肯定是前景或对象,就使用某个颜色(或灰度值)标签标记它。如果某个区域肯定不是对象而是背景就使用另外一个颜色标签标记。而剩下的不能确定是前景还是背景的区域就用 0 标记。这就是我们的标签。然后实施分水岭算法。每一次灌水,我们的标签就会被更新,当两个不同颜色的标签相遇时就构建堤坝,直到将所有山峰淹没,最后我们得到的边界对象(堤坝)的值为 -1。
27.1 代码
下面的例子中我们将就和距离变换和分水岭算法对紧挨在一起的对象进行分割。
如下图所示,这些紧挨在一起。就算你使用阈值操作,它们任然是紧挨着的。


我们从找到的近似估计开始。我们可以使用 Otsu's 二值化。
结果

现在我们要去除图像中的所有的白噪声。这就需要使用形态学中的开运算。
为了去除对象上小的空洞我们需要使用形态学闭运算。所以我们现在知道靠近对象中心的区域肯定是前景,而远离对象中心的区域肯定是背景。而不能确定的区域就是之间的边界。
所以我们要提取肯定是的区域。腐蚀操作可以去除边缘像素。剩下就可以肯定是了。当之间没有接触时,这种操作是有效的。但是由于之间是相互接触的,我们就有了另外一个更好的选择:距离变换再加上合适的阈值。接下来我们要找到肯定不是的区域。这是就需要进行膨胀操作了。膨胀可以将对象的边界延伸到背景中去。这样由于边界区域被去处理,我们就可以知道那些区域肯定是前景,那些肯定是背景。如下图所示。

剩下的区域就是我们不知道该如何区分的了。这就是分水岭算法要做的。
这些区域通常是前景与背景的交界处(或者两个前景的交界)。我们称之为边界。从肯定是不是背景的区域中减去肯定是前景的区域就得到了边界区域。
如结果所示,在阈值化之后的图像中,我们得到了肯定是的区域,而且之间也被分割开了。(有些情况下你可能只需要对前景进行分割,而不需要将紧挨在一起的对象分开,此时就没有必要使用距离变换了,腐蚀就足够了。当然腐蚀也可以用来提取肯定是前景的区域。)

现在知道了那些是背景那些是了。那我们就可以创建标签(一个与原图像大小相同,数据类型为 in32 的数组),并标记其中的区域了。对我们已经确定分类的区域(无论是前景还是背景)使用不同的正整数标记,对我们不确定的区域使用 0 标记。我们可以使用函数 cv2.connectedComponents()来做这件事。它会把将背景标记为 0,其他的对象使用从 1 开始的正整数标记。
但是,我们知道如果背景标记为 0,那分水岭算法就会把它当成未知区域了。所以我们想使用不同的整数标记它们。而对不确定的区域(函数cv2.connectedComponents 输出的结果中使用 unknown 定义未知区域)标记为 0。
结果如下。有些的边界被分割的很好,也有一些之间的边界分割的不好。

Now our marker is ready. It is time for final step, apply watershed. Then marker image will be modified. The boundary region will be marked with -1.
See the result below. For some coins, the region where they touch are segmented properly and for some, they are not.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-70909-5.html
也许美国会派兵抓你回美国
在不经我大中国同意的情况下派军舰前来
66666666666666666