最近工作中需要判断焊球的图像圆不圆,于是DIY了一个算法,可以定量计算任意图像与圆的偏离程度。这里首先假设图像是单连通域的二值图(单连通不满足也可计算,二值图可以转化而来)。
第一步是计算形心:
def gravity_center(array):
"""计算重心,array的元素都是1或者0, 且只有一个连通域,计算1部分的重心"""
rows, cols = array.shape
sumx = 0
sumy = 0
for x in range(rows):
for y in range(cols):
sumx += array[x, y] * x
sumy += array[x, y] * y
center_x = sumx / array.sum()
center_y = sumy / array.sum()
return center_x, center_y第二步是计算等效半径。我们可以从圆(本篇指圆盘)开始考虑。
设R为圆的直径,A为圆的面积,J为圆的转动惯量。

则有

根据这一思路我们可以计算任意图像的等效圆半径
def cal_radius(array):
rows, cols = array.shape
center_x, center_y = gravity_center(array)
J = 0.0
A = array.sum()
for x in range(rows):
for y in range(cols):
if array[x, y]:
d_square = (x - center_x) ** 2 + (y - center_y) ** 2
J += d_square
radius = math.sqrt(2 * J / A)
return radius最后就是计算图形和等效圆的差异。
可以把图像上超出等效圆的部分称为凸起,图像边界之外等效圆以内的部分称为凹陷。二者可同等对待。设O为等效圆的圆心,设P为凸起或凹陷区域内任意一点,设K为直线OP与等效圆边界的交点。则可对KP的平方在整个凸起和凹陷区域A上进行积分。积分结果除以A的面积之后开根号,则是KP的”平均”长度的。将其无量纲化,即除以R,即可用来刻画图像偏离圆的程度。

def circle_roughness(array, radius):
rows, cols = array.shape
center_x, center_y = gravity_center(array)
sum_ = 0.0
sum_area = 0
for x in range(rows):
for y in range(cols):
d_square = (x - center_x) ** 2 + (y - center_y) ** 2
d = math.sqrt(d_square)
if (d < radius and array[x, y] == 0) or (d > radius and array[x, y] == 1):
# 凹坑 inside circle or 凸起 outside circle
sum_ += (radius - d) ** 2
sum_area += 1
# print(x, y, array[x, y], d)
h = math.sqrt(sum_ / sum_area) # 平均起伏
return h / radius # 越小越圆,无量纲。程序其它非关键部分:
import numpy as np
from matplotlib import image
import math
import cv2
if __name__ == "__main__":
import matplotlib
from matplotlib import pyplot as plt
#imPath = r"moon.jpg"
imPath = r"circle.jfif"
imPath = r"square.jfif"
#imPath = r"square2.jpg"
#imPath = r"5angle.jpg"
im0 = image.imread(imPath)
gray = cv2.cvtColor(im0, cv2.COLOR_BGR2GRAY)
print(gray.shape)
black_white = np.zeros(gray.shape)
#black_white[np.where(gray > 10)] = 1 # for moon.jpg
black_white[np.where(gray < 50)] = 1 # for black circle or black square
plt.imshow(im0)
plt.show()
plt.imshow(black_white, cmap=matplotlib.cm.gray)
center_X, center_Y = gravity_center(black_white)
print(f"center_x, center_y = {center_X}, {center_Y}")
R = cal_radius(black_white)
print(f"等效半径 = {R} pix")
print(f"等效圆相对偏离度 = {circle_roughness(black_white, R)} ")
plt.show()对于正方形(不妨设边长为2),这个相对偏离度的理论值的计算过程如下:





等效圆相对偏离度 = 0.07485999995045131
改变大小和角度后:

等效圆相对偏离度 = 0.07515387089789077
和理论值都很接近。

等效圆相对偏离度 = 0.00029343583223142254
对于圆,理论值是0。这里非零的原因有两个,一是因为图像是离散的,像素不是无穷小,二是因为计算误差。

等效圆相对偏离度 = 0.2588976795687409

等效圆相对偏离度 = 0.14882923003105267

等效圆相对偏离度 = 0.48937452632099054


等效圆相对偏离度 = 0.20005032570252199
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!