
目标
•学习功能: cv2.watershed()
原理
任何灰度图像都可以看作是一个拓扑平面,灰度值高的区域可以被视为山峰,灰度值低的区域可以被视为山谷. 我们在每个山谷中填充不同颜色的水. 随着水位的上升,不同山谷中的水汇合并汇合. 为了防止不同山谷的水汇合,我们需要在水汇合处修建水坝. 不断灌溉和修建水坝,直到所有山峰都被淹没为止. 我们建造的水坝就是图像的分割. 这是分水岭算法背后的原理.
但是这种方法通常会导致过度分割,这是由图像中的噪声或其他不规则因素引起的. 为了减少这种影响,OpenCV使用基于蒙版的分水岭算法. 在此算法中,我们需要设置哪些谷点将收敛而哪些谷点不会收敛. 这是一个交互式图像分割. 我们要做的就是标记我们知道的不同对象. 如果一个

该区域必须是前景或对象,因此请使用颜色(或灰度值)标签对其进行标记. 如果某个区域绝对不是对象而是背景,则使用另一个颜色标签. 不能确定为前景或背景的其余区域标记为0. 这是我们的标签. 然后实现分水岭算法. 每次灌溉时,我们的标签都会更新,并且当两个不同颜色的标签相遇时,我们会建立一个银行
大坝,直到所有峰都被淹没,最后我们得到的边界物体(坝)的值为-1.
代码
在下面的示例中,我们将使用距离变换和分水岭算法将对象彼此分割.
如下所示,这些靠在一起. 即使您使用阈值运算,它们仍然是彼此相邻的.


我们首先找到这些的近似估计值,然后使用Otsu的二值化方法.
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('image/coins.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
结果图:

现在,我们要消除图像中的所有白噪声,这需要使用形态学中的open操作. 为了去除物体上的小孔,我们需要使用形态封闭操作. 因此,我们现在知道,靠近对象中心的区域必须是前景,而远离对象中心的区域必须是背景. 无法确定的区域是之间的边界.
因此,我们必须提取必须为的区域. 蚀刻可以去除边缘像素. 其余的肯定可以是. 当之间没有接触时,此操作有效. 但是因为彼此接触,所以我们还有另一个更好的选择: 距离变换加上合适的阈值. 接下来,我们需要找到绝对不是的区域. 这需要扩展操作. 扩张可以将对象的边界扩展到背景中. 这样,在处理边界区域时,我们可以知道这些区域必须是前景,而这些背景必须是背景.


我们不知道如何区分其他地区. 这就是分水岭算法的作用. 这些区域通常是前景和背景的交界处(或两个前景的交界处). 我们称这个边界. 通过从绝对是背景的区域中减去绝对是前景的区域来获得边界区域.
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, 1, 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)
如结果所示,在阈值化后的图像中图像分割c语言,我们得到了绝对是的区域,并且也被分割. (在某些情况下,您可能只需要分割前景而无需将对象彼此相邻. 此时图像分割c语言,无需使用距离变换. 腐蚀就足够了. 当然,腐蚀也可以用于提取物体. 前景肯定是Area. )

现在我们知道背景和是什么,我们可以创建标签(与原始图像大小相同且数据类型为in32的数组),并标记其中的区域. 对于我们确定了分类的区域(前景或背景),请使用不同的正整数标签;对于不确定的区域,请使用0标签. 我们可以使用功能cv2.connectedComponents()来实现. 它将背景标记为0,其他对象将标记为从1开始的正整数.

但是,我们知道如果背景标记为0,则分水岭算法会将其视为未知区域. 所以我们想用不同的整数来标记它们. 不确定区域(未知区域由cv2.connectedComponents函数的输出中的unknown定义)标记为0.
ret,markers1 = cv2.connectedComponents(sure_fg) markers = markers1 + 1 markers[unknown == 255] = 0
结果使用JET颜表示. 深蓝色区域是未知区域. 的区域必须用不同的颜色标记. 该区域的其余部分是用浅蓝色标记的背景. 标签现在准备就绪.
最后一步: 实现分水岭算法. 标签图像将被修改,边界区域的标记将变为-1.
markers3 = cv2.watershed(img, markers) img[markers3 == -1] = [255,0,0]
结果如下. 一些的边界分割得很好,而某些的边界分割得不好.

参考: Opencv官方中文版(对于Python)
以上是本文的全部内容. 希望对大家的学习有所帮助. 我也希望每个人都支持该脚本主页.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-158803-1.html
喜欢刘诺英的歌声
祖国呀