圆的散点拟合, 已知圆的采样点, 求圆的圆心和半径.

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

问题描述

首先还是先来描述一下问题,
假如我们有一个采样数据 A = { a 1 , a 2 , ⋯   , a N } A=\{a_1,a_2, \cdots, a_N\} A={a1,a2,,aN}, 其中 a i a_i ai,
是n维空间中点的坐标向量. 我们希望去拟合一个圆心 x x x, 和一个半径 r r r,
注意 x x x是一个n维向量而 r r r是一个标量. 注意重申一下我们的已知集合 A A A,
未知 x , r x, r x,r.

求解过程

首先, 我们需要写出我们的最优化化方程

arg ⁡ min ⁡ x , r = ∑ i = 1 N [ ∥ x − a i ∥ 2 2 − r 2 ] 2 \arg\min_{x,r}=\sum_{i=1}^{N}[\|x-a_i\|_2^2-r^2]^2 argx,rmin=i=1N[xai22r2]2

接下来我们来分析下中括号内部的这个东西怎么来写.

∥ x − a i ∥ 2 2 − r 2 = ( x − a i ) T ( x − a i ) − r 2 = ( x T − a i T ) ( x − a i ) − r 2 = x T x − 2 a i T x + a i T a i − r 2 \left. \begin{aligned} \|x-a_i\|_2^2-r^2&=(x-a_i)^T(x-a_i)-r^2\\ &=(x^T-a_i^T)(x-a_i)-r^2\\ &=x^Tx-2a_i^Tx+a_i^Ta_i-r^2\\ \end{aligned} \right. xai22r2=(xai)T(xai)r2=(xTaiT)(xai)r2=xTx2aiTx+aiTair2

对于上式最后的一个等式, 我们可以构造一个成新的形式

x T x − 2 x T a i + a i T a i − r 2 = a i T a i − ( a i T 1 ) ( 2 x r 2 − x T x ) x^Tx-2x^Ta_i+a_i^Ta_i-r^2 = a_i^Ta_i-\left( \begin{array}{cc} a_i^T& 1 \end{array} \right)\left( \begin{array}{c} 2x \\ r^2-x^Tx \end{array} \right) xTx2xTai+aiTair2=aiTai(aiT1)(2xr2xTx)

接下来令 y = ( 2 x r 2 − x T x ) , b i = ( a i 1 ) y=\left( \begin{array}{c} 2x \\ r^2-x^Tx \end{array} \right), b_i = \left( \begin{array}{c} a_i \\ 1 \end{array} \right) y=(2xr2xTx),bi=(ai1) 可得
arg ⁡ min ⁡ x , r = ∑ i = 1 N [ ∥ x − a i ∥ 2 2 − r 2 ] 2 ⇒ arg ⁡ min ⁡ y ∑ i = 1 N { a i T a i − b i T y } 2 \arg\min_{x,r}=\sum_{i=1}^{N}[\|x-a_i\|_2^2-r^2]^2 \Rightarrow \arg\min_{y}\sum_{i=1}^{N}\{a_i^Ta_i-b_i^Ty\}^2 argx,rmin=i=1N[xai22r2]2argymini=1N{aiTaibiTy}2
再次令
B T = { b 1 , b 2 , ⋯   , b N } , d T = { ∥ a 1 ∥ 2 2 , ∥ a 2 ∥ 2 2 , ⋯   , ∥ a N ∥ 2 2 } B^T=\{b_1,b_2, \cdots, b_N\}, d^T=\{\|a_1\|_2^2, \|a_2\|_2^2, \cdots, \|a_N\|_2^2\} BT={b1,b2,,bN},dT={a122,a222,,aN22}
可得, 最终的优化方程为 arg ⁡ min ⁡ y ∥ B y − d ∥ 2 2 \arg\min_{y}\|By-d\|^2_2 argyminByd22

至此, 我们实际上就得到了一个非常简单的线性最小二乘法方程.
解得 y = ( B T B ) + B T d y=(B^{T}B)^{+}B^{T}d y=(BTB)+BTd之后. 我们就可以很顺利方便的求出 x , r x,r x,r.( C + C^{+} C+
C C C的伪逆)

x i = 1 2 y i , i ∈ { 1 , 2 , ⋯   , n } , r = y n + 1 + x T x x_i=\frac{1}{2}y_i, i\in\{1,2,\cdots, n\}, r=\sqrt{y_{n+1}+x^Tx} xi=21yi,i{1,2,,n},r=yn+1+xTx

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
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值