Circularity signifies the comparability of the shape to a circle. A measure of circularity is the shape area to the circle area ratio having an identical perimeter (we denote it as Circle Area) as represented in equation below.
Sample Circularity = Sample Area / Circle Area
Let the perimeter of shape be P, so
P = 2 * pi * r
then
P^2 = 4 * pi^2 r^2 = 4 * pi * (pi * r^2) = 4 * pi * Circle Area. Thus
Circle Area = Sample Perimeter^2 / (4 * pi)
which implies
Sample Circularity = (4 * pi * Sample Area) / (Sample Perimeter^2)
So with help of math, there is no need to find an algorithm to calculate fit circle or draw it on a right way over shape or etc.
This statistic equals 1 for a circular object and less than 1 for an object that departs from circularity, except that it is relatively insensitive to irregular boundaries.
ok, that's fine, but ... .
In python i try calculate circularity for a simple circle but always i got 1.11. My python approach is:
import cv2
import math
Gray_image = cv2.imread(Input_Path, cv2.IMREAD_GRAYSCALE)
cnt , her = cv2.findContours(Gray_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
Perimeter = cv2.arcLength(cnt[0], True)
Area = cv2.contourArea(cnt[0])
Circularity = math.pow(Perimeter, 2) / (4 * math.pi * Area)
print(round(Circularity , 2))
If i use
Perimeter = len(cnt[0])
then answer is 0.81 which is incorrect again. Thank you for taking the time to answer.
To draw a circle, use following command:
import cv2
import numpy as np
Fill_Circle = np.zeros((1000, 1000, 3))
cv2.circle(Fill_Circle, (500, 500), 450, (255, 255, 255), -1)
cv2.imwrite(Path_to_Save, Fill_Circle)
CodePudding user response:
As I mentioned in this recent answer to a related question, OpenCV's perimeter estimate is not good enough to compute the circularity feature. OpenCV computes the perimeter by adding up all the distances between vertices of the polygon built from the edge pixels of the image. This length is typically larger than the actual perimeter of the actual object imaged. This blog post of mine describes the problem well, and provides a better way to estimate the perimeter of an object from a binary image.
This better method is implemented (among other places) in DIPlib, in the function dip.MeasurementTool.Measure(), as the feature "Perimeter". [Disclosure: I'm an author of DIPlib].
The feature "Roundness" implements what you refer to a circularity here (these feature names are used interchangeably in the literature). There is a different feature referred to as "Circularity" in DIPlib, which does not depend on the perimeter and typically is more precise if the shape is close to a circle.
This is how you would use that function:
import diplib as dip
import cv2
import numpy as np
Fill_Circle = np.zeros((1000, 1000, 3))
cv2.circle(Fill_Circle, (500, 500), 450, (255, 255, 255), -1)
labels = dip.Label(Fill_Circle[:, :, 0] > 0)
msr = dip.MeasurementTool.Measure(labels, features=["Perimeter", "Size", "Roundness", "Circularity"])
print(msr)
Circularity = msr[1]["Roundness"][0]
For your circle, I see:
- area = 636121.0
- perimeter = 2829.27
- roundness = 0.9986187 (this is what you refer to as circularity)
- circularity = 0.0005368701 (closer to 0 means more like a circle)