本文内容均参考
s
c
i
p
y
1.9.1
scipy1.9.1
scipy1.9.1版本的源码,若有任何不当欢迎指出
我们截取官方注释如下:
def apply_hysteresis_threshold(image, low, high):
"""Apply hysteresis thresholding to ``image``.
This algorithm finds regions where ``image`` is greater than ``high``
OR ``image`` is greater than ``low`` *and* that region is connected to
a region greater than ``high``.
Parameters
----------
image : array, shape (M,[ N, ..., P])
Grayscale input image.
low : float, or array of same shape as ``image``
Lower threshold.
high : float, or array of same shape as ``image``
Higher threshold.
Returns
-------
thresholded : array of bool, same shape as ``image``
Array in which ``True`` indicates the locations where ``image``
was above the hysteresis threshold.
Examples
--------
>>> image = np.array([1, 2, 3, 2, 1, 2, 1, 3, 2])
>>> apply_hysteresis_threshold(image, 1.5, 2.5).astype(int)
array([0, 1, 1, 1, 0, 0, 0, 1, 1])
References
----------
.. [1] J. Canny. A computational approach to edge detection.
IEEE Transactions on Pattern Analysis and Machine Intelligence.
1986; vol. 8, pp.679-698.
:DOI:`10.1109/TPAMI.1986.4767851`
"""
我一开始的时候只读到了这句话:
This algorithm finds regions where ``image`` is greater than ``high``
OR ``image`` is greater than ``low`` *and* that region is connected to
a region greater than ``high``.
我以为的是如果某一个区域的像素值如果在高低阈值之间,那么这个像素点就会被留下,但是不是这样的。这句话里面有一个重点地方为:
that region is connected to a region greater than ``high``.
这就表明了这个函数留下的有两种像素点:
- 超出最高阈值的
- 在低阈值与高阈值之间的像素点:如果这个点所在的low像素连通块(高低之间的)与高像素块有连接的话,那么这个像素块整体都会被保留
口说无凭,我们来看一下源码:
low = np.clip(low, a_min=None, a_max=high) # ensure low always below high
mask_low = image > low
mask_high = image > high
# Connected components of mask_low
labels_low, num_labels = ndi.label(mask_low)
# Check which connected components contain pixels from mask_high
sums = ndi.sum(mask_high, labels_low, np.arange(num_labels + 1))
connected_to_high = sums > 0
thresholded = connected_to_high[labels_low]
return thresholded
这一段代码看似简单,但里面有很多函数必须要理解其含义才能明白这一整个代码。
在这里为了简单起见,我们把这个low和high都设置成常数。比如,low=20,high=50;
mask_low = image > low
mask_high = image > high
这两句是生成了一个mask_low和mask_high的bool矩阵,也就是True和False
接着往下看:
labels_low, num_labels = ndi.label(mask_low)
这个函数是需要注意的。
这是官方文档中给出的示例,其实就是把每一个连通块进行标号,并且返回这个图里有几个连通块。
好,接下来来看这句话:
sums = ndi.sum(mask_high, labels_low, np.arange(num_labels + 1))
小小的一句话却藏着很多机密,就是这一句话决定了我们前面说的那两种保留下来的像素点。
这个sum函数点进去之后是:
def sum(input, labels=None, index=None):
"""
Calculate the sum of the values of the array.
Notes
-----
This is an alias for `ndimage.sum_labels` kept for backwards compatibility
reasons, for new code please prefer `sum_labels`. See the `sum_labels`
docstring for more details.
"""
return sum_labels(input, labels, index)
这个sum_labels的官方文档是:
这里面的函数描述为:
Values of `input` inside the regions defined by `labels` are summed together.
这就意味着
sums = ndi.sum(mask_high, labels_low, np.arange(num_labels + 1))
这句话的含义是统计Low(包含high)连通块上有多少个high,如果至少有一个,那么这个块将被保留。
至少我们得到的sums是全部连通块的high数量
应该形如
sums[i]表示第i个连通块的high数量。
接着往下看:
connected_to_high = sums > 0
connected_to_high[i]就是表示第i个连通块是否与high相连,如果第i个连通块全是high的,那么一定保留,如果全是low,但是connected_to_high[i]>0,则保留,如果一半high一半low也保留,直接相连。
接下来的这一句话有点诡异,也为他是用矩阵做了索引。
但其实没啥,就是取得矩阵值做索引,然后把connected_to_high得值给放到相应位置上就可以了。
thresholded = connected_to_high[labels_low]
label_low是连通块号,形状是图片形状。connected_to_high含义不再赘述。
返回的就是True False矩阵表示每个像素点是否被留下。
好了本文结束,感谢观看~