根据官方文档中的描述,本文参考https://github.com/scikit-image/scikit-image/blob/v0.13.1/skimage/morphology/watershed.py#L134
分水岭算法主要是用于切割存在重复的图像的切割。
Examples -------- The watershed algorithm is useful to separate 重叠 objects. We first generate an initial image with two overlapping circles: >>> x, y = np.indices((80, 80)) >>> x1, y1, x2, y2 = 28, 28, 44, 52 >>> r1, r2 = 16, 20 >>> mask_circle1 = (x - x1)**2 + (y - y1)**2 < r1**2 >>> mask_circle2 = (x - x2)**2 + (y - y2)**2 < r2**2 >>> image = np.logical_or(mask_circle1, mask_circle2) Next, we want to separate the two circles. We generate markers at the maxima of the distance to the background: >>> from scipy import ndimage as ndi >>> distance = ndi.distance_transform_edt(image) >>> from skimage.feature import peak_local_max >>> local_maxi = peak_local_max(distance, labels=image, ... footprint=np.ones((3, 3)), ... indices=False) >>> markers = ndi.label(local_maxi)[0] Finally, we run the watershed on the image and markers: >>> labels = watershed(-distance, markers, mask=image) The algorithm works also for 3-D images, and can be used for example to separate overlapping spheres. """ image, markers, mask = _validate_inputs(image, markers, mask) connectivity, offset = _validate_connectivity(image.ndim, connectivity, offset) # pad the image, markers, and mask so that we can use the mask to # keep from running off the edges pad_width = [(p, p) for p in offset] image = np.pad(image, pad_width, mode='constant') mask = np.pad(mask, pad_width, mode='constant').ravel() output = np.pad(markers, pad_width, mode='constant') flat_neighborhood = _compute_neighbors(image, connectivity, offset) marker_locations = np.flatnonzero(output).astype(np.int32) image_strides = np.array(image.strides, dtype=np.int32) // image.itemsize _watershed.watershed_raveled(image.ravel(), marker_locations, flat_neighborhood, mask, image_strides, compactness, output.ravel(), watershed_line) output = crop(output, pad_width, copy=True) if watershed_line: min_val = output.min() output[output == min_val] = 0 return output
这里先插入一段官方给的例子来说明。
首先采用了np.indice()函数来生成切片索引序列。其函数的具体实现功能,在这篇文章中可以看到。https://blog.csdn.net/daimashiren/article/details/111127432。
对生成的切片索引进行判别,确定出两个重叠的圆的布尔值索引集合,并对两个集合进行与操作,从而得到存在重叠区域的两个圆的布尔值索引集合。
生成圆的工作已经完成,接下来我们需要对两个圆进行分割操作。
首先,我们需要找到我们所需要的markers点,标记点,不过我更喜欢把它叫做注水点。可以用该函数ndi.distance_transform_edt进行寻找,函数作用参考https://blog.csdn.net/weixin_43508499/article/details/106609901。总结一下,就是计算每个像素点到最邻近的背景点(0值点)的距离,从而完成对整个图像的重新赋值。
在此例子中,我们要分离两个圆,找的注水点就是两个圆的圆心。简单分析可得,最佳的注水点应该是图像中值最高的两个点。
利用peak_local_max对距离图像进行遍历,返回一个和图像相同形状的数组,对其中的峰值点进行标记为True。
然后通过ndi.label()对峰值检测数组进行遍历,对其进行遍历操作,类似区域生长的算法在此都能够得到实现,标记类别。用途就是可以对二值图进行类别标记,默认是四连通区域检测,如果需要八连通区域则需要自己定义卷积核。
最后进行区域的分水岭算法。
以原始图像的前景区域为边界进行填充,输入地势条件-distance,数值越低表示地势越低,markers为注水点标记,后期注水时会以注水点标记为数值,以相应的类别值为水值进行注水。