首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何定量判断图形有多圆?

如何定量判断图形有多圆?

作者头像
用户6021899
发布2021-12-07 17:35:46
发布2021-12-07 17:35:46
9200
举报

最近工作中需要判断焊球的图像圆不圆,于是DIY了一个算法,可以定量计算任意图像与圆的偏离程度。这里首先假设图像是单连通域的二值图(单连通不满足也可计算,二值图可以转化而来)。

第一步是计算形心:

代码语言:javascript
复制
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为圆的转动惯量。

则有

根据这一思路我们可以计算任意图像的等效圆半径

代码语言:javascript
复制
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,即可用来刻画图像偏离圆的程度。

代码语言:javascript
复制

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  # 越小越圆,无量纲。

程序其它非关键部分:

代码语言:javascript
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档