After some trial and error, and adapting code from Peak detection in a 2D array, I have come up with the following solution. NB: threshold = np.mean(image)-np.std(image)
Please feel free to post any improvements, I'm still kinda new to python
def detect_minima(image, threshold):
# define an 8-connected neighborhood
neighborhood = generate_binary_structure(2,2)
# apply the local minimum filter; all pixel of minimal value
# in their neighborhood are set to 1
local_min = minimum_filter(image, footprint=neighborhood) == image
# local_min is a mask that contains the minimas we are
# looking for, but also the background.
# In order to isolate the minimas we must remove the background from the mask.
# we create the mask of the background
background = (image > threshold)
# a little technicality: we must erode the background in order to
# successfully subtract it form local_min, otherwise a line will
# appear along the background border (artifact of the local minimum filter)
eroded_background = binary_erosion(background, structure=neighborhood, border_value=1)
# we obtain the final mask, containing only minimas,
# by removing the background from the local_min mask
detected_minimas = local_min - eroded_background
# Label minimas and extract each minima
labels, nlabels = label(detected_minimas , structure=neighborhood)
dim1 = np.zeros(nlabels, dtype=np.int)
dim2 = np.zeros(nlabels, dtype=np.int)
val = np.zeros(nlabels)
for l in range(0,nlabels):
dim1[l], dim2[l] = minimum_position(image, labels=labels, index=l+1)
val[l] = image[dim1[l],dim2[l]]
# ensure points are below threshold
lt_threshold = val < threshold
dim1 = dim1[lt_threshold]
dim2 = dim2[lt_threshold]
val = val[lt_threshold]
# remove points which neighbour any background or missing points.
image[background] = threshold
keep_asl = []
for l in range(0,len(dim1)):
bounds1a, bounds1b = dim1[l]-1, dim1[l]+2
bounds2a, bounds2b = dim2[l]-1, dim2[l]+2
if (bounds1a < 0): bounds1a = 0
if (bounds1b >= image.shape[0]): bounds1a = image.shape[0]-1
if (bounds2a < 0): bounds2a = 0
if (bounds2b >= image.shape[1]): bounds2a = image.shape[1]-1
neighbour_vals = image[ bounds1a:bounds1b, bounds2a:bounds2b ]
neighbour_max = np.max(neighbour_vals)
if (type(image.data) == np.ma.core.MaskedArray):
if ( (neighbour_max < threshold) & (image.fill_value not in neighbour_vals) ):
keep_asl.append(l)
else:
if (neighbour_max < threshold): keep_asl.append(l)
dim1 = dim1[keep_asl]
dim2 = dim2[keep_asl]
val = val[keep_asl]
# sort by value (lowest first)
sort_ind = np.argsort(val)
dim1 = dim1[sort_ind]
dim2 = dim2[sort_ind]
val = val[sort_ind]
return dim1, dim2, val