一、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,c∈R。 ??式(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/4?c(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个线性方程,然后可以采用最小二乘法求解,非常简单有效。
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')
二、3D圆弧拟合
?? 3D圆弧拟合可以分解两个问题: ?? (1)三维点的球面拟合(见博文:最小二乘法球面拟合(附完整代码)) ?? (2)平面拟合 ??球面拟合后,球心便为3D圆弧的圆心,平面拟合则可以得到3D圆弧所在平面的法向量,3D圆弧的方程便确定。
|