2016-08-24 167 views
2

我正在制作音乐识别程序,并且作为它的一部分,我需要从png(2200x1700像素)中找到numpy数组的最大连接区域。我目前的解决方案如下。加速numpy过滤

labels, nlabels = ndimage.label(blobs) 
cutoff = len(blobs)*len(blobs[0])/nlabels 
blobs_found = 0 
x = [] 
t1 = time() 
for n in range(1, nlabels+1): 
    squares = np.where(labels==n) 
    if len(squares[0]) < cutoff: 
     blobs[squares] = 0 
    else: 
     blobs_found += 1 
     blobs[squares] = blobs_found 
     x.append(squares - np.amin(squares, axis=0, keepdims=True)) 
nlabels = blobs_found 
print(time() - t1) 

这个工作,但它需要约6.5秒的运行。有没有一种方法可以从此代码中删除循环(或以其他方式加速)?

+0

这是一个有趣的问题,你可以使[mcve](http://stackoverflow.com/help/mcve)? – BPL

回答

2

你可以得到每个标记区域的大小(像素):

unique_labels = numpy.unique(labels) 
label_sizes = scipy.ndimage.measurement.sum(numpy.ones_like(blobs), labels, unique_labels) 

最大将为:

unique_labels[label_size == numpy.max(label_size)] 
+0

有没有简单的方法让最后一行成为n个最大标签的列表? –

+0

是的,使用'numpy.argsort'来取代前n个值,如:'unique_labels [numpy.argsort(label_size)[0:n-1]]' – Benjamin

+0

'ndimage.measurement.sum'应该是ndimage。总结新版本? –

2

最快很可能会使用numpy.bincount和工作距离那里。例如:

labels, nlabels = ndimage.label(blobs) 
cutoff = len(blobs)*len(blobs[0])/float(nlabels) 

label_counts = np.bincount(labels) 

# Re-label, taking the cutoff into account 
cutoff_mask = (label_counts >= cutoff) 
cutoff_mask[0] = False 
label_mapping = np.zeros_like(label_counts) 
label_mapping[cutoff_mask] = np.arange(cutoff_mask.sum()) + 1 

# Create an image-array with the updated labels 
blobs = label_mapping[labels].astype(blobs.dtype) 

这可以针对速度进行优化,但我的目标是可读性。