19
$\begingroup$

I have this picture of small particles in a polymer film. I want to count how many particles in the figure, so that I can have a rough estimation of the particle density. But the image quality is poor, I had a hard time to do it.

particle in film - grayscale, particle in film - color

I have tried several ways to do it, but failed. below is the code. The first method I tried is:

`SetDirectory["C:\\Users\\mayao\\documents"]
image = Import["Picture3.jpg"];
imag2 = Binarize[image, {0.0, 0.8}];
cells = SelectComponents[DeleteBorderComponents[imag2], "Count", -400];

circles = ComponentMeasurements[ImageMultiply[image,cells],"Centroid", "EquivalentDiskRadius"}][[All, 2]]; Show[image, Graphics[{Red, Thick, Circle @@ # & /@ circles}]]

Here is what I got: enter image description here

So it does not count all the particle. Plus, it sometimes take several particle as one.

I read another method from a thread here, the code is:

obl[transit_Image] := (SelectComponents[
     MorphologicalComponents[
      DeleteSmallComponents@
       ChanVeseBinarize[#, "TargetColor" -> Black], 
      Method -> "ConvexHull"], {"Count", "SemiAxes"}, 
     Abs[Times @@ #2 Pi - #1] < #1/100 &]) &@
  transit; GraphicsGrid[{#, obl@# // Colorize, 
    ImageMultiply[#, 
     Image@Unitize@
       obl@#]} & /@ (Import /@ ("C:\\Users\\mayao\\documents\\" <> # \
& /@ {"Picture1.jpg", "Picture2.jpg", "Picture3.jpg", 
       "Picture1.jpg"}))]

But it does not recognize the single particles:

enter image description here

Is there any other method to do this task? Thanks a lot for any suggestions.

$\endgroup$
1

4 Answers 4

11
$\begingroup$

get the binarize image

 img = Import["https://i.sstatic.net/0OJd7.jpg"];
 binimg = LocalAdaptiveBinarize[img, 25];

enter image description here

The effect like this:

    big = ImageDemosaic[binimg // ColorConvert[#, "Grayscale"] &, 
         "RGGB"] // MinDetect // SelectComponents[#, "Count", # > 100 &] &;
    (array = WatershedComponents[GradientFilter[big, 2], 
        DistanceTransform[big] // MaxDetect]) // Colorize

enter image description here

Then your number is

array // Max

1650

Update===========================================================

Use the Closing to optimize the binarize image.

binimg = Closing[LocalAdaptiveBinarize[img, 25], 3]

enter image description here

Then we get the array and verify the effect.

(array = WatershedComponents[GradientFilter[binimg, 2], 
    DistanceTransform[binimg // ColorNegate] // 
     MaxDetect]) // Colorize

enter image description here

Or you can like this:

Show[img, 
 Graphics[{Red, 
   Point[(array /. 1164 -> 0 // 
       ComponentMeasurements[#, "Centroid"] &)[[All, 2]]]}]]

enter image description here

So the number of your component is:

array // Max

1340

$\endgroup$
1
  • $\begingroup$ Awesome, this is the most accurate result! One question, what does 1164->0 mean? why specifically 1164? $\endgroup$
    – BNHSX
    Commented Dec 11, 2015 at 1:32
8
$\begingroup$

You could try something like this

HighlightImage[
  ImageTake[img, {100, 400}, {100, 400}],
  ImageCorners[
    ImageTake[img, {100, 400}, {100, 400}],
    1.0,
    0.0002,
    10
  ]
]

Output of ImageCorners combined with ImageTake.

for visualization and then

Length@
  ImageCorners[
    ImageTake[img, {100, 400}, {100, 400}],
    1.0,
    0.0002,
    10
  ]

to get an estimate of the numbers of particles. In any case I would start by selecting a subsection of the image where the lighting is as homogenous as possible. As you can see at the above example there's still a number of false positives and false negatives, and you'll also have to guesstimate the actual area your image is covering in order to calculate the density.

$\endgroup$
8
$\begingroup$

In the post referenced in the comment, the key ideas is

In order to separate the overlapping cells, I extract a set of markers by finding local maximas of the DistanceTransform and use these as markers in WatershedComponents

However exactly following that example verbatim won't work (because there are hyperparameters) and would give something like this:

enter image description here

Here are the preprocessing steps I would take:

s1 = GradientFilter[img, 5] // ImageAdjust;
s2 = Threshold[s1, {"Hard", "Cluster"}];
s3 = FillingTransform[s2];
s4 = DeleteSmallComponents[s3, 30];

The bottom line is that it is tough for a human to delineate the blobs, so it is for a computer. However you can play with the "minimum saliency" threshold as follows:

marker = MaxDetect[DistanceTransform[s4, Padding -> 0] // ImageAdjust,
    0.1];

Manipulate[
 w = WatershedComponents[GradientFilter[s4, 3], marker, 
   Method -> {"MinimumSaliency", ms}];
 cells = SelectComponents[w, {"Area", "EquivalentDiskRadius"}, 
   10 < #1 < 1000 && #2 > 4 &];
 measures = 
  ComponentMeasurements[{cells, img}, {"Centroid", 
    "EquivalentDiskRadius", "Area"}];
 Show[img, 
  Graphics[{Thickness[0.003], Opacity[0.6, Yellow], 
    Circle @@ # & /@ (measures[[All, 2, 1 ;; 2]])}], 
  ImageSize -> 800], {ms, 0, 1}]

To manually to achieve to desired cell separations:

enter image description here

which will look much better:

enter image description here

$\endgroup$
1
  • 1
    $\begingroup$ Wow! That looks pretty accurate. If, for some reason, this approach tends to either overestimate or underestimate the density and a human eye could do a bit better, one might consider a statistical sampling scheme where the whole image is done with your method and then a random sample of smaller rectangles are counted by eye (small enough so that counting would be easy but large enough to contain say at least 10 particles). The automated estimate would be adjusted by the ratio of the sampled by-eye particles to the sampled counts by the automated method. $\endgroup$
    – JimB
    Commented Dec 2, 2015 at 16:06
4
$\begingroup$

The local binarization can help with the uneven lighting. Dilation helps disconnect some particles that remain connected, and DeleteSmallComponents removes small portions caused by noise.

img = Import["https://i.sstatic.net/0OJd7.jpg"];
comps = MorphologicalComponents[DeleteSmallComponents[
        ColorNegate[Dilation[LocalAdaptiveBinarize[img, 10], 1]]]];
comps // Colorize
Max[comps]

984

enter image description here

$\endgroup$
2
  • $\begingroup$ The use of MorphologicalComponents will lead the result to smaller obviously. $\endgroup$
    – yode
    Commented Dec 9, 2015 at 5:52
  • $\begingroup$ @yode -- so do the Dilation and DeleteSmallComponents! $\endgroup$
    – bill s
    Commented Dec 9, 2015 at 15:07

Your Answer

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

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