圆的散点拟合, 已知圆的采样点, 求圆的圆心和半径.
程序员文章站
2022-03-31 20:53:12
...
UTF8gbsn
本文介绍一个圆的拟合方法. 参照论文为 Coope, I. D. (1993). Circle fitting
by linear and nonlinear least squares. Journal of Optimization Theory
and Applications, 76(2), 381–388. https://doi.org/10.1007/BF00939613
问题描述
首先还是先来描述一下问题,
假如我们有一个采样数据, 其中,
是n维空间中点的坐标向量. 我们希望去拟合一个圆心, 和一个半径,
注意是一个n维向量而是一个标量. 注意重申一下我们的已知集合,
未知.
求解过程
首先, 我们需要写出我们的最优化化方程
接下来我们来分析下中括号内部的这个东西怎么来写.
对于上式最后的一个等式, 我们可以构造一个成新的形式
接下来令 可得
再次令
可得, 最终的优化方程为
至此, 我们实际上就得到了一个非常简单的线性最小二乘法方程.
解得之后. 我们就可以很顺利方便的求出.(
是的伪逆)
python 代码实现
我们在2D上实现这个算法. 也就是拟合一个平面圆圈.
- 首先, 产生试验数据, 生成一个圆并进行均匀采样,
采样的时候随机加入噪声.
def genPoints(r, c, n):
'''
r: radius
c: center
n: sample's number
'''
if n <= 10:
n = 10
points = []
for k in range(n):
angle = 2*np.math.pi * k / n
x = np.math.cos(angle) * r + np.random.rand()*0.01*r
y = np.math.sin(angle) * r + np.random.rand()*0.01*r
p = [c[0]+x, c[1]+y]
points.append(p)
return points
- 进行线程方程组求解.
def circleFit(points):
# generates d
d = []
for p in points:
d.append(np.linalg.norm(p)**2)
d = np.array(d)
# generates B
B = []
for p in points:
v = p+[1]
B.append(v)
B = np.array(B)
tB = B.T
M = tB.dot(B)
invM = np.linalg.inv(M)
td = d.T
sd = td.dot(B)
y = invM.dot(sd)
center = [y[0]/2, y[1]/2]
radius = np.math.sqrt(y[2]+np.linalg.norm(center)**2)
return center, radius
- 调用代码和测试代码如下
points = genPoints(10, [2,7], 2000)
c, r = circleFit(points)
print(c, r)
# [2.0485439006362554, 7.051224621760529] 10.000426704550165
上一篇: matlab 求圆的周长和面积
下一篇: Matlab根据数据拟合圆及拟合效果对比