Get coordinates of local maxima in 2D array above certain value

后端 未结 3 874
心在旅途
心在旅途 2020-11-30 22:04
from PIL import Image
import numpy as np
from scipy.ndimage.filters import maximum_filter
import pylab

# the picture (256 * 256 pixels) contains bright spots of whi         


        
相关标签:
3条回答
  • 2020-11-30 22:45
    import numpy as np
    import scipy
    import scipy.ndimage as ndimage
    import scipy.ndimage.filters as filters
    import matplotlib.pyplot as plt
    
    fname = '/tmp/slice0000.png'
    neighborhood_size = 5
    threshold = 1500
    
    data = scipy.misc.imread(fname)
    
    data_max = filters.maximum_filter(data, neighborhood_size)
    maxima = (data == data_max)
    data_min = filters.minimum_filter(data, neighborhood_size)
    diff = ((data_max - data_min) > threshold)
    maxima[diff == 0] = 0
    
    labeled, num_objects = ndimage.label(maxima)
    xy = np.array(ndimage.center_of_mass(data, labeled, range(1, num_objects+1)))
    
    plt.imshow(data)
    plt.savefig('/tmp/data.png', bbox_inches = 'tight')
    
    plt.autoscale(False)
    plt.plot(xy[:, 1], xy[:, 0], 'ro')
    plt.savefig('/tmp/result.png', bbox_inches = 'tight')
    

    The previous entry was super useful to me, but the for loop slowed my application down. I found that ndimage.center_of_mass() does a great and fast job to get the coordinates... hence this suggestion.

    0 讨论(0)
  • 2020-11-30 22:48
    import numpy as np
    import scipy
    import scipy.ndimage as ndimage
    import scipy.ndimage.filters as filters
    import matplotlib.pyplot as plt
    
    fname = '/tmp/slice0000.png'
    neighborhood_size = 5
    threshold = 1500
    
    data = scipy.misc.imread(fname)
    
    data_max = filters.maximum_filter(data, neighborhood_size)
    maxima = (data == data_max)
    data_min = filters.minimum_filter(data, neighborhood_size)
    diff = ((data_max - data_min) > threshold)
    maxima[diff == 0] = 0
    
    labeled, num_objects = ndimage.label(maxima)
    slices = ndimage.find_objects(labeled)
    x, y = [], []
    for dy,dx in slices:
        x_center = (dx.start + dx.stop - 1)/2
        x.append(x_center)
        y_center = (dy.start + dy.stop - 1)/2    
        y.append(y_center)
    
    plt.imshow(data)
    plt.savefig('/tmp/data.png', bbox_inches = 'tight')
    
    plt.autoscale(False)
    plt.plot(x,y, 'ro')
    plt.savefig('/tmp/result.png', bbox_inches = 'tight')
    

    Given data.png:

    enter image description here

    the above program yields result.png with threshold = 1500. Lower the threshold to pick up more local maxima:

    enter image description here

    References:

    • J.F. Sebastian counts nuclei
    • Joe Kington finds paw prints
    • Ivan finds local maximums
    0 讨论(0)
  • 2020-11-30 22:52

    This can now be done with skimage.

    from skimage.feature import peak_local_max
    xy = peak_local_max(data, min_distance=2,threshold_abs=1500)
    

    On my computer, for a VGA image size it runs about 4x faster than the above solution and also returned a more accurate position in certain cases.

    0 讨论(0)
提交回复
热议问题