Find radii of concentric circles in image
You can use the center detection from this answer:
Basically, the center you're looking for is a point in the image for which every gradient points towards or away from the center. That means we can minimize this error term:
squaredError = 1/2 ({cx - x, cy - y}.{-gy, gx})^2;
which leads to a linear equation system:
errDerivative = Expand[D[squaredError, {{cx, cy}}]];
linearSystem = {{D[errDerivative, cx],
D[errDerivative, cy]}, -errDerivative /. {cx -> 0, cy -> 0}}
Now we can simply insert the gradients from the image into this equation system:
gradientX = ImageData@GaussianFilter[img, 1, {0, 1}];
gradientY = ImageData@GaussianFilter[img, 1, {1, 0}];
xArr = Array[N[#2] &, Dimensions[gradientX]];
yArr = Array[N[#1] &, Dimensions[gradientX]];
ls = Total[
linearSystem /. {gx -> gradientX, gy -> gradientY, x -> xArr,
y -> yArr}, {-2, -1}];
center = LinearSolve @@ ls;
The center location is in indices (starting with 1) and image processing functions want coordinates (starting with 0, at the bottom left corner), so I have to convert the coordinates:
center[[1]] -= 1;
center[[2]] = Length[gradientX] - center[[2]];
Then I can apply a polar transform
maxRadius = 250;
polar = ImageTransformation[img,
center + {Cos[#[[1]]], Sin[#[[1]]]}*#[[2]] &, {360, maxRadius},
DataRange -> Full,
PlotRange -> {{0, 360 \[Degree]}, {1, maxRadius}}]
The mean brightness for each row gives a measure of the strength of each radius:
radiusStrength = Mean /@ ImageData[polar, DataReversed -> True];
peakX = Position[
MapThread[#1 > #2 && #1 > #3 &, {radiusStrength,
RotateLeft[radiusStrength], RotateRight[radiusStrength]}],
True][[All, 1]];
peaks = SortBy[Transpose[{peakX, radiusStrength[[peakX]]}], Last];
ListLinePlot[radiusStrength, Epilog -> {Red, Point[peaks[[-4 ;;]]]}]
The radii with the highest strengths correspond nicely with the radii you're looking for:
Show[img,
Graphics[{Red, Dashed, Circle[center, #] & /@ peaks[[-4 ;;, 1]]}]]
Note that while this is more complex than a 'ComponentMeasurements'-based solution it is much more robust. You don't have to adjust any thresholds or parameters. And it should work fine, even if parts of the circles are occluded or hardly visible.
What you could do is apply an edge filter and find the threshold which binarizes your image best:
i = Import["http://i.imgur.com/oTTM9MG.jpg"];
edges = LaplacianGaussianFilter[ColorNegate[i], 2];
Manipulate[Binarize[edges, t], {t, 0, .1}]
After that you could select all objects with a certain radius or you throw out all small objects with a specific "Count"
. You have to decide then what you prefer as radius. I thought maybe the "MeanCentroidDistance"
gives a quite stable measure
circles =
SelectComponents[
MorphologicalComponents[LaplacianGaussianFilter[ColorNegate@i, 2], 0.0056`],
"Count", # > 300 &];
Colorize[circles]
ComponentMeasurements[circles, "MeanCentroidDistance"]
(*
{26 -> 271.952, 33 -> 262.778, 129 -> 221.202, 157 -> 209.482,
329 -> 154.293, 398 -> 136.493}
*)