Fit a circle to a region of an image
If img
is your image, you can use Binarize
to find a fixed
fraction of black pixels:
img = Import["https://i.stack.imgur.com/T76kp.png"];
bin = Binarize[img, Method -> {"BlackFraction", .1}]
Then you can use ComponentMeasurements
to find the centroid and radius:
comp = ComponentMeasurements[
ColorNegate@bin, {"Centroid", "EquivalentDiskRadius",
"Circularity"}, #Circularity > 0.5 &];
HighlightImage[img, {comp /. (index_ -> {c_, r_, __}) :>
Circle[c, r]}]
Response to comment:
@anderstood asked why ComponentMeasurements
finds two components. We can use the Mask
measurement to get a binary mask for each component:
HighlightImage[img, Image[#]] & /@
ComponentMeasurements[ColorNegate@bin, "Mask"][[All, 2]]
and see that the first component is the black border around the image.
Let's look at your data in more detail. The image has a black frame around it which is taken into account! This means, that binarizing using "BlackFraction"
as Niki did will lead to an incorrect result.
In fact, if you take this into account, then the frame alone contains more than 5% of your total density. Let's calculate the amount of density we want:
img = RemoveAlphaChannel[
ColorConvert[Import["https://i.stack.imgur.com/T76kp.png"],
"Grayscale"]];
data = ImageData[ColorNegate[img], "Real"];
thresh = .95*Total[Flatten[data]]
(* 5539.33 *)
By removing only the frame, we are well below this threshold
Total[Flatten[ArrayPad[data, -10]]]
(* 4972.88 *)
Let us remove this and calculate the 95% boundary correctly
data = ArrayPad[data, -10];
thresh = .95*Total[Flatten[data]]
(* 4724.23 *)
To create a centered disk that we can use as a mask, we can use DiskMatrix
. This can be used with varying radii until we find the correct one that meets the wanted threshold:
densityDifference[r_?NumericQ] :=
Total[Flatten[data*DiskMatrix[r, Dimensions[data]]]] - thresh
FindRoot[densityDifference[r], {r, 50, 100}, Method -> "Secant"]
(* about 69 *)
HighlightImage[
img,
Image@DiskMatrix[69, Reverse@ImageDimensions[img]]
]