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

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

相关文章

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义