根據官方文檔中的描述,本文參考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為注水點標記,后期注水時會以注水點標記為數值,以相應的類別值為水值進行注水。