Python 使用numpy进行非最大值抑制的二维峰值查找
我编写了一个函数,用于查找图像中顶部num_峰值强度值的位置,同时执行非最大值抑制以仅选择局部最大值:Python 使用numpy进行非最大值抑制的二维峰值查找,python,numpy,opencv,image-processing,Python,Numpy,Opencv,Image Processing,我编写了一个函数,用于查找图像中顶部num_峰值强度值的位置,同时执行非最大值抑制以仅选择局部最大值: 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 imag
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])])
这似乎适用于较小的图像和较大的阈值,但事实证明,对于我的目的来说,这是非常低效的,因为我有较低的阈值,如0.1到0.2。我还没有能够使我的初学者numpy技能更有效
我想知道是否可以对这段代码进行任何更改,以提高其性能。另外,由于我使用的是numpy和OpenCV,如果有一个库函数可以实现类似的功能,或者以某种方式利用它来编写一个高效的峰值查找器,那就很好了。值得一提的是,既然您已经在使用numpy,那么在pip install scikit image中安装skimage的额外使用应该是轻而易举的事。然后,您可以使用skimage.feature.peak_local_max或skimage.ndimage.maximum_过滤器创建感兴趣位置的地图,由于对象本机被视为numpy数组,您可以通过从原始数组中减去结果数组的一部分来抑制这些区域。您的算法依赖于对图像值进行排序,因此其时间复杂度取决于图像像素数N中的logn,并且需要额外的内存缓冲区来存储排序后的值 标准的局部极大值检测器依赖于使用一个小的结构元素来扩展图像,该结构元素的大小取决于图像的噪声或峰值,然后找到原始图像和扩展图像具有相等值的像素。这是及时开启的,需要额外的开启缓冲区。非局部极大值像素的抑制是自动的,并且通过对发现的局部极大值进行排序(其数量通常为