# Fit a circle to a region of an image

I would like to develop a routine that associates a size with images such as that below. My idea is to find the radius of the circle (centered at the origin) that contains (say) 95% of the total density. How can I achieve this? Also, are there better image processing techniques for associating a size to this region?

• This site is about the software Wolfram Mathematica and not image processing. You might want to consider asking this somewhere else. – halirutan Feb 16 '18 at 13:21

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[
"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[#]] & /@


and see that the first component is the black border around the image.

• That was blisteringly fast. Thanks! I'll have a play :) – Tom Feb 16 '18 at 13:39
• Why did you use ColorNegate? Also, would you know why ComponentMeasurements[bin, {"Centroid", "EquivalentDiskRadius"}] returns two circles (also with ColorNegate@bin instead of bin)? – anderstood Feb 16 '18 at 13:45
• @anderstood: I used ColorNegate because ComponentMeasurements searches for white objects on a black background - and the source image is the opposite. The second object is the black border around the image. – Niki Estner Feb 16 '18 at 15:47

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"]