切比雪夫(最小区域法)平面拟合算法

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

本期话题:切比雪夫(最小区域法)平面拟合算法

相关背景和理论
点击前往
主要介绍了应用背景和如何转化成线性规划问题

在这里插入图片描述

平拟合输入和输出要求

输入

  1. 10到631个点,全部采样自平面附近。
  2. 每个点3个坐标,坐标精确到小数点后面20位。
  3. 坐标单位是mm, 范围[-500mm, 500mm]。

输出

  1. 平面上一点X0,用三个坐标表示。
  2. 法向A。
  3. 平面度F,所有点到平面距离最大的2倍。

精度要求

  1. X0点平面距离不能超过0.0001mm。
  2. 法向A与标准法向夹角不能超过0.0000001rad。
  3. F与标准平面度误差不能超过0.00001mm。

平面优化标函数

根据认证要求,平面拟合转化成数学表示如下:

平面参数化表示

  1. 平面上1点X0 = (x0, y0, z0)。
  2. 方向单位向量A=(a,b,c)。

点到平面距离

第i个点 pi(xi, yi, zi)。

根据点乘得到距离

d i = ∥ ( p i − X 0 ) ⋅ A ∥ ∥ A ∥ d_i = \frac { \left \| (p_i-X_0)\cdot A \right \|}{\left \| A \right \|} di=A(piX0)A

展开一下:

d i = a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 d_i = \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)} {\sqrt{a^2+b^2+c^2}} di=a2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)

优化能量方程

能量方程 H = f ( X 0 , A ) = max ⁡ 1 n ∣ d i ∣ H=f(X0, A)=\displaystyle \max_1^n {|d_i|} H=f(X0,A)=1maxndi

X0, A是未知量,拟合平面的过程也可以理解为优化X0, A使得方程H最小。

如何3个参数表示平面

如果直接拿6个参数去做迭代,1是比较麻烦,会出现比较难解的方向,2是平面上的点有很多个,结果不唯一。

当平面法向与Z轴偏差比较小的时候可以使用3个参数来表示。

在这里插入图片描述

如上图,绿线为Z轴,橙色线为XOY平面。

由于法向与Z轴比较相近,可以设法向为(a, b, 1), a,b 是比较小的量。

现在表示 平面还需要一个点,规定点必须在以(a,b,1)为法向过0点的直线上。

就有直线公式 x0/a=y0/b=z0/c

那么只要知道z0就可知 x0=az0, y0=bz0.

综上,可以使用a, b, z0 表示一个法向与Z轴相近的 平面。

转化为线性规划(法向与Z轴接近)

设 a = ( z 0 , A a , A b ) , d i = F ( x i ; a ) , 引入 Γ = M A X i = 1 n ∣ d i ∣ 设a=(z_0, A_a, A_b), d_i=F(x_i;\ a), 引入\Gamma=\overset n{\underset {i=1}{MAX}}\;|d_i| a=(z0,Aa,Ab),di=F(xi; a),引入Γi=1MAXndi

根据上述定义,可以将原来的最值问题转化为下述条件

对于所有点应该满足

F ( x i ; a ) ≤ Γ , ( F ( x i ; a ) > 0 ) F(x_i;\ a)\le \Gamma, (F(x_i;\ a)>0) F(xi; a)Γ,(F(xi; a)>0)

− F ( x i ; a ) ≤ Γ , ( F ( x i ; a ) < 0 ) -F(x_i;\ a)\le \Gamma, (F(x_i;\ a)<0) F(xi; a)Γ,(F(xi; a)<0)

我们可以通过小量迭代慢慢减小Γ

m a x Δ Γ s . t . F ( x i , a ) + J Δ a ≤ Γ − Δ Γ , ( i = 1 , 2... n ) − ( F ( x i , a ) + J Δ a ) ≤ Γ − Δ Γ , ( i = 1 , 2... n ) Δ Γ ≥ 0 \begin {array}{c}max \ \ \ \ \Delta {\Gamma}\\ s.t.\ \ \ F(x_i, a) + J\Delta a \le \Gamma -\Delta \Gamma, (i=1,2...n)\\ \ \ \ \ \ \ \ \ \ -(F(x_i, a) + J\Delta a) \le \Gamma -\Delta \Gamma, (i=1,2...n)\\ \Delta \Gamma \ge0\end{array} max    ΔΓs.t.   F(xi,a)+JΔaΓΔΓ,(i=1,2...n)         (F(xi,a)+JΔa)ΓΔΓ,(i=1,2...n)ΔΓ0

上述条件不需要管 F ( x i , a ) + J Δ a 正负情况,若 F ( x i , a ) + J Δ a 为正 − ( F ( x i , a ) + J Δ a ) ≤ Γ − Δ Γ 必成立,反之亦然。 上述条件不需要管F(x_i, a) + J\Delta a正负情况,若F(x_i, a) + J\Delta a为正-(F(x_i, a) + J\Delta a) \le \Gamma -\Delta \Gamma必成立,反之亦然。 上述条件不需要管F(xi,a)+JΔa正负情况,若F(xi,a)+JΔa为正(F(xi,a)+JΔa)ΓΔΓ必成立,反之亦然。
求解出以后更新a, Γ。

对线性规划模型标准化

需要对 Δ z 0 , Δ A a , Δ A b 拆解,要求变量都要大于等于 0 需要对\Delta z_0, \Delta A_a, \Delta A_b 拆解,要求变量都要大于等于0 需要对Δz0,ΔAa,ΔAb拆解,要求变量都要大于等于0

m a x Δ Γ s . t . J i ⋅ [ Δ z 0 + - Δ z 0 - Δ A a + - Δ A a - Δ A b + − Δ A b − ] + Δ Γ ≤ Γ - d i , ( i = 1 , 2... n ) − J i ⋅ [ Δ z 0 + - Δ z 0 - Δ A a + - Δ A a - Δ A b + − Δ A b − ] + Δ Γ ≤ Γ + d i , ( i = 1 , 2... n ) Δ z 0 + , Δ z 0 − , Δ A a + , Δ A a − , Δ A b + , Δ A b − , Δ Γ ≥ 0 ( 1 ) \begin {array}{c}max \ \ \ \ \Delta {\Gamma}\\ s.t.\ \ \ J_i \cdot \begin {bmatrix} \Delta z_0^+-\Delta z_0^-\\ \Delta A_a^+-\Delta A_a^-\\ \Delta A_b^+- \Delta A_b^- \end{bmatrix} +\Delta \Gamma\le \Gamma-d_i, (i=1,2...n)\\\\ \ \ \ \ \ \ -J_i \cdot \begin {bmatrix} \Delta z_0^+-\Delta z_0^-\\ \Delta A_a^+-\Delta A_a^-\\ \Delta A_b^+- \Delta A_b^- \end{bmatrix}+\Delta \Gamma\le \Gamma+d_i, (i=1,2...n)\\ \Delta z_0^+, \Delta z_0^-, \Delta A_a^+, \Delta A_a^-, \Delta A_b^+, \Delta A_b^-, \Delta \Gamma \ge0\end{array} (1) max    ΔΓs.t.   Ji Δz0+Δz0ΔAa+ΔAaΔAb+ΔAb +ΔΓΓdi,(i=1,2...n)      Ji Δz0+Δz0ΔAa+ΔAaΔAb+ΔAb +ΔΓΓ+di,(i=1,2...n)Δz0+,Δz0,ΔAa+,ΔAa,ΔAb+,ΔAb,ΔΓ0(1)

算法描述

法向与Z轴重合时
x 0 = 0 , y 0 = 0 , z 0 = 0 , a = 0 , b = 0 , c = 1 x_0=0, y_0=0, z_0=0, a=0,b =0, c=1 x0=0,y0=0,z0=0,a=0,b=0,c=1

d i = a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 = z i d_i = \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)} {\sqrt{a^2+b^2+c^2}}=z_i di=a2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)=zi

J, D的计算。

3个未知分别对d_i求导结果如下:

求导后a=b=z0=x0=y0=0,c=1要代入

∂ d i ∂ z 0 = ∂ a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 ∂ z 0 ∣ z 0 = 0 = − 1 \frac {\partial d_i} {\partial z0}=\frac {\partial \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)}{\sqrt{a^2+b^2+c^2}}} {\partial z0}_{|z0=0} = -1 z0di=z0a2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)z0=0=1

∂ d i ∂ a = ∂ a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 ∂ a ∣ a = 0 = x i \frac {\partial d_i} {\partial a}=\frac {\partial \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)}{\sqrt{a^2+b^2+c^2}}} {\partial a}_{|a=0} = x_i adi=aa2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)a=0=xi

∂ d i ∂ b = ∂ a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 ∂ b ∣ b = 0 = y i \frac {\partial d_i} {\partial b}=\frac {\partial \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)}{\sqrt{a^2+b^2+c^2}}} {\partial b}_{|b=0} = y_i bdi=ba2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)b=0=yi

一次迭代过程

  1. 确定平面初值,Γ, 任意选择三点拟合平面

  2. 根据上述公式(1)构建线性规划方程

  3. 求解 Δ p \Delta p Δp

  4. 更新解
    [ x 0 y 0 z 0 ] = [ x 0 y 0 z 0 ] + U T ⋅ [ p a ∗ p z 0 p b ∗ p z 0 p z 0 ] [ a b c ] = U T ⋅ [ p a p b 1 ] . n o r m a l i z e ( ) Γ = Γ − Δ Γ \begin {array}{l} \begin {bmatrix}x_0 \\ y_0 \\ z_0 \end {bmatrix} = \begin {bmatrix}x_0 \\ y_0 \\ z_0 \end {bmatrix} + U^T \cdot \begin{bmatrix}p_a*p_{z_0} \\ p_b*p_{z_0} \\ p_{z_0} \end {bmatrix}\\ \\ \begin {bmatrix}a \\ b \\ c \end {bmatrix} = U^T \cdot \begin{bmatrix}p_a \\ p_b \\ 1 \end {bmatrix}.normalize() \\ \\ \Gamma = \Gamma-\Delta \Gamma \end {array} x0y0z0 = x0y0z0 +UT papz0pbpz0pz0 abc =UT papb1 .normalize()Γ=ΓΔΓ

  5. 重复2直到收敛

最后,输出时F=2*Γ

代码实现

代码链接:https://gitcode.com/chenbb1989/3DAlgorithm/blob/master/CBB3DAlgorithm/Fitting/chebyshev/PlaneFitter.cpp

拟合代码

#include "PlaneFitter.h"
#include "../gauss/FittingPlane.h"
#include <algorithm>
#include <Eigen/Dense>namespace Chebyshev {double PlaneFitter::F(Fitting::Plane plane, const Point& p){auto de = p - plane.BasePoint;return plane.Orient.dot(de);}double PlaneFitter::GetError(Fitting::Plane plane, const std::vector<Eigen::Vector3d>& points){double err = 0;for (auto& p : points) { err = std::max(err, abs(F(plane, p)));}return err;}Fitting::Matrix PlaneFitter::Jacobi(const std::vector<Eigen::Vector3d>& points){Fitting::Matrix J(points.size(), 3);for (int i = 0; i < points.size(); ++i) {auto& p = points[i];J(i, 0) = -1;J(i, 1) = p.x();J(i, 2) = p.y();}return J;}void PlaneFitter::beforHook(const std::vector<Eigen::Vector3d>& points){U = Fitting::getRotationByOrient(plane.Orient);for (int i = 0; i < points.size(); ++i) {transPoints[i] = U * (points[i] - plane.BasePoint);}}void PlaneFitter::afterHook(const Eigen::VectorXd& xp){plane.BasePoint += U.transpose() * Eigen::Vector3d(xp(0) * xp(1), xp(0) * xp(2), xp(0));plane.Orient = U.transpose() * Eigen::Vector3d(xp(1), xp(2), 1).normalized();gamma -= xp(3);}Eigen::VectorXd PlaneFitter::getDArray(const std::vector<Eigen::Vector3d>& points){Eigen::VectorXd D(points.size());for (int i = 0; i < points.size(); ++i)D(i) = points[i].z();return D;}bool PlaneFitter::GetInitFit(const std::vector<Eigen::Vector3d>& points){if (points.size() < 3)return false;Fitting::FittingBase* fb = new Gauss::FittingPlane();fb->Fitting(points, &plane);delete fb;gamma = GetError(plane, points);return true;}double PlaneFitter::F(const Eigen::Vector3d& p){return Chebyshev::PlaneFitter::F(plane, p);}double PlaneFitter::GetError(const std::vector<Eigen::Vector3d>& points){return Chebyshev::PlaneFitter::GetError(plane, points);}void PlaneFitter::Copy(void* ele){memcpy(ele, &plane, sizeof(Fitting::Plane));}PlaneFitter::PlaneFitter(){ft = Fitting::FittingType::CHEBYSHEV;}
}

测试结果

https://gitcode.com/chenbb1989/3DAlgorithm/blob/master/CBB3DAlgorithm/Fitting/chebyshev/chebyshev-testdata/officialtest/fitting_result/result.txt
C17 : PLANE : pass
C18 : PLANE : pass
C19 : PLANE : pass
C20 : PLANE : pass
C21 : PLANE : pass
C22 : PLANE : pass
C23 : PLANE : pass
C24 : PLANE : pass
C25 : PLANE : pass
C26 : PLANE : pass

本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。创作不易,帮忙点击公众号的链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/701682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue2:多级路由案例

一、情景说明 上一节&#xff0c;我们学习了Vue中的路由功能 但是&#xff0c;只是基础的一级路由 在实际生产中&#xff0c;路径不可能只有一级&#xff0c;一般都有3,4层级 二、案例 1、修改路由器文件 index.js 新增两个组件 这里实现二级路由配置 关键配置&#xff1a;…

命题逻辑|析取、合取和蕴含到底什么意思

如是我闻&#xff1a;在逻辑学中&#xff0c;“析取”、“合取”和“蕴含”这些术语的中文翻译是有其逻辑和哲学基础的&#xff0c;它们准确地反映了这些逻辑操作的本质。虽然他们被翻译的很高级&#xff0c;但并不能让人一下子就明白。 析取 (Disjunction) 原理&#xff1a;…

【C++精简版回顾】8.const

1.const数据成员 &#xff08;1&#xff09;const数据成员必须使用初始化参数列表 &#xff08;2&#xff09;不能修改 &#xff08;3&#xff09;不能修改必须初始化 class MM { public:MM() {}MM(int age, string name) :age(age), name(name) {}~MM() {cout << "…

SpringBoot和ApiFox整合快速上手

前置&#xff1a;IDEA版本IntelliJ IDEA 2023.2.4&#xff0c;Apifox 2.5.6 安装插件&#xff1a;Apifox Helper1.2.1 目录 1.文档生成 2.提取登录接口token 1.文档生成 把密钥配置到 导入成功:文档就会出现 2.提取登录接口token 之后我们再使用的时候&#xff0c;只需要配置…

面试整理(昆明)去面试就更新

1.MyBatis与MyBatis-Plus的区别&#xff1f; MyBatis和MyBatis-Plus都是Java语言中非常常用的ORM框架&#xff0c;二者有以下区别&#xff1a; 1.实现方式不同 MyBatis是基于XML或注解方式进行数据库操作的持久化框架&#xff0c;它提供了简单的CRUD操作及动态SQL生成等功能。…

五个使用Delphi语言进行开发的案例

案例一&#xff1a;学生信息管理系统 某学校需要开发一个学生信息管理系统&#xff0c;用于记录学生的基本信息、成绩和考勤情况等。开发者使用Delphi语言进行开发&#xff0c;设计了一个包含多个窗体的应用程序。主窗体用于展示学生的列表和基本信息&#xff0c;其他窗体则用…

2024.2.25 -ElasticSearch 进阶

倒排索引 Elasticsearch的倒排索引机制是通过将文档中出现的词汇与它们所在的文档ID关联起来&#xff0c;实现快速查找包含特定词汇的文档。下面是一个具体的例子来说明倒排索引的工作原理&#xff1a; 假设我们有一个简单的文章集合&#xff0c;包含以下三篇文章&#xff1a…

Java学习——泛型

Java泛型是Java语言中的一个特性&#xff0c;它允许你在类、接口和方法上定义类型参数。使用泛型可以使代码更加通用&#xff0c;减少代码重复&#xff0c;并在编译时提供更强的类型检查。下面分别介绍泛型类、泛型方法和泛型接口。 泛型类 泛型类是在类名后添加类型参数声明…

ap和ac的工作原理

让我们一步步解释无线网络中访问点 (AP) 和无线控制器 (AC) 的工作原理&#xff1a; 1. 访问点 (AP)&#xff1a; 访问点是无线局域网络 (WLAN) 中的关键组件之一&#xff0c;它充当无线设备&#xff08;如笔记本电脑、智能手机等&#xff09;和有线网络之间的桥梁。其工作原理…

Oracle开发和应用——PL/SQL语法2(游标及集合)

6.4.6. 游标 这里的游标(cursor),是指数据库开发中的游标,而且,这里所指的是显式定义的游标。因为,除了显式定义的游标,我们每条SQL语句也会隐式的定义、打开和关闭一个游标,其实质是一个带有指针的结果集。当我们按照顺序取出结果时,这个指针会按照从前到后的顺序移…

990-09产品经理:How project management benefits different teams 项目管理如何使不同的团队受益

Project management methods and tools can be deployed across all teams and industries to help improve efficiency and drive results. In this chapter, we’ll provide an overview of how PM benefits construction, IT, marketing, and operations teams. 项目管理方法…

解锁苏宁电商数据新纪元:关键字搜索API接口引领业务升级

苏宁关键字搜索API接口&#xff1a;电商数据探索的新篇章 一、引言 在电商领域&#xff0c;数据的重要性不言而喻。为了帮助开发者更高效地获取和利用电商数据&#xff0c;苏宁开放平台提供了关键字搜索API接口。本文将带你深入了解这一接口的技术细节&#xff0c;让你在电商…

如何获取pnpm存储目录

现在你可以做 得到&#xff1a;\path\to.pnpm-store\v3 pnpm store path注&#xff1a;从v7.0.0开始&#xff0c;pnpm 存储位于不同的文件夹中。它将位于$XDG_DATA_HOMELinux Linux : ~/.local/share/pnpm/store (default) Windows : C:\Users\YOUR_NAME\AppData\Local\pn…

设计模式--单例模式--懒汉饿汉

单例模式 单例模式(Singleton)&#xff0c;保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 单例模式 通常我们可以让一个全局变量使得一个对象被访问&#xff0c;但它不能防止你实例化多个对象。一个最好的办法就是&#xff0c;让类自身负责保存它的唯一实…

selenium自动化测试如何定位一闪而过的元素,比如提示信息、提交按钮

这里以登录按钮为例 在当前页面按F12点击控制,在下方输入debugger&#xff0c;点击登录按钮后点击输入debugger的地方按回车&#xff0c;一闪而过的元素就会定住不动就可以定位了

golang中make和new的区别

参考链接 https://worktile.com/kb/ask/38441.html 在Go语言中&#xff0c;make和new都是用于创建数据结构的内置函数&#xff0c;区别&#xff1a; 分配内存的区别 返回类型的区别 初始化的区别 分配内存的区别 make 用于创建切片、映射和通道等 引用类型 的数据结构。new 用…

企业网站建设需要多少钱?定制开发费用报价在3000-4000元

建立一个网站需要多少钱&#xff1f; 网站建设的价格划分也有很多。 这里首先要提的是市面上常见的一种低成本建站方式——模板网站&#xff0c;就是那种直接制作网站原型就可以无限复制的网站。 或者可以在几分钟内建立一个由软件生成的网站。 成本低得惊人&#xff0c;从500元…

【C++那些事儿】C++入门 | 命名空间 | 缺省参数 | 引用 | 内联函数 | auto关键字 | 范围for循环 | nullptr

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C那些事儿 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 前言1. C关键字(C98)2. 命名空间2.1 命名空间定义2.2 命名空间使用 3. C输入&输出4. 缺…

Qt 使用MD5给数据加密方法

重点&#xff1a; 1.通常在存储密码的时候需要对数据进行加密&#xff0c;通常采用Md5进行加密。 //存储密码时候 //读取存储的用户名和密码, 密码是经过加密的 void TDialogLogin::readSettings() {QSettings settings; //创建QSettings对象bool savedsettings.value(&q…

PyPDF2:项目实战源码分享(PDF裁剪)

目录&#x1f4d1; 1. 背景&#x1f4d1;2. 源码模块解析&#x1f4d1;2.1 读取PDF页数2.2 获取指定页的宽高尺寸2.3 裁剪单页PDF2.4 批量裁剪PDF 总结&#x1f4d1; 1. 背景&#x1f4d1; 接PyPDF2模块推荐博文中提到的实际需求&#xff08;将银行网站下载来的多页且单页多张…