最小二乘法圆拟合(附完整代码)

文章目录

  • 一、2D圆弧拟合
    • 1、不经过给定起点与终点
    • 2、精确经过给定起点与终点
  • 二、3D圆弧拟合

一、2D圆弧拟合

1、不经过给定起点与终点

  平面圆的一般方程为:
x 2 + y 2 + a x + b y + c = 0 (1) x^2 + y^2 + ax + by +c = 0\tag 1 x2+y2+ax+by+c=0(1)
  其中, a , b , c ∈ R a,b,c\in R a,b,cR
  式(1)配方,可以得到:
( x + a / 2 ) 2 + ( x + b / 2 ) 2 = a 2 / 4 + b 2 / 4 − c (2) (x + a/2)^2 + (x + b/2)^2 = a^2/4 + b^2/4 - c \tag 2 (x+a/2)2+(x+b/2)2=a2/4+b2/4c(2)

  对于给定的一系列二维数据 ( x i , y i ) , i = 0 , . . . , n (x_i,y_i),i=0,...,n (xi,yi),i=0,...,n,根据式(1)可以列出 n + 1 n+1 n+1个线性方程,然后可以采用最小二乘法求解,非常简单有效。
  不经过给定起点与终点的2D圆弧拟合另一种方法可参考:最小二乘法拟合圆。

2、精确经过给定起点与终点

  有时候我们需要约束圆弧精确经过给定起点与终点,设起点坐标为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),终点坐标为 ( x n , y n ) (x_n,y_n) (xn,yn),则有约束等式:
{ x 0 2 + y 0 2 + a x 0 + b y 0 + c = 0 x n 2 + y n 2 + a x n + b y n + c = 0 (3) \begin{cases} x_0^2 + y_0^2 + ax_0 + by_0 +c = 0 \\ x_n^2 + y_n^2 + ax_n + by_n +c = 0 \\ \tag 3 \end{cases} {x02+y02+ax0+by0+c=0xn2+yn2+axn+byn+c=0(3)
  (1)若起点与终点坐标重合,则式(3)退化为一个约束等式,将参数 c c c的表达式代入到式(1),利用最小二乘法求解参数 a , b a,b a,b,再计算参数 c c c
  (2)若 x 0 ≠ x n x_0\ne x_n x0=xn,根据式(3)解出参数 a , c a,c a,c的表达式,然后代入到式(1),利用最小二乘法求解参数 b b b,再计算参数 a , c a,c a,c
  (3)若 y 0 ≠ y n y_0\ne y_n y0=yn,根据式(3)解出参数 b , c b,c b,c的表达式,然后代入到式(1),利用最小二乘法求解参数 a a a,再计算参数 b , c b,c b,c

  circle_fitting_2D.m

function [ center, R, fittingError ] = circle_fitting_2D( points, pointCount, crossStartAndEndPointFlag )
%{
Function: circle_fitting_2D
Description: 2D圆弧拟合
Input: 二维点points, 点个数pointCount, 是否经过起点/终点标志位crossStartAndEndPointFlag
Output: 圆心center, 半径R, 拟合误差fittingError
Author: Marc Pony(marc_pony@163.com)
圆的方程:x^2 + y^2 + a*x + b*y +c = 0  -> (x + a/2)^2 + (x + b/2)^2 = a^2/4 + b^2/4 - c
%}
if crossStartAndEndPointFlag == 0
    x = points(:, 1);
    y = points(:, 2);
    A = [x, y, ones(size(x))];
    B = -x.^2 - y.^2;
    temp = A \ B;
    
    a = temp(1);
    b = temp(2);
    c = temp(3);
else
    x0 = points(1, 1);
    y0 = points(1, 2);
    xn = points(pointCount, 1);
    yn = points(pointCount, 2);
    x = points(2 : pointCount - 1, 1);
    y = points(2 : pointCount - 1, 2);
    EPS = 1.0e-4;
    
    if abs(x0 - xn) < EPS && abs(y0 - yn) < EPS %起点与终点重合
        A = [x - x0, y - y0];
        B = x0^2 + y0^2 - x.^2 - y.^2;
        temp = A \ B;
        a = temp(1);
        b = temp(2);
        c = -x0^2 - y0^2 - a * x0 - b * y0;
    else
        if abs(x0 - xn) > abs(y0 - yn)
            A = x * (yn - y0) / (x0 - xn) + y - (x0 * yn - xn * y0) / (x0 - xn);
            B = -x.^2 - y.^2 - x * (xn^2 + yn^2 - x0^2 - y0^2) / (x0 - xn) + ((xn^2 + yn^2) * x0 - (x0^2 + y0^2) * xn) / (x0 - xn);
            b = A \ B;
            P = -x0^2 - y0^2 - b * y0;
            Q = -xn^2 - yn^2 - b * yn;
            a = (P - Q) / (x0 - xn);
            c = -(P * xn - Q * x0) / (x0 - xn);
        else
            A = x * (xn - x0) / (y0 - yn) + y - (y0 * xn - yn * x0) / (y0 - yn);
            B = -x.^2 - y.^2 - x * (yn^2 + xn^2 - y0^2 - x0^2) / (y0 - yn) + ((yn^2 + xn^2) * y0 - (y0^2 + x0^2) * yn) / (y0 - yn);
            a = A \ B;
            P = -y0^2 - x0^2 - a * x0;
            Q = -yn^2 - xn^2 - a * xn;
            b = (P - Q) / (y0 - yn);
            c = -(P * yn - Q * y0) / (y0 - yn);
        end
    end
end

R = sqrt(a^2 / 4 + b^2 / 4 - c);
center(1) = -a / 2;
center(2) = -b / 2;
fittingError = sqrt((points(:, 1) - center(1)).^2 + (points(:, 2) - center(2)).^2) - R;

end

  test_circle_fitting_2D.m

clc
clear
close all

%% 绘参考圆
figure
axis([0 100 0 100])
theta = linspace(0, 2*pi, 1000);
r = 30;
x = 50 + r*cos(theta);
y = 50 + r*sin(theta);
plot(x,y,'g--')
hold on
axis equal

%% 左键点击取点,按回车键退出
pos = ginput();
%pos = [pos;pos(1,1), pos(1,2)];  %起点与终点重合
pointCount = size(pos, 1);
plot(pos(1, 1), pos(1, 2), 'k+')
plot(pos(pointCount, 1), pos(pointCount, 2), 'k+')
plot(pos(2:pointCount-1, 1), pos(2:pointCount-1, 2), 'o')

%% 圆最小二乘拟合
crossStartAndEndPointFlag = 1; %0:不经过给定起点与终点;  1:精确经过给定起点与终点
[ center, R, fittingError ] = circle_fitting_2D( pos, pointCount, crossStartAndEndPointFlag )

x = center(1) + R * cos(theta);
y = center(2) + R * sin(theta);
plot(x, y, 'b')                   
plot(center(1), center(2), 'b+')
plot(center(1), center(2), 'bo')

最小二乘法圆拟合(附完整代码)_第1张图片

二、3D圆弧拟合

   3D圆弧拟合可以分解两个问题:
   (1)三维点的球面拟合(见博文:最小二乘法球面拟合(附完整代码))
   (2)平面拟合
  球面拟合后,球心便为3D圆弧的圆心,平面拟合则可以得到3D圆弧所在平面的法向量,3D圆弧的方程便确定。

你可能感兴趣的:(计算几何,最小二乘法,圆弧拟合,最小二乘法圆弧拟合,经过起点终点的圆弧拟合,空间圆弧拟合)