直线拟合(支持任意维空间的直线拟合,附代码)

2024-01-28 08:52

本文主要是介绍直线拟合(支持任意维空间的直线拟合,附代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

一、问题描述

  给定一系列的三维空间点 ( x i , y i , z i ) , i = 1 , 2 , . . . , n (x_i,y_i,z_i),i=1,2,...,n (xi,yi,zi),i=1,2,...,n,拟合得到直线的方程。本文的直线拟合方法适用于任意维空间的直线拟合,不失一般性,这里以三维空间的直线拟合为例。本文的直线拟合方法的基本思想参考博文:最小二乘法三维(k维)直线拟合。

二、推导步骤

  设直线的点向式方程为:
x − x 0 a = y − y 0 b = z − z 0 c = s (1) \frac{x-x_0}{a}=\frac{y-y_0}{b}=\frac{z-z_0}{c}=s \tag 1 axx0=byy0=czz0=s(1)
  由式(1),得到直线的参数方程为:
{ x = x 0 + a s y = y 0 + b s z = z 0 + c s (2) \left\{ \begin{array}{c} x=x_0+as \\ y=y_0+bs \\ \tag 2 z=z_0+cs\end{array}\right. x=x0+asy=y0+bsz=z0+cs(2)
  式(2)写成向量形式为:
L = L 0 + v s (3) \bm{L}=\bm{L_0}+\bm{v}s \tag 3 L=L0+vs(3)
  其中, L = [ x , y , z ] T \bm{L}=[x,y,z]^T L=[x,y,z]T L 0 = [ x 0 , y 0 , z 0 ] T \bm{L_0}=[x_0,y_0,z_0]^T L0=[x0,y0,z0]T为直线上任意一点, v = [ a , b , c ] T \bm{v}=[a,b,c]^T v=[a,b,c]T为直线的单位方向向量。
  如下图,红色点 L i ( x i , y i , z i ) L_i(x_i,y_i,z_i) Li(xi,yi,zi)为给定的一系列三维空间点,根据给定三维空间点,拟合直线方程(3),也就是计算 L 0 \bm{L_0} L0 v \bm{v} v,使得在某种“距离”的度量下,达到最佳的直线拟合效果。
在这里插入图片描述
  点 L i L_i Li到直线距离的平方为:
∣ ∣ Q i L i ∣ ∣ 2 = ∣ ∣ L 0 L i ∣ ∣ 2 − ∣ ∣ L 0 Q i ∣ ∣ 2 (4) ||\bm{Q_iL_i}||^2 = ||\bm{L_0L_i}||^2 -||\bm{L_0Q_i}||^2 \tag 4 ∣∣QiLi2=∣∣L0Li2∣∣L0Qi2(4)
   L 0 L i \bm{L_0L_i} L0Li在直线的投影的平方为:
∣ ∣ L 0 Q i ∣ ∣ 2 = ( L 0 L i ⋅ v ) 2 (5) ||\bm{L_0Q_i}||^2= (\bm{L_0L_i} \cdot \bm{v})^2\tag 5 ∣∣L0Qi2=(L0Liv)2(5)
  令向量 Y i = L 0 L i = L i − L 0 \bm{Y_i}=\bm{L_0L_i}=\bm{L_i}-\bm{L_0} Yi=L0Li=LiL0,式(4)写成:
∣ ∣ Q i L i ∣ ∣ 2 = ∣ ∣ Y i ∣ ∣ 2 − ( Y i ⋅ v ) 2 = Y i T Y i − ( v T Y i ) 2 (6) ||\bm{Q_iL_i}||^2 = ||\bm{Y_i}||^2 -(\bm{Y_i} \cdot \bm{v})^2= \bm{Y_i}^T \bm{Y_i} -(\bm{v}^T \bm{Y_i})^2 \tag 6 ∣∣QiLi2=∣∣Yi2(Yiv)2=YiTYi(vTYi)2(6)
  在最小二乘准则下,可以建立直线拟合的优化模型目标函数:
f = ∑ i = 1 n ∣ ∣ Q i L i ∣ ∣ 2 = ∑ i = 1 n [ Y i T Y i − ( v T Y i ) 2 ] (7) f=\sum\limits_{i=1}^{n} ||\bm{Q_iL_i}||^2 = \sum\limits_{i=1}^{n}[ \bm{Y_i}^T \bm{Y_i} -(\bm{v}^T \bm{Y_i})^2] \tag 7 f=i=1n∣∣QiLi2=i=1n[YiTYi(vTYi)2](7)
  计算 L 0 \bm{L_0} L0:
  目标函数 f f f对向量 Y i \bm{Y_i} Yi求偏导数:
∂ f ∂ Y i = ∑ i = 1 n ( 2 Y i − 2 v T Y i v ) = ∑ i = 1 n ( 2 Y i − 2 v v T Y i ) = ∑ i = 1 n 2 ( I − v v T ) Y i (8) \frac{ \partial f }{ \partial \bm{Y_i} }=\sum\limits_{i=1}^{n} ( 2\bm{Y_i} -2\bm{v}^T \bm{Y_i}\bm{v})=\sum\limits_{i=1}^{n} ( 2\bm{Y_i} -2\bm{v}\bm{v}^T \bm{Y_i})=\sum\limits_{i=1}^{n}2 (\bm{ I} -\bm{v}\bm{v}^T ) \bm{Y_i}\tag 8 Yif=i=1n(2Yi2vTYiv)=i=1n(2Yi2vvTYi)=i=1n2(IvvT)Yi(8)
  式(8)中,利用了恒等式 v T Y i v ≡ v v T Y i \bm{v}^T \bm{Y_i}\bm{v}\equiv \bm{v}\bm{v}^T \bm{Y_i} vTYivvvTYi,简单进行验算可以证明该恒等式。
  由于 v \bm{v} v为单位向量,可以证明 I − v v T ≠ 0 \bm{ I} -\bm{v}\bm{v}^T\ne \bm{0} IvvT=0
  因此
∑ i = 1 n Y i = ∑ i = 1 n ( L i − L 0 ) = ∑ i = 1 n L i − n L 0 = 0 (9) \sum\limits_{i=1}^{n}\bm{Y_i}= \sum\limits_{i=1}^{n}(\bm{L_i}-\bm{L_0})=\sum\limits_{i=1}^{n}\bm{L_i}-n\bm{L_0}=\bm{0}\tag 9 i=1nYi=i=1n(LiL0)=i=1nLinL0=0(9)
L 0 = 1 n ∑ i = 1 n L i (10) \bm{L_0}=\frac{1}{n}\sum\limits_{i=1}^{n}\bm{L_i}\tag {10} L0=n1i=1nLi(10)
  可以得到结论:待拟合的直线经过一个点 L 0 \bm{L_0} L0,该点的坐标为所有给定点的坐标平均值。如下图所示,一旦确定直线的单位方向向量 v \bm{v} v,则直线的方程便确定。
在这里插入图片描述
  计算 v \bm{v} v:
  对于单位向量 v \bm{v} v v T v = 1 \bm{v}^T\bm{v}=1 vTv=1,可以证明: Y i T Y i ≡ v T ( Y i T Y i ) v \bm{Y_i}^T \bm{Y_i} \equiv\bm{v^T}(\bm{Y_i}^T \bm{Y_i})\bm{v} YiTYivT(YiTYi)v ( v T Y i ) 2 ≡ v T ( Y i Y i T ) v (\bm{v}^T \bm{Y_i})^2 \equiv \bm{v}^T(\bm{Y_i}\bm{Y_i^T})\bm{v} (vTYi)2vT(YiYiT)v

  式(7)可改写成:
f = ∑ i = 1 n [ Y i T Y i − ( v T Y i ) 2 ] = ∑ i = 1 n [ v T ( Y i T Y i ) v − v T ( Y i Y i T ) v ] = v T ∑ i = 1 n [ ( Y i T Y i ) I − Y i Y i T ] v (11) f=\sum\limits_{i=1}^{n}[ \bm{Y_i}^T \bm{Y_i} -(\bm{v}^T \bm{Y_i})^2] =\sum\limits_{i=1}^{n}[ \bm{v^T}(\bm{Y_i}^T \bm{Y_i})\bm{v} -\bm{v}^T(\bm{Y_i}\bm{Y_i^T})\bm{v}] = \bm{v^T}\sum\limits_{i=1}^{n}[ (\bm{Y_i}^T \bm{Y_i}) \bm{I} -\bm{Y_i}\bm{Y_i^T}] \bm{v}\tag {11} f=i=1n[YiTYi(vTYi)2]=i=1n[vT(YiTYi)vvT(YiYiT)v]=vTi=1n[(YiTYi)IYiYiT]v(11)
  令矩阵 S = ∑ i = 1 n [ ( Y i T Y i ) I − Y i Y i T ] S=\sum\limits_{i=1}^{n}[ (\bm{Y_i}^T \bm{Y_i}) \bm{I} -\bm{Y_i}\bm{Y_i^T}] S=i=1n[(YiTYi)IYiYiT],式(11)可写成:

f = v T S v (12) f= \bm{v^T}S \bm{v}\tag {12} f=vTSv(12)
   f f f的最小值为矩阵 S S S最小特征值对应的特征向量。直线方向向量 v v v的求解问题转化为矩阵最小特征值对应的特征向量的求解问题!

三、 M A T L A B MATLAB MATLAB代码

%{
Function: line_fitting
Description: 直线拟合
Input: 任意维直线点数据points,行数为点个数,列数为点的维数
Output: 拟合得到的直线经过的一点L0,直线的单位方向向量v
Author: Marc Pony(marc_pony@163.com)
%}
function [L0, v] = line_fitting(points)
n = size(points, 1);
x = points(:, 1);
y = points(:, 2);
z = points(:, 3);L0 = [mean(x); mean(y); mean(z)];
S = zeros(3,3);
for i = 1 : nYi = [x(i) - L0(1); y(i) - L0(2); z(i) - L0(3)];S = S + (Yi' * Yi * eye(3, 3) - Yi * Yi');
end
[V, ~] = eig(S);v = V(:, 1); %矩阵S最小特征值对应的特征向量
end
%{
Function: generate_line_points
Description: 直线路径点生成
Input: 直线经过的一点L0,直线的单位方向向量v,点个数n,路径标量最小值minS,路径标量最大值maxS
Output: 任意维直线点数据points,行数为点个数,列数为点的维数
Author: Marc Pony(marc_pony@163.com)
%}
function points = generate_line_points(L0, v, n, minS, maxS)
points = zeros(n, length(v));
s = linspace(minS, maxS, n);
for i = 1 : npoints(i, :) = (L0 + v * s(i))';
end
end
clear
clc
close all%% 验证恒等式: v'*Yi*v = v*v'*Yi
syms v1 v2 v3 y1 y2 y3 real
v = [v1; v2; v3];
Yi = [y1; y2; y3];
res1 = simplify(v'*Yi*v - v*v'*Yi)%% 验证恒等式: Yi'*Yi = v'*(Yi'*Yi)*v, 其中v'*v=1
res2 = [Yi'*Yi; simplify(v'*(Yi'*Yi)*v)]%% 验证恒等式: (v'*Yi)^2 = v'*(Yi*Yi')*v
res3 = simplify((v'*Yi)^2 - v'*(Yi*Yi')*v)% points = [1 0 0
%     1 10 0
%     1 20 0
%     ];
% points = [0 1 0
%     10 1 0
%     200 1 0
%     ];
% points = [1 1 1
%     2 1 2
%     ];figure
axis([-10, 10, -10, 10])
hold on
pointCount = 6;
points = zeros(pointCount, 3);
for i = 1 : pointCount[points(i, 1), points(i, 2)] = ginput(1);plot(points(i, 1), points(i, 2), '+')
end[L0, v] = line_fitting(points)n = 100;
len = sqrt((max(points(:,1)) - min(points(:,1)))^2 + (max(points(:,2)) - min(points(:,2)))^2 + (max(points(:,3)) - min(points(:,3)))^2);
minS = -0.6 * len;
maxS = 0.6 * len;
p = generate_line_points(L0, v, n, minS, maxS);
plot3(p(:,1), p(:,2), p(:,3), '-')

在这里插入图片描述

这篇关于直线拟合(支持任意维空间的直线拟合,附代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/653111

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

华为鸿蒙HarmonyOS 5.1官宣7月开启升级! 首批支持名单公布

《华为鸿蒙HarmonyOS5.1官宣7月开启升级!首批支持名单公布》在刚刚结束的华为Pura80系列及全场景新品发布会上,除了众多新品的发布,还有一个消息也点燃了所有鸿蒙用户的期待,那就是Ha... 在今日的华为 Pura 80 系列及全场景新品发布会上,华为宣布鸿蒙 HarmonyOS 5.1 将于 7

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061

pandas实现数据concat拼接的示例代码

《pandas实现数据concat拼接的示例代码》pandas.concat用于合并DataFrame或Series,本文主要介绍了pandas实现数据concat拼接的示例代码,具有一定的参考价值,... 目录语法示例:使用pandas.concat合并数据默认的concat:参数axis=0,join=

C#代码实现解析WTGPS和BD数据

《C#代码实现解析WTGPS和BD数据》在现代的导航与定位应用中,准确解析GPS和北斗(BD)等卫星定位数据至关重要,本文将使用C#语言实现解析WTGPS和BD数据,需要的可以了解下... 目录一、代码结构概览1. 核心解析方法2. 位置信息解析3. 经纬度转换方法4. 日期和时间戳解析5. 辅助方法二、L

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

IIS 7.0 及更高版本中的 FTP 状态代码

《IIS7.0及更高版本中的FTP状态代码》本文介绍IIS7.0中的FTP状态代码,方便大家在使用iis中发现ftp的问题... 简介尝试使用 FTP 访问运行 Internet Information Services (IIS) 7.0 或更高版本的服务器上的内容时,IIS 将返回指示响应状态的数字代

MySQL 添加索引5种方式示例详解(实用sql代码)

《MySQL添加索引5种方式示例详解(实用sql代码)》在MySQL数据库中添加索引可以帮助提高查询性能,尤其是在数据量大的表中,下面给大家分享MySQL添加索引5种方式示例详解(实用sql代码),... 在mysql数据库中添加索引可以帮助提高查询性能,尤其是在数据量大的表中。索引可以在创建表时定义,也可