# Computing density of particles and distances from microscopic images

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):

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 =
DistanceTransform@
ColorNegate@
MorphologicalBinarize[
ridgelines] (*distance transform image based on the ridge filter*)
\
distMaximum =
MaxDetect[distanceRidges,
4] (*find centre of masses using max ridge dists*)


which yields:

• 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. – flinty Aug 11 at 15:31
• Similar question here, with great answers – MelaGo Aug 11 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];
BoxWhiskerChart[
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 =
DistanceTransform@
ColorNegate@
MorphologicalBinarize[
ridgelines];

distMaximum = MaxDetect[distanceRidges, 4];
dots = SelectComponents[Pruning[Thinning@distMaximum], #Count == 1 &];
positions = PixelValuePositions[dots, 1];
Blend[{
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.

• You may want to consider DeleteSmallComponents too if there are small fragments that are biasing the result down. – flinty Aug 11 at 15:26
• 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! – CuriousBadger Aug 12 at 11:24
• @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. – flinty Aug 12 at 12:02
• 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) – CuriousBadger Aug 12 at 12:33
• @CuriousBadger you should look into SmoothKernelDistribution for that purpose. – flinty Aug 12 at 12:54