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 ?
Mathematica Stack Exchange is a question and answer site for users of Wolfram Mathematica. It only takes a minute to sign up.
Sign up to join this communityI 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 ?
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 Circle
s:
HighlightImage[bin, {Thick,
components /. (index_ -> {center_, radius_, __}) :>
Circle[center, radius]}]
Instead of the bounding disk center/radius, you could also use:
Centroid
gives the center mass of the bright pixelsCaliperLength
/CaliperWidth
measure the largest/smallest diameterOther 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.
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}
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)
Radii: {39,63,19,40,36,29,52}
of course these numbers are scaled so you will have to find the correct scale