2
$\begingroup$

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

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

$\endgroup$
2
  • $\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, 2020 at 15:31
  • $\begingroup$ Similar question here, with great answers $\endgroup$
    – MelaGo
    Aug 11, 2020 at 23:46

1 Answer 1

3
$\begingroup$

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 &]];

segmentation

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
]

distances

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.

cell density

$\endgroup$
10
  • $\begingroup$ You may want to consider DeleteSmallComponents too if there are small fragments that are biasing the result down. $\endgroup$
    – flinty
    Aug 11, 2020 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$ Aug 12, 2020 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, 2020 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$ Aug 12, 2020 at 12:33
  • $\begingroup$ @CuriousBadger you should look into SmoothKernelDistribution for that purpose. $\endgroup$
    – flinty
    Aug 12, 2020 at 12:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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