I have an image that looks like this, with some larger impurities/overexposed spots. It generally doesn't matter if they're detected, as measurements are time resolved, so they'll be removed later on.
However, I'm interested in as many as the small dots as possible - as fast as possible. skimage.feature.peak_local_max
does a really good job, and is very easy to use on different data, because there's no need to play around much with intensity scaling.
The problem is though, that large spots for some reason give very strong positives.
import skimage.io
import skimage.feature
import skimage.morphology
from matplotlib.collections import PatchCollection
import matplotlib.pyplot as plt
def plotRoi(spots, img_ax, color, radius):
patches = []
for spot in spots:
y, x = spot
c = plt.Circle((x, y), radius)
patches.append(c)
img_ax.add_collection(PatchCollection(patches, facecolors = "None", edgecolors = color, alpha = 0.3, linewidths = 1))
img = skimage.io.imread("/Path/to/img.png")
img = img[:,:,0]
fig, ax = plt.subplots()
ax.imshow(img, cmap = "Greys")
spots = skimage.feature.peak_local_max(img, min_distance = 0, exclude_border = True, num_peaks = 2000)
plotRoi(spots, ax, "red", radius = 10)
plt.show()
And searching for thousands of spots in some images lead to a large number of local maxima being pretty much on top of each other. Is there a way to avoid this, e.g. by applying a filter on image loading, as I would prefer not to move to a slower type of peak fitting?
The problem is that there are peaks in regions of pixels with exactly the same value. One way to solve this is to merge the peaks to the centre of mass these regions.
Below I recreate the problem and solve it as stated.
import numpy as np
import matplotlib.pyplot as plt
from skimage.feature import peak_local_max
from scipy.ndimage.measurements import center_of_mass, label
# Generate test data with two peaks, one of which consists of two pixels of equal value
image = np.zeros((11,11),dtype=np.uint8)
image[5,3] = 128
image[5,2] = 255
image[5,7:9] = 255
image[6,8] = 128
# Finding peaks normally; results in three peaks
peaks = peak_local_max(image)
# Find peaks and merge equal regions; results in two peaks
is_peak = peak_local_max(image, indices=False) # outputs bool image
labels = label(is_peak)[0]
merged_peaks = center_of_mass(is_peak, labels, range(1, np.max(labels)+1))
merged_peaks = np.array(merged_peaks)
# Visualize the results
fig,(ax1,ax2)=plt.subplots(1,2)
ax1.imshow(image.T,cmap='gray')
ax1.plot(peaks[:,0],peaks[:,1],'ro')
ax2.imshow(image.T,cmap='gray')
ax2.plot(merged_peaks[:,0],merged_peaks[:,1],'ro')
Result: