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

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

相关文章

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调