Skimage中分水岭算法的一些理解

根据官方文档中的描述,本文参考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为注水点标记,后期注水时会以注水点标记为数值,以相应的类别值为水值进行注水。

posted @ 2021-04-17 15:22  Anm半夏  阅读(1302)  评论(0编辑  收藏  举报