当前位置: 首页 > news >正文

任意空间平面点云旋转投影至水平面—罗德里格旋转公式

1、背景介绍

       将三维空间中位于任意平面上的点云数据,通过一系列的坐标变换(平移+旋转),使其投影到XOY平面上,同时保证点云的几何中心与XOY平面的原点重合,同时点云形状保持不变。具体效果如下,具体来说,对于原始点集(红色点集),对其进行平移+旋转处理后,得到新的点云(白色点云),该点云与水平面平行,同时保持与原始点云形状相同。

三维空间动图前视图(白色点云水平)俯视图(两点云簇形状形同)

      为什么要将点云旋转,将其与水平面平行,这样做的好处体现在以下几方面:

  • 数据简化:将三维问题简化为二维问题,便于后续处理,如数据分析、可视化、特征提取等。
  • 算法适用性:某些算法可能在二维平面上表现得更好或更高效,投影可以使得这类算法得以应用。
  • 几何一致性:确保所有点云数据在同一参考平面上,便于比较和处理。

2、点云旋转投影流程与原理

2.1 流程介绍

     一般来说,点云旋转投影至水平面,包括如下步骤:

  • 中心化点云:首先计算点云的几何中心,然后将点云相对于其几何中心平移,使中心点与全局坐标系的原点重合。
  • 确定平面法向量:找出点云所在平面的法向量,这是点云所在平面垂直于三维空间的方向。
  • 旋转对齐:根据平面法向量与Z轴的偏差,构造旋转矩阵,旋转点云使之与XOY平面平行或重合。目的是消除Z坐标的影响,使所有点落在XOY平面上。
  • 投影:完成旋转后,可以安全地忽略所有点的Z坐标,只保留X和Y坐标,从而将点云投影到XOY平面上。

      上述四个步骤中,其实最为核心的步骤是求解旋转矩阵,本文介绍基于罗德里格旋转公式方法求解旋转矩阵。

2.2 推导过程

      假设待旋转的点云集,其拟合平面对应的法向量为vectorBefore(x1,y1,z1),经过旋转处理后,最终要得到的平面法向量为 vectorAfter(x2,y2,z2),将这两个向量转为单位向量。

  得到 va = normalize(vectorBefore), vb = normalize(vectorAfter)

  ② vs = vb × va, 叉乘得到旋转轴vs

  ③ v = normalize(vs), vs转为单位向量得到v

  ④ ca = vb · va, 点乘得到旋转角的余弦值 ca, 即cos(angle)

  ⑤ vt = v * scale, 对v进行缩放,方便后面计算, scale = 1 - ca

  ⑥ 旋转矩阵rm为 [3,3]矩阵, 计算原理为罗德里格旋转公式(Rodrigues' rotation formula)

    rm[0,0] = vt.x * v.x + ca    

    rm[1,1] = vt.y * v.y + ca

    rm[2,2] = vt.z * v.z + ca

    vt.x *= v.y

    vt.z *= v.x

    vt.y *= v.z

    rm[0,1] = vt.x - vs.z

    rm[0,2] = vt.z - vs.y

    rm[1,0] = vt.x - vs.z

    rm[1,2] = vt.y - vs.x

    rm[2,0] = vt.z - vs.y

    rm[2,1] = vt.y - vs.x

3、测试与结果

      基于上述步骤原理,使用C++进行编程,使用Eigen库进行向量点乘、叉乘。源代码下载链接:

https://download.csdn.net/download/qq_32867925/89552493

  随机生成10000个位于同一平面点集,其中可以根据需要修改平面方程,从而生成不同平面上点集。

for (int i = 0; i < numpt; i++){double x = rand() % 500;double y = rand() % 500;double z = 1 * x + 1 * y - 5;//假设平面方程类型 x+y-z-5=0Vector3d temp(x, y, z);points.push_back(temp);}

     不进行中心化处理进行旋转,即旋转中心随机,结果如下,平面方程为:x+y-z-5=0。其中,红色点集为原始点云,白色点集为旋转后点集。可以发现,白色点集均处于水平,即旋转成功,与水平面平行。通过解算参数也可以看出,z轴方向的法向量分量为-1,x轴、y轴分量为0。

未中心化旋转前视图
中心化后旋转前视图

4、总结

     介绍了三维空间内平面点云旋转平移,投影至水平面过程,并展示程序测试效果。

相关文章:

  • 【简洁明了】调节大模型的prompt的方法【带案例】
  • 一款IM即时通讯聊天系统源码,包含app和后台源码
  • 【Hive SQL 每日一题】找出各个商品销售额的中位数
  • C语言 ——— 实用调试技巧(Visual Studio)
  • 业务系统核心模块资料访问性能优化实战
  • 【Rust】使用日志记录利器flexi_logger
  • 【系统架构设计师】十一、系统架构设计(层次架构风格|MVC|面向服务的架构风格|ESB)
  • 解决 Failed to get nested archive for entry BOOT-INF/lib/xxx.jar
  • 【编程语言】C++和C的异同点
  • DBA 数据库管理 表管理 数据批量处理。表头约束
  • SAC-IA粗配准算法记录
  • 景联文科技构建高质量心理学系知识图谱,助力大模型成为心理学科专家
  • AI艺术创作:掌握Midjourney和DALL-E的技巧与策略
  • python爬虫实现简单的代理ip池
  • 微信小程序-实现跳转链接并拼接参数(URL拼接路径参数)
  • [nginx文档翻译系列] 控制nginx
  • 78. Subsets
  • express.js的介绍及使用
  • IOS评论框不贴底(ios12新bug)
  • JavaScript异步流程控制的前世今生
  • Laravel5.4 Queues队列学习
  • Linux Process Manage
  • PHP面试之三:MySQL数据库
  • Shell编程
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 搞机器学习要哪些技能
  • 给初学者:JavaScript 中数组操作注意点
  • 和 || 运算
  • 机器学习学习笔记一
  • 将 Measurements 和 Units 应用到物理学
  • 解析 Webpack中import、require、按需加载的执行过程
  • 区块链共识机制优缺点对比都是什么
  • 一个SAP顾问在美国的这些年
  • 移动端唤起键盘时取消position:fixed定位
  • 异步
  • postgresql行列转换函数
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​如何防止网络攻击?
  • #Java第九次作业--输入输出流和文件操作
  • #宝哥教你#查看jquery绑定的事件函数
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (el-Transfer)操作(不使用 ts):Element-plus 中 Select 组件动态设置 options 值需求的解决过程
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (四)事件系统
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (一)UDP基本编程步骤
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (状压dp)uva 10817 Headmaster's Headache
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .bashrc在哪里,alias妙用
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例