I am analysing microscopic particles images of the kind shown below, and primarily I am interested in learning whether in Mathematica one can extract structural properties of the particles using the built-in image analysis tools.

More precisely,

  • is it for instance possible to compute the nearest-neighbour distance distribution?

  • Or more importantly, measuring the density of particles from the image? (that is, number of particles per area when binning the image).

I admit there might be similar questions previously asked but I could not pinpoint one that tackled such problem, so any help would be much appreciated.

Image example (source):

enter image description here

The kind of analysis I have learned so far is to use the ridge lines separating the particles in order to detect them and find their centres of mass based on the point of maximum distance to a ridge line (per particle). Here's an example

img = Import["https://i.stack.imgur.com/rUnvs.jpg"]
ridgelines = RidgeFilter[-img, 4];
distanceRidges = 
    ridgelines] (*distance transform image based on the ridge filter*)
distMaximum = 
  4] (*find centre of masses using max ridge dists*)

which yields:

enter image description here enter image description here enter image description here

  • $\begingroup$ If you do dots = SelectComponents[Pruning[Thinning@distMaximum], #Count == 1 &] you can get those blobs as entirely single dots. Then PixelValuePositions[dots,1] will get you their centers. From there you can do DistanceMatrix and other such things like Nearest etc. $\endgroup$ – flinty Aug 11 '20 at 15:31
  • $\begingroup$ Similar question here, with great answers $\endgroup$ – MelaGo Aug 11 '20 at 23:46

I think you're going in the right direction. You could also attempt a segmentation from your ridge filtering and extract the centroids of the components. This is a bit sensitive to the "MinimumSaliency" value so it needs some manual intervention:

wsh = WatershedComponents[ridgelines, Method -> {"MinimumSaliency", 0.2}];
wsh // Colorize
centroids = Values[Select[ComponentMeasurements[wsh, "Centroid"], #[[1]] > 1 &]];


The advantage of ComponentMeasurements is you can get the "Area" and "EquivalentDiskRadius" if those things interest you too.

You can use the centroids and compute a DistanceMatrix:

dmtx = DistanceMatrix[centroids];

... or create a Nearest function and get the distance to the closest component centroid:

nf = Nearest[centroids];
 EuclideanDistance[#, Last[nf[#, 2]]] & /@ centroids


So the median distance between centroids of the cells is about 42 pixels.

Here's how you could get a density map based on the dots method I proposed in the question comments, but you could alternatively use the centroids I calculated above in place of positions:

img = Import["https://i.stack.imgur.com/rUnvs.jpg"];
ridgelines = RidgeFilter[-img, 4];
distanceRidges = 

distMaximum = MaxDetect[distanceRidges, 4];
dots = SelectComponents[Pruning[Thinning@distMaximum], #Count == 1 &];
positions = PixelValuePositions[dots, 1];
  Image[SmoothDensityHistogram[positions, 60, 
    PlotRangePadding -> None, Frame -> None, ColorFunction -> Hue]],
  img}, .5]

Note that the density is fairly uniform and that I needed to manually provide the width as the automatic width was inadequate and didn't capture the lower density near the holes.

cell density

  • $\begingroup$ You may want to consider DeleteSmallComponents too if there are small fragments that are biasing the result down. $\endgroup$ – flinty Aug 11 '20 at 15:26
  • $\begingroup$ Hi! Many thanks, this has been really instructive, I did not know yet ComponentMeasurements could be used in such ways! If I may ask, regarding the density question (count of particle per area of bin), the attempt is to find out locally in the image where there are a higher density of particles (intuitively, like a heat-map that shows this fluctuation). Do you happen to have some ideas as to how we could tackle this? thanks again! $\endgroup$ – CuriousBadger Aug 12 '20 at 11:24
  • $\begingroup$ @CuriousBadger I added a density map. It performs okay-ish but needs manual adjustment of the kernel width for the holes to show up as low-density patches. The holes could be highlighted by other means however, as they are quite dark regions compared to the cells. $\endgroup$ – flinty Aug 12 '20 at 12:02
  • $\begingroup$ This is remarkably efficient! Thank you flinty! Does SmoothDensityHistogram allow to extract the density profile in a numerical fashion? (i.e. how density changes as a function of x-axis for instance) $\endgroup$ – CuriousBadger Aug 12 '20 at 12:33
  • $\begingroup$ @CuriousBadger you should look into SmoothKernelDistribution for that purpose. $\endgroup$ – flinty Aug 12 '20 at 12:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.