最小二乘法拟合空间直线
一、空间直线方程
1.1 一般方程
空间直线可以看成成两个平面的交线,设两个平面方程分别为 和 ,则直线的一般方程可以表示为:
1.2 点向式
设直线方向向量为,直线上一点,则任意点可以表示为 ,所以直线也可以表示为:
1.3 参数式
点向式经过简单变形即可得到:
1.4 平面法线叉乘表示
设两平面法线分别为: 和 ,则直线的方向向量可以表示为:
在到直线上取一点即可表示直线。
二、公式推导
这里参考链接1给出基于最小二乘法拟合直线的推导,设直线点向式方程为:,则转换后可以得到
其中。
所以空间直线可以看作
两个平面相交,因此对空间之间拟合就可以转换为对这两个平面的拟合,假设有个点,则可以得到这些点和两个平面的残差的平方和为:
依据最小二乘法有: 和 ,因此分别对求导,然后令导数为0可以得到:
依据第一个式子有:
==>
依据第二个式子有:
将代入中可以得到:
同理可以得到:
求出后就可以算出直线的方向向量,令,则,所以,还可以求出直线上一个点 ,令,则,所以点坐标可以表示为:。
三、代码实现
double FitLine(const std::vector<Vector3>& pointArray, Vector3& dir, Vector3& pt)
{
// ref: https://www.doc88.com/p-8189740853644.html
core::Vector3 center = core::Vector3(0.0, 0.0, 0.0);
int n = pointArray.size();
for (const core::Vector3& pt : pointArray) {
center += pt;
}
double sumXZ = 0.0, sumYZ = 0.0, sumZ2 = 0.0;
for (const core::Vector3& pt : pointArray) {
sumXZ += pt.x() * pt.z();
sumYZ += pt.y() * pt.z();
sumZ2 += pt.z() * pt.z();
}
double den = n * sumZ2 - center.z() * center.z();
double k1 = (n * sumXZ - center.x() * center.z()) / den;
double b1 = (center.x() - k1 * center.z()) / n;
double k2 = (n * sumYZ - center.y() * center.z()) / den;
double b2 = (center.y() - k2 * center.z()) / n;
dir = core::Vector3(k1, k2, 1.0);
dir.Normalize();
double z = 1.0;
double x = k1 + b1;
double y = k2 + b2;
pt = core::Vector3(x, y, 1.0);
return 0.0;
}
四、效果
下面是拟合的效果,红色点是输入散点,绿色点表示直线上的两个点。
五、参考资料
分类:
几何
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧