最小二乘法拟合空间直线

最小二乘法拟合空间直线

注:本文借鉴了 博客1博客2 这两篇博客

空间直线的一种表达方式:(点向式)
x − x 0 m = y − y 0 n = z − z 0 k \frac {x-x_0}{m}= \frac{y-y_0}{n}= \frac{z-z_0}{k} mxx0=nyy0=kzz0

方法一

可以将该公式转换为如下形式:
{ x = x 0 + m k ( z − z 0 ) y = y 0 + n k ( z − z 0 ) \left\{ \begin{aligned} x&=x_0+\frac{m}{k}(z-z_0) \\ \\ y&=y_0+\frac{n}{k}(z-z_0) \end{aligned} \right. xy=x0+km(zz0)=y0+kn(zz0)
令 方程为
{ x = k 1 z + b 1 y = k 2 z + b 2 \left\{ \begin{aligned} x&=k_1z+b_1 \\ y&=k_2z+b_2 \end{aligned} \right. {xy=k1z+b1=k2z+b2
其中
k 1 = m k , b 1 = x 0 − m k z 0 k 2 = n k , b 2 = y 0 − n k z 0 \begin{aligned} k_1 &= \frac{m}{k},&b_1 &= x_0 -\frac{m}{k}z_0 \\\\ k_2 &= \frac{n}{k},&b_2 &= y_0 -\frac{n}{k}z_0 \end{aligned} k1k2=km,=kn,b1b2=x0kmz0=y0knz0
利用残差的平方和
Q 1 = ∑ i = 1 n ( x i − k 1 z i − b 1 ) 2 Q 2 = ∑ i = 1 n ( y i − k 2 z i − b 2 ) 2 Q_1=\displaystyle\sum_{i=1}^n(x_i-k_1z_i-b_1)^2 \\ Q_2=\displaystyle\sum_{i=1}^n(y_i-k_2z_i-b_2)^2 Q1=i=1n(xik1zib1)2Q2=i=1n(yik2zib2)2
为使得 Q 1 Q_1 Q1, Q 2 Q_2 Q2最小,则应满足:
{ ∂ Q 1 ∂ k 1 = 0 , ∂ Q 1 ∂ b 1 = 0 ∂ Q 2 ∂ k 2 = 0 , ∂ Q 2 ∂ b 2 = 0 \left\{ \begin{aligned} \frac{\partial Q_1}{\partial k_1}=0, \frac{\partial Q_1}{\partial b_1}=0\\ \frac{\partial Q_2}{\partial k_2}=0, \frac{\partial Q_2}{\partial b_2}=0\\ \end{aligned} \right. k1Q1=0,b1Q1=0k2Q2=0,b2Q2=0

{ ∑ i = 1 n 2 ( x i − k 1 z i − b 1 ) × ( − z i ) = 0 ∑ i = 1 n 2 ( x i − k 1 z i − b 1 ) × ( − 1 ) = 0 ∑ i = 1 n 2 ( y i − k 2 z i − b 2 ) × ( − z i ) = 0 ∑ i = 1 n 2 ( y i − k 2 z i − b 2 ) × ( − 1 ) = 0 \left\{ \begin{aligned} &\displaystyle\sum_{i=1}^n2(x_i-k_1z_i-b_1)\times (-z_i) =0\\ &\displaystyle\sum_{i=1}^n2(x_i-k_1z_i-b_1)\times (-1) =0\\ &\displaystyle\sum_{i=1}^n2(y_i-k_2z_i-b_2)\times (-z_i) =0\\ &\displaystyle\sum_{i=1}^n2(y_i-k_2z_i-b_2)\times (-1) =0\\ \end{aligned} \right. i=1n2(xik1zib1)×(zi)=0i=1n2(xik1zib1)×(1)=0i=1n2(yik2zib2)×(zi)=0i=1n2(yik2zib2)×(1)=0
联立上面的方程,得:
{ k 1 = n ∑ x i z i − ∑ x i ∑ z i n ∑ z 2 − ∑ z i ∑ z i b 1 = k 1 ∑ z i − ∑ x i n k 2 = n ∑ y i z i − ∑ y i ∑ z i n ∑ z 2 − ∑ z i ∑ z i b 2 = k 2 ∑ z i − ∑ y i n \left\{ \begin{aligned} &k_1=\frac{n\sum x_iz_i-\sum x_i\sum z_i}{n\sum z^2-\sum z_i\sum z_i}\\\\ &b_1=\frac{k1\sum z_i-\sum x_i}{n}\\\\ &k_2=\frac{n\sum y_iz_i-\sum y_i\sum z_i}{n\sum z^2-\sum z_i\sum z_i}\\\\ &b_2=\frac{k2\sum z_i-\sum y_i}{n} \end{aligned} \right. k1=nz2zizinxizixizib1=nk1zixik2=nz2zizinyiziyizib2=nk2ziyi

求解出 k 1 , k 2 , b 1 , b 2 k_1,k_2,b_1,b_2 k1,k2,b1,b2,即得出直线方程
当直线不平行于xoy平面时 ( \big( (该直线过点( b 1 b_1 b1, b 2 b_2 b2, 0),法向量为( k 1 k_1 k1, k 2 k_2 k2, 1) ) \big) )

代码中的结构体

// (x-x0)/m = (y-y0)/n = (z-z0)/k
struct SpaceLine
{
    double x;
    double y;
    double z;
    double m;
    double n;
    double k;
    SpaceLine() = default;
        SpaceLine(double x, double y, double z, double m, double n, double k) : x(x), y(y), z(z), m(m), n(n), k(k) { }
};

struct Point3d
{
    double x;
    double y;
    double z;
    Point3d() = default;
    Point3d(double x, double y, double z) : x(x), y(y), z(z) { }
};

c++代码

using std::vector;

SpaceLine fit3dline(vector<Point3d> const & data)
{
	int n = data.size();
	double sum_xz = 0, sum_x = 0, sum_z = 0, sum_zz = 0, sum_yz = 0, sum_y = 0;

	for (Point3d const& p : data)
	{
		sum_xz += p.x * p.z;
		sum_x += p.x;
		sum_z += p.z;
		sum_zz += std::pow(p.z, 2);
		sum_yz += p.z * p.y;
		sum_y += p.y;
	}
	double k1 = (n * sum_xz - sum_x * sum_z) / (n * sum_zz - pow(sum_z, 2));
	double b1 = (sum_x - k1 * sum_z) / n;

	double k2 = (n * sum_yz - sum_y * sum_z) / (n * sum_zz - pow(sum_z, 2));
	double b2 = (sum_y - k2 * sum_z) / n;

	return SpaceLine(b1, b2, 0, k1, k2, 1);
}

方法二

当直线不平行于xoy平面时,令 z 0 z_0 z0 = 0,k =1,简化该方程为:
x − x 0 m = y − y 0 n = z 1 \frac {x-x_0}{m}= \frac{y-y_0}{n}= \frac{z}{1} mxx0=nyy0=1z
{ x = m z + x 0 y = n z + y 0 \left\{ \begin{aligned} x &=mz+x_0 \\ y&=nz+y_0 \end{aligned} \right. {xy=mz+x0=nz+y0
表现成矩阵形式为:
[ m x 0 n y 0 ] [ z 1 ] = [ x y ] \begin{bmatrix} m & x_0 \\ n & y_0\\ \end{bmatrix} \begin{bmatrix} z \\ 1\\ \end{bmatrix}= \begin{bmatrix} x\\y\\ \end{bmatrix} [mnx0y0][z1]=[xy]
当有n个点时第i个点的方程为:
[ m x 0 n y 0 ] [ z i 1 ] = [ x i y i ] \begin{bmatrix} m & x_0 \\ n & y_0\\ \end{bmatrix} \begin{bmatrix} z_i \\ 1\\ \end{bmatrix}= \begin{bmatrix} x_i\\y_i\\ \end{bmatrix} [mnx0y0][zi1]=[xiyi]
并联n个方程得到:
[ m x 0 n y 0 ] [ z ⋯ z n 1 ⋯ 1 ] = [ x 1 ⋯ x n y 1 ⋯ y n ] \begin{bmatrix} m & x_0 \\ n & y_0\\ \end{bmatrix} \begin{bmatrix} z & \cdots &z_n\\ 1& \cdots &1\\ \end{bmatrix}= \begin{bmatrix} x_1 & \cdots & x_n\\ y_1 & \cdots & y_n\\ \end{bmatrix} [mnx0y0][z1zn1]=[x1y1xnyn]
最小二乘拟合:
[ m x 0 n y 0 ] [ z ⋯ z n 1 ⋯ 1 ] [ z 1 1 ⋮ ⋮ z n 1 ] = [ x 1 ⋯ x n y 1 ⋯ y n ] [ z 1 1 ⋮ ⋮ z n 1 ] \begin{bmatrix} m & x_0 \\ n & y_0\\ \end{bmatrix} \begin{bmatrix} z & \cdots &z_n\\ 1& \cdots &1\\ \end{bmatrix} \begin{bmatrix} z_1 &1\\ \vdots & \vdots\\ z_n& 1\\ \end{bmatrix}= \begin{bmatrix} x_1 & \cdots & x_n\\ y_1 & \cdots & y_n\\ \end{bmatrix} \begin{bmatrix} z_1 &1\\ \vdots & \vdots\\ z_n& 1\\ \end{bmatrix} [mnx0y0][z1zn1] z1zn11 =[x1y1xnyn] z1zn11
化简为:
[ m x 0 n y 0 ] = [ ∑ x i z i ∑ x i ∑ y i z i ∑ y i ] [ ∑ z i 2 ∑ z i ∑ z i n ] − 1 \begin{bmatrix} m & x_0 \\ n & y_0\\ \end{bmatrix} = \begin{bmatrix} \sum x_iz_i & \sum x_i\\ \sum y_iz_i & \sum y_i\\ \end{bmatrix} \begin{bmatrix} \sum z_i^2 & \sum z_i\\ \sum z_i & n\\ \end{bmatrix} ^{-1} [mnx0y0]=[xiziyizixiyi][zi2zizin]1
求出 m , n , x 0 , y 0 m,n,x_0,y_0 m,n,x0,y0后 ,该直线过( x 0 x_0 x0, y 0 y_0 y0, 0),法向量为(m,n,1)

c++代码

using std::vector;
// 还运用了eigen库,进行矩阵的运算

SpaceLine fit3dline(vector<Point3d> const & data)
{
	int n = data.size();
	double sum_xz = 0, sum_x = 0, sum_yz = 0, sum_y = 0, sum_zz = 0, sum_z = 0;

	for (Point3d const & p : data)
	{
		sum_xz += p.x*p.z;
		sum_x += p.x;
		sum_yz += p.y*p.z;
		sum_y += p.y;
		sum_zz += pow(p.z, 2);
		sum_z += p.z;
	}

	Eigen::MatrixXf mat1(2, 2);
	mat1 <<
		sum_xz, sum_x,
		sum_yz, sum_y;

	Eigen::MatrixXf mat2(2, 2);
	mat2 <<
		sum_zz, sum_z,
		sum_z, n;

	Eigen::MatrixXf mat_result = mat1 * mat2.inverse();

	Eigen::MatrixXf &r = mat_result;

	return SpaceLine(r(0, 1), r(1, 1), 0, r(0, 0), r(1, 0), 1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值