4
$\begingroup$

I have this SEM image: enter image description here

I would like to make a list of all diameters of each circle.

Can I somehow let Mathematic identify the circles (approx.) and extract the diameters ?

$\endgroup$
  • 1
    $\begingroup$ Take a look at this. $\endgroup$ – swish May 9 '17 at 19:49
8
$\begingroup$

Binarize does a good job of separating the circles from the background, so I wouldn't use anything more fancy:

img = Import["https://i.stack.imgur.com/WMekK.png"];    
bin = DeleteSmallComponents@Binarize[img];

and once you have a binarized image, ComponentMeasurements is your friend: it searches for connected components in a binary image and performs measurements on them:

components = 
 ComponentMeasurements[
  bin, {"BoundingDiskCenter", "BoundingDiskRadius", "Area", 
   "FilledCircularity"}, #Area > 100 && #FilledCircularity > 0.5 &]

returns a list like:

{1 -> {{799.443, 645.185}, 111.547, 20099.9, 0.670784}, 2 -> {{352.465, 642.549}, 114.035, 22007.8, 0.6883}, 3 -> {{123.306, 402.687}, 110.381, 22336., 0.683878}, 4 -> {{571.642, 401.299}, 111.803, 22602.6, 0.679659}, 5 -> {{341.824, 170.178}, 114.181, 26117.5, 0.70231}, 6 -> {{784.029, 169.859}, 112.099, 22142.8, 0.685281}}

i.e. for every component an element index -> {center, radius, area, filled circularity}

We can use replacement rules to turn these components to Circles:

HighlightImage[bin, {Thick, 
  components /. (index_ -> {center_, radius_, __}) :> 
    Circle[center, radius]}]

enter image description here

Instead of the bounding disk center/radius, you could also use:

  • Centroid gives the center mass of the bright pixels
  • CaliperLength/CaliperWidth measure the largest/smallest diameter

Other measurements to distinguish between circles and other objects (instead of or in addition to FilledCircularity) include:

  • Eccentricity is the eccentricity of the best-fit ellipse (0 for a circle)
  • CaliperElongation measures 1 - the ratio of largest/smallest diameter (0 for a circle)

You'll have to play with these a little to find what works best with your data.

$\endgroup$
  • $\begingroup$ Great ! This is what I was looking for ! Thank you very much ! $\endgroup$ – henry May 10 '17 at 11:47
4
$\begingroup$

I made some changes to the code proposed by swish in the comments and I think it worked.

markschulze = 
ImageResize[Import["https://i.stack.imgur.com/WMekK.png"], 500]
markschulzeedges = Binarize[markschulze, .75]~Blur~3
ParallelMap[
Image@Divide[
 ListConvolve[#, ImageData@markschulzeedges, 
  Ceiling[(Length@#)/2]], Total[#, 2]] &, 
Map[Function[{r}, 
  DiskMatrix[r] - ArrayPad[DiskMatrix[r - 1], 1]][#] &, 
Range[14, 18, 1]]];
HoughCircleDetection[image_Image, radiusmin_Integer: 1, 
radiusmax_Integer: 40, edgedetectradius_Integer: 10, 
minfitvalue_Real: .25, radiusstep_Integer: 1, 
minhoughvoxels_Integer: 4] := 
Module[{edgeimage, hough3dbin, hough3dbinlabels, coords, arraydim}, 
edgeimage = 
SelectComponents[
 DeleteBorderComponents[
  EdgeDetect[image, edgedetectradius, Method -> "Sobel"]], 
 "EnclosingComponentCount", # == 0 &];
hough3dbin = 
DeleteSmallComponents[
 Image3D[ParallelMap[
   Binarize[
     Image@Divide[
       ListConvolve[#, ImageData@edgeimage, 
        Ceiling[(Length@#)/2]], Total[#, 2]], minfitvalue] &, 
   Map[
    Function[{r}, 
       DiskMatrix[r] - ArrayPad[DiskMatrix[r - 1], 1]][#] &, 
    Range[radiusmin, radiusmax, radiusstep]]]], minhoughvoxels];
hough3dbinlabels = MorphologicalComponents[hough3dbin];
coords = 
ParallelMap[Round[Mean[Position[hough3dbinlabels, #]]] &, 
 Sort[Rest@Tally@Flatten@hough3dbinlabels, #1[[2]] > #2[[2]] &][[
  All, 1]]];
 arraydim = Rest@Dimensions[hough3dbinlabels];
 Print["Radii: ", radiusmin + coords[[All, 1]] - 1];
 ParallelMap[
 Function[{level, offx, offy}, 
   ImageMultiply[image, 
    Image@ArrayPad[
      DiskMatrix[
       radiusmin + level - 1], {{offx - radiusmin - level, 
        First@arraydim - offx - radiusmin - level + 1}, {offy - 
         radiusmin - level, 
        Last@arraydim - offy - radiusmin - level + 1}}]]][
  Sequence @@ #] &, coords]];

Show[ImageApply[Plus, HoughCircleDetection[markschulzeedges, 40, 80]],
ImageSize -> 200]

Radii: {52,52,52,51,53,53}

enter image description here

it would be better if you cropped the images first

you must always check the boundaries of the search (in the last line of the code)
for images like yours I set them between 40-80

here is another example with different circles (set 10-100) enter image description here

Radii: {39,63,19,40,36,29,52}

of course these numbers are scaled so you will have to find the correct scale

$\endgroup$

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.