使用numpy进行非最大抑制的2D峰值发现

时间:2018-01-04 16:19:26

标签: python numpy opencv image-processing

我编写了一个函数(如下所示)来查找图像中顶部num_peaks强度值的位置,同时执行非最大抑制以仅选择局部最大值:

def find_peaks(img, num_peaks, threshold_fraction=0.5, nhood_size=None):
    """Find locally maximum intensities in an image"""
    # calculate threshold as a fraction of intensity range in the image
    threshold = (threshold_fraction * (img.max() - img.min())) + img.min()

    # determine offsets in each direction that constitute a neighbourhood
    if nhood_size is None:
        nhood_size = np.array(img.shape) * 0.02
    nhood_offset = (np.around(nhood_size / 2)).astype(int)

    # create array with labelled fields to allow intensity-specific sorting
    rows, cols = np.array(np.where(img >= threshold))
    values = []
    for i, j in zip(rows, cols):
        values.append((i, j, img[i, j]))

    dtype = [('row', int), ('col', int), ('intensity', np.float64)]
    indices = np.array(values, dtype=dtype)

    # sort in-place in descending order
    indices[::-1].sort(order='intensity')

    # Perform suppression
    for idx_set in indices:
        intensity = idx_set[2]
        if not intensity:
            continue

        x0 = idx_set[1] - nhood_offset[1]
        xend = idx_set[1] + nhood_offset[1]
        y0 = idx_set[0] - nhood_offset[0]
        yend = idx_set[0] + nhood_offset[0]

        indices_to_suppress = np.where((indices['col'] >= x0) &
                                       (indices['col'] <= xend) &
                                       (indices['row'] >= y0) &
                                       (indices['row'] <= yend))
        if indices_to_suppress:
            indices['intensity'][indices_to_suppress] = 0

        idx_set[2] = intensity

    # perform second sorting & return the remaining n (num_peaks) most
    # intense values
    indices[::-1].sort(order='intensity')
    if len(indices) <= num_peaks:
        return np.array([np.array([i, j])
                        for i, j in zip(indices['row'], indices['col'])])

    # or return all of them
    return np.array([np.array([i, j])
                    for i, j in zip(indices['row'][:num_peaks], indices['col'][:num_peaks])])

这似乎适用于小图像和大threshold_fraction(较少的值来抑制周围),但事实证明对我的目的而言效率非常低,我的阈值较低,如0.1到0.2。我无法通过初学者的numpy技能提高效率。

我想知道是否可以对这段可能会改善其性能的代码进行任何更改。此外,由于我使用的是numpy和OpenCV,因此很高兴知道是否有可以实现类似功能的库函数或以某种方式利用它来编写有效的峰值查找器。

2 个答案:

答案 0 :(得分:0)

由于您已经在使用numpy,因为它已经使用skimagepip install scikit-image(与skimage.feature.peak_local_max()一起安装)的额外使用应该是轻而易举的。然后,您可以使用skimage.ndimage.maximum_filter()#mainDiv { height: 200px; width: 200px; position: relative; background: #3beadc; padding: 10px; border-bottom-right-radius: 25px; } .cornerBorder { position: absolute; height: 15%; width: 15%; top: 0; left: 0; border-left: 5px solid black; border-top: 5px solid black; } .roundedBorder { position: absolute; height: 15%; width: 15%; bottom: 0; right: 0; border-right: 5px solid black; border-bottom: 5px solid black; border-bottom-right-radius: 25px; }创建您感兴趣的位置的地图,并且由于这些对象本身被认为是numpy数组,因此可以通过减去某些部分来抑制这些区域。你原来的结果数组。

答案 1 :(得分:0)

您的算法依赖于对图像值进行排序,因此其时间复杂度为图像像素数N的O(N log N),并且需要额外的O(N)内存缓冲区来存储排序值。

标准的局部最大值检测器依赖于用一个小的结构元素扩大图像(其大小取决于&#34;嘈杂&#34;或者&#34;峰值&#34;图像是什么),以及然后找到原始图像和扩散图像具有相等值的像素。这是O(N)的时间并且需要额外的O(N)缓冲器。非局部最大像素的抑制是自动的,并且过度接近&#34;通过按图像强度对找到的局部最大值(其数量通常<&lt;&lt; N)进行排序并按排序顺序去除接近的最大值,可以容易地完成局部最大值。

因此,对于足够大的图像,后一种算法在理论上更具性能,并且可能实际上也更具性能。当然YMMV取决于实现和图像大小。