基于周长与面积的简单圆形Circularity计算异常问题排查
OpenCV计算圆形Circularity值异常问题排查
问题背景
Circularity用于衡量形状与圆形的相似度,标准公式为:
Sample Circularity = (4 * π * Sample Area) / (Sample Perimeter²)
完美圆形的该值为1,偏离圆形则小于1。
但使用Python+OpenCV计算自行生成的理想圆形时,结果始终为1.11;若将周长替换为len(cnt[0]),结果为0.81,均不符合预期。
用户的计算代码:
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))
测试用圆形生成代码:
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)
问题原因
- 公式完全写反:用户代码中计算的是
Perimeter²/(4π*Area),和标准定义的(4π*Area)/Perimeter²互为倒数。完美圆的理论值代入该错误公式会得到1,但实际因像素离散性,结果接近1的倒数(1.11)。 - 像素轮廓的离散性:OpenCV生成的圆形是像素级的近似多边形,并非数学上的完美圆。
cv2.arcLength计算的是离散轮廓的近似周长,cv2.contourArea计算的是轮廓包围的像素面积,两者都存在微小误差。 - 错误的周长计算方式:用
len(cnt[0])作为周长完全错误——轮廓点数量不等于实际周长,相邻轮廓点的距离可能是1(水平/垂直)或√2(对角线),直接用点数计算会严重低估实际周长。
解决方案
- 修正Circularity计算公式:改为符合标准定义的形式:
Circularity = (4 * math.pi * Area) / (Perimeter ** 2)
- 接受像素级误差:即使修正公式,结果也会接近1但并非严格1(比如约0.99),这是像素离散化导致的正常误差,属于可接受范围。
- 优化测试图像生成:直接生成单通道灰度图,避免通道转换的潜在问题:
import cv2 import numpy as np # 直接生成单通道灰度图 Fill_Circle = np.zeros((1000, 1000), dtype=np.uint8) cv2.circle(Fill_Circle, (500, 500), 450, 255, -1) cv2.imwrite(Path_to_Save, Fill_Circle)
验证结果
修正公式后,运行代码得到的Circularity值会接近1(比如0.99),符合近似完美圆的预期结果。
内容的提问来源于stack exchange,提问作者Aref Shaker
相关产品推荐
相关产品推荐

