For some shapes, particularly ones with a small variety of pixels, a commonly-used technique for computing circularity usually ends in a price which is biased excessive, and which might be higher than 1. In releases previous to R2023a, the operate regionprops used this frequent technique. In R2023a, the computation technique has been modified to right for the bias.
For the total story, learn on!
What Is Circularity?
Our definition of circularity is:
$c = frac{4pi a}{p^2}$
the place a is the realm of a form and p is its perimeter. It’s a unitless amount that lies within the vary $[0,1]$. A real circle has a circularity of 1. Listed below are the estimated circularity measurements for some easy shapes.
url = “https://blogs.mathworks.com/steve/information/simple-shapes.png”;
p = regionprops(“desk”,A,[“Circularity” “Centroid”])
textual content(p.Centroid(ok,1),p.Centroid(ok,2),string(p.Circularity(ok)),…
BackgroundColor = “blue”,…
HorizontalAlignment = “heart”,…
VerticalAlignment = “center”,…
title(“Circularity measurements for some easy shapes”)
Circularity > 1??
url = “https://blogs.mathworks.com/steve/information/small-circle.png”;
BackgroundColor = “blue”,…
HorizontalAlignment = “heart”,…
VerticalAlignment = “center”,…
title(“Circularity as measured in earlier releases”)
Measuring Perimeter
In truth, measuring perimeter is what will get the frequent circularity computation technique in bother. Measuring the perimeter of objects in digital pictures is often executed by tracing alongside from one pixel heart to the subsequent, after which including up weights which can be decided by the angles between successive segments.
plot(b{1}(:,1),b{1}(:,2),Colour = [0.850 0.325 0.098],…
maintain off
The reason for the circularity computation bias might be seen within the determine above. The perimeter is being calculated primarily based on a path that connects pixel facilities. A few of the pixels, although, lie partially exterior the pink curve. The perimeter, then, is being calculated alongside a curve that doesn’t utterly comprise all the sq. pixels; the curve is only a bit too small. Relative to the realm computation, then, the perimeter computation is being underestimated. Since perimeter is within the denominator of the circularity formulation, the ensuing worth is simply too excessive.
Can we repair the issue by tracing the perimeter path in another way? Let’s attempt with a digitized sq. at a 45-degree angle.
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 0 0
0 0 0 0 1 1 1 1 1 0 0 0 0
0 0 0 1 1 1 1 1 1 1 0 0 0
0 0 1 1 1 1 1 1 1 1 1 0 0
0 1 1 1 1 1 1 1 1 1 1 1 0
0 0 1 1 1 1 1 1 1 1 1 0 0
0 0 0 1 1 1 1 1 1 1 0 0 0
0 0 0 0 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 ];
Right here is the trail traced by regionprops for computing the perimeter.
outlinePixels(dimension(masks))
plot(x,y,Colour = [0.850 0.325 0.098])
maintain off
The perimeter of the pink sq. is $4 cdot 5 sqrt{2} approx 28.3$. The would correspond to an space of $(5 sqrt{2})^2$. Nevertheless, the variety of white squares is 61. The estimated perimeter and space are inconsistent with one another, which is able to lead to a biased circularity measurement.
Can we repair it by tracing the perimeter alongside the outer factors of the pixels, like this?
x = [1.5 6.5 7.5 12.5 12.5 7.5 6.5 1.5 1.5];
y = [6.5 1.5 1.5 6.5 7.5 12.5 12.5 7.5 6.5];
outlinePixels(dimension(masks))
plot(x,y,Colour = [0.850 0.325 0.098])
maintain off
Now the calculated perimeter goes to be too excessive as a result of it corresponds to an space that’s a lot higher than 61, the variety of white pixels.
perim = sum(sqrt(sum(diff([x(:) y(:)]).^2,2)))
For a sq., that perimeter corresponds to this space:
This time, the estimated perimeter is simply too excessive with respect to the estimated space, and so the computed circularity can be biased low.
What if we compute the perimeter by tracing alongside the pixel edges?
x = [1.5 2.5 2.5 3.5 3.5 4.5 4.5 5.5 5.5 6.5 6.5 …
7.5 7.5 8.5 8.5 9.5 9.5 10.5 10.5 11.5 11.5 12.5 12.5 …
11.5 11.5 10.5 10.5 9.5 9.5 8.5 8.5 7.5 7.5 6.5 6.5 …
5.5 5.5 4.5 4.5 3.5 3.5 2.5 2.5 1.5 1.5];
y = [7.5 7.5 8.5 8.5 9.5 9.5 10.5 10.5 11.5 11.5 …
12.5 12.5 11.5 11.5 10.5 10.5 9.5 9.5 8.5 8.5 …
7.5 7.5 6.5 6.5 5.5 5.5 4.5 4.5 3.5 3.5 2.5 2.5 1.5 1.5 …
2.5 2.5 3.5 3.5 4.5 4.5 5.5 5.5 6.5 6.5 7.5];
outlinePixels(dimension(masks))
plot(x,y,Colour = [0.850 0.325 0.098], LineWidth = 5)
maintain off
However now the calculated perimeter is WAY too excessive with respect to the realm, so the computed circularity can be very low.
perim = sum(sqrt(sum(diff([x(:) y(:)]).^2,2)))
Bias Correction Mannequin
In spite of everything that, we determined to depart the perimeter tracing technique alone. As a substitute, we got here up with a easy approximate mannequin for the circularity bias after which used that mannequin to derive a correction issue.
Contemplate a circle with radius r. We are able to mannequin the bias by computing circularity utilizing space that’s calculated from r and perimeter that’s calculated from $r – 1/2$. The end result, $c’$, is the mannequin of the biased circularity.
$c’ = frac{1}{1 – frac{1}{r} + frac{0.25}{r^2}} = frac{1}{left(1 – frac{0.5}{r}proper)^2}$
How effectively does $c’$ match what the previous regionprops computation was returning? Here’s a comparability carried out on digitized circles with a variety of radii.
However what ought to we do for basic shapes? In spite of everything, if we already know it is a circle, then there isn’t any massive must compute the circularity metric, proper?
This is the technique: Given the computed space, a, decide an equal radius, $r_{textual content{eq}}$, which is the radius of a circle with the identical space. Then, use $r_{textual content{eq}}$ to derive a bias correction issue:
$c_{textual content{corrected}} = cleft(1 – frac{0.5}{r_{textual content{eq}}}proper)^2 = cleft(1-frac{0.5}{sqrt{a/pi}}proper)^2$
Does It Work?
We simply made a giant assumption there, computing $r_{textual content{eq}}$ as if our form is a circle. Can we actually do this? Nicely, we did a bunch of experiments, utilizing numerous sorts of shapes, scaled over a wide variety of sizes, and rotated at numerous angles. Listed below are the outcomes for one experiment, utilizing an equilateral triangle with a base rotated off the horizontal axis by 20 levels. The blue curve is the circularity computed in earlier releases; the pink curve is the corrected circularity as computed in R2023a, and the horizontal orange line is the theoretical worth.
We noticed comparable curves for a broad vary of shapes. For some shapes, with a theoretical circularity worth under round 0.2, the correction didn’t enhance the end result. On stability, nonetheless, we determined that the correction technique was worthwhile and that regionprops ought to be modified to include it.
Helper Operate
operate outlinePixels(sz)
xline(ok, Colour = [.7 .7 .7]);
yline(ok, Colour = [.7 .7 .7]);