Skip to main content
2 of 2
deleted 1 character in body
Niki Estner
  • 36.4k
  • 3
  • 92
  • 156

One very general way to solve this kind of problem is to use GeodesicDilation to find the peaks.

The intuition behind GeodesicDilation is that you dilate an image, then "clip" it using a mask image, i.e. for every pixel in the mask and the dilated image, you choose the darker of the two pixels. So the mask limits the growth of the dilation. This is repeated until convergence.

To find peaks, you start with "reduced" version of the source image, i.e. you subtract a constant from the image or multiply it by a constant, then dilate it using the original image as mask. In 1d, the result looks like this:

enter image description here

As you can see, the reconstruction (the green line) grows in every iteration, until it reaches the "borders" of the source image. Now, if you subtract this reconstruction from the source image:

enter image description here

...everything but the peaks will be zero.

In 2d:

img = ColorConvert[Import["https://i.sstatic.net/4gWnl.png"], "Grayscale"];    
γ = 0.5;
plateu = GeodesicDilation[ImageMultiply[img, γ], img];
bin = Binarize[ImageDifference[plateu, img], 0];
bin = Erosion[bin, 1]

enter image description here

I've used Erosion to remove small 1-pixel peaks and to separate close peaks, but you might want to play with different alternatives (e.g. the watershed-based algorithm @Pickett linked to - now that you have a marker image, that should work fine.)

Final step: Find centroids and draw the Voronoi cells:

centroids = ComponentMeasurements[bin, "Centroid"][[All, 2]];
v = VoronoiMesh[centroids];
Show[img, 
 Graphics[{Red, 
   GraphicsComplex[MeshCoordinates[v], MeshCells[v, 1]]}]]

enter image description here

Niki Estner
  • 36.4k
  • 3
  • 92
  • 156