Finding local brightness maximas with OpenCV

I want to find points (of a processed image) that are the brightest in their local region.

Basically, I want all of the points whose 8 neighbors are all smaller but I want to have brighter maxima block out nearby dimmer maxima. So, for example, the 8-neighbor maximas could be sorted by descending brightness then yielded in order while excluding points covered by previously-yielded points.

I know how to implement this logic, but because I'm using python there's a huge runtime speed advantage to using built-in opencv/numpy functions.

Haralick's primal topograhic sketch is the answer to that. Check-out the peak section of :

Haralick R., et al. - The Topographic Primal Sketch

If you also look at the notation and Hessian parts, you will grasp how to implement peak finding (local-max) as a convolution operator.

Of course you get multiple peaks, but this is also the case when you convolve with a simple 3x3 mask. However, the technique is more robust because:

1. If you do the classification from the eigenvalues/vectors of the structure tensor, you will be reasonably robust against the noise.
2. Of course you get multiple peaks, but this is also the case when you convolve with a simple 3x3 mask. However, such peaks can be avoided using appropriate thresholds. If such threhsolds are not available, dynamic thresholding might be an option.
3. This is better than checking all the neighbors mainly for your question, because every operation can be done through OpenCV routines. And also because you will have a much much better result.
4. I would like to direct you to Haralick's original paper, which is fun to read.

Harlick R., et al. - The Use of the Facet Model and the Topographic Primal Sketch in Image Analysis

and also check out other important works such as:

Boulanger P., Cohen P. - Stable Estimation of a Topographic Primal Sketch for Range Image Interpretation

Consider using the Facet model for approximating the local image structures with polynomials. Read Haralick's paper for more information.

Finally, for more information on the structure tensor, you can checkout the wiki pages and here:

Goldlückel B. - The Structure Tensor of an Image

• Could you expand on your answer? Based on your hinting and the link I would guess that it's just applying a Sobel transform to get the 1st and 2nd derivatives, then doing the standard critical point classification stuff from calculus. But how does that avoid giving multiple peaks in a small area? What are potential issues? How much does noise hurt? Why is this better than just checking that all 4 or 8 neighbors are not greater? Your link is just a list of critical point classifications; are there any better resources? – Craig Gidney Aug 28 '14 at 3:16
• Okay, big topic so I will be adding more details to my answer. – Tolga Birdal Aug 28 '14 at 13:33

A really simple strategy I'm using at the moment, though not particularly fast, is to just roll-and-max the image against itself (I think this might be equivalent to dilating the image?). This basically replaces every pixel with a nearby maximum, and so a pixel not equal to itself after roll-and-max'ing can be excluded.

def findIsolatedLocalMaxima(greyScaleImage):
squareDiameterLog3 = 3 #27x27

total = greyScaleImage
for axis in range(2):
d = 1
for i in range(squareDiameterLog3):
total = np.maximum(total, np.roll(total, d, axis))
total = np.maximum(total, np.roll(total, -d, axis))
d *= 3

maxima = total == greyScaleImage
h,w = greyScaleImage.shape

result = []
for j in range(h):
for i in range(w):
if maxima[j][i]:
result.append((i, j))
return result