# Identify circles in Image and make list of all diameters

I have this SEM image:

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 ?

• Take a look at this. Commented May 9, 2017 at 19:49

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

img = Import["https://i.sstatic.net/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_, __}) :>


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.

• Great ! This is what I was looking for ! Thank you very much ! Commented May 10, 2017 at 11:47

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

markschulze =
ImageResize[Import["https://i.sstatic.net/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]]];
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]][#] &,
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,
DiskMatrix[
radiusmin + level - 1], {{offx - radiusmin - level,
First@arraydim - offx - radiusmin - level + 1}, {offy -
Last@arraydim - offy - radiusmin - level + 1}}]]][
Sequence @@ #] &, coords]];

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