PCL-计算点云AABB包围盒

PCL-计算点云AABB包围盒

  • 一、概述
  • 二、实验代码
  • 三、效果展示
  • 四、总结

一、概述

点云包围盒也叫外接最小矩形,是一种求解离散点集最优包围空间的算法,基本思想是用体积稍大且特性简单的几何体(称为包围盒)来近似地代替复杂的几何对象。常见的包围盒算法有AABB包围盒、包围球、方向包围盒OBB以及固定方向凸包FDH。
在这里插入图片描述
最小包围盒的计算过程大致如下:
1.利用PCA主元分析法获得点云的三个主方向,获取质心,计算协方差,获得协方差矩阵,求取协方差矩阵的特征值和特长向量,特征向量即为主方向。
2.利用1中获得的主方向和质心,将输入点云转换至原点,且主方向与坐标系方向重回,建立变换到原点的点云的包围盒。
3.给输入点云设置主方向和包围盒,通过输入点云到原点点云变换的逆变换实现。

AABB(Axis-Aligned Bounding Box,轴对齐包围盒)是一种简单的包围体积,用于快速地包含和近似复杂形状或点云。AABB的特点是它的所有边都与坐标轴平行,这使得它易于计算、存储和相交测试
对于点云数据,AABB可以通过找到点云在所有三个维度(X、Y、Z)上的最小和最大坐标值来构建。这些最小和最大坐标值定义了AABB的八个顶点(尽管实际上只需要六个参数来完全描述一个AABB:三个最小值和三个最大值)。

OBB相关

构建AABB的步骤:
1.初始化最小和最大坐标值:为X、Y、Z轴设置非常大的初始最大值和非常小的初始最小值。
2.遍历点云:对于点云中的每个点,更新X、Y、Z轴上的最小和最大坐标值。
如果点的X坐标小于当前最小X值,则更新最小X值。
如果点的X坐标大于当前最大X值,则更新最大X值。
3.对Y和Z坐标重复上述步骤。
计算AABB的中心点和尺寸:
中心点坐标是各轴最小和最大坐标值的平均值。
尺寸是各轴上最大和最小坐标值之差

二、实验代码

#include <iostream>
#include <Eigen/Core>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>using namespace std;
typedef pcl::PointXYZ PointType;int main(int argc, char** argv)
{pcl::PointCloud<PointType>::Ptr cloud(new pcl::PointCloud<PointType>());pcl::io::loadPCDFile("E:\\******.pcd", *cloud);// 计算点云质心和协方差矩阵Eigen::Vector4f pcaCentroid;pcl::compute3DCentroid(*cloud, pcaCentroid);Eigen::Matrix3f covariance;pcl::computeCovarianceMatrixNormalized(*cloud, pcaCentroid, covariance);// 协方差矩阵分解求特征值特征向量Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors();Eigen::Vector3f eigenValuesPCA = eigen_solver.eigenvalues();// 校正主方向间垂直eigenVectorsPCA.col(2) = eigenVectorsPCA.col(0).cross(eigenVectorsPCA.col(1));eigenVectorsPCA.col(0) = eigenVectorsPCA.col(1).cross(eigenVectorsPCA.col(2));eigenVectorsPCA.col(1) = eigenVectorsPCA.col(2).cross(eigenVectorsPCA.col(0));cout << "特征值va(3x1):\n" << eigenValuesPCA << endl; // Eigen计算出来的特征值默认是从小到大排列cout << "特征向量ve(3x3):\n" << eigenVectorsPCA << endl;cout << "质心点(4x1):\n" << pcaCentroid << endl;// 将输入点云转换至原点Eigen::Matrix4f tm = Eigen::Matrix4f::Identity();     // 定义变换矩阵 Eigen::Matrix4f tm_inv = Eigen::Matrix4f::Identity(); // 定义变换矩阵的逆tm.block<3, 3>(0, 0) = eigenVectorsPCA.transpose();   // 旋转矩阵R.tm.block<3, 1>(0, 3) = -1.0f * (eigenVectorsPCA.transpose()) * (pcaCentroid.head<3>());// 平移向量 -R*ttm_inv = tm.inverse();std::cout << "变换矩阵tm(4x4):\n" << tm << std::endl;std::cout << "逆变矩阵tm'(4x4):\n" << tm_inv << std::endl;pcl::PointCloud<PointType>::Ptr transformedCloud(new pcl::PointCloud<PointType>);pcl::transformPointCloud(*cloud, *transformedCloud, tm);PointType min_p1, max_p1;Eigen::Vector3f c1, c;pcl::getMinMax3D(*transformedCloud, min_p1, max_p1);c1 = 0.5f * (min_p1.getVector3fMap() + max_p1.getVector3fMap());cout << "型心c1(3x1):\n" << c1 << endl;Eigen::Affine3f tm_inv_aff(tm_inv);pcl::transformPoint(c1, c, tm_inv_aff);Eigen::Vector3f whd, whd1;whd1 = max_p1.getVector3fMap() - min_p1.getVector3fMap();whd = whd1;float sc1 = (whd1(0) + whd1(1) + whd1(2)) / 3;  //点云平均尺度,用于设置主方向箭头大小cout << "width1=" << whd1(0) << endl;cout << "heght1=" << whd1(1) << endl;cout << "depth1=" << whd1(2) << endl;cout << "scale1=" << sc1 << endl;const Eigen::Quaternionf bboxQ1(Eigen::Quaternionf::Identity());const Eigen::Vector3f    bboxT1(c1);const Eigen::Quaternionf bboxQ(tm_inv.block<3, 3>(0, 0));const Eigen::Vector3f    bboxT(c);// 变换到原点的点云主方向PointType op;op.x = 0.0;op.y = 0.0;op.z = 0.0;Eigen::Vector3f px, py, pz;Eigen::Affine3f tm_aff(tm);pcl::transformVector(eigenVectorsPCA.col(0), px, tm_aff);pcl::transformVector(eigenVectorsPCA.col(1), py, tm_aff);pcl::transformVector(eigenVectorsPCA.col(2), pz, tm_aff);PointType pcaX;pcaX.x = sc1 * px(0);pcaX.y = sc1 * px(1);pcaX.z = sc1 * px(2);PointType pcaY;pcaY.x = sc1 * py(0);pcaY.y = sc1 * py(1);pcaY.z = sc1 * py(2);PointType pcaZ;pcaZ.x = sc1 * pz(0);pcaZ.y = sc1 * pz(1);pcaZ.z = sc1 * pz(2);// 初始点云的主方向PointType cp;cp.x = pcaCentroid(0);cp.y = pcaCentroid(1);cp.z = pcaCentroid(2);PointType pcX;pcX.x = sc1 * eigenVectorsPCA(0, 0) + cp.x;pcX.y = sc1 * eigenVectorsPCA(1, 0) + cp.y;pcX.z = sc1 * eigenVectorsPCA(2, 0) + cp.z;PointType pcY;pcY.x = sc1 * eigenVectorsPCA(0, 1) + cp.x;pcY.y = sc1 * eigenVectorsPCA(1, 1) + cp.y;pcY.z = sc1 * eigenVectorsPCA(2, 1) + cp.z;PointType pcZ;pcZ.x = sc1 * eigenVectorsPCA(0, 2) + cp.x;pcZ.y = sc1 * eigenVectorsPCA(1, 2) + cp.y;pcZ.z = sc1 * eigenVectorsPCA(2, 2) + cp.z;// 可视化pcl::visualization::PCLVisualizer viewer;viewer.setBackgroundColor(1.0, 1.0, 1.0);viewer.setWindowName("PCA获取点云包围盒");//输入的初始点云pcl::visualization::PointCloudColorHandlerCustom<PointType> color_handler(cloud, 255, 0, 0);viewer.addPointCloud(cloud, color_handler, "cloud");viewer.addCube(bboxT, bboxQ, whd(0), whd(1), whd(2), "bbox");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "bbox");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "bbox");viewer.addArrow(pcX, cp, 1.0, 0.0, 0.0, false, "arrow_x");viewer.addArrow(pcY, cp, 0.0, 1.0, 0.0, false, "arrow_y");viewer.addArrow(pcZ, cp, 0.0, 0.0, 1.0, false, "arrow_z");//转换到原点的点云pcl::visualization::PointCloudColorHandlerCustom<PointType> tc_handler(transformedCloud, 0, 255, 0);viewer.addPointCloud(transformedCloud, tc_handler, "transformCloud");viewer.addCube(bboxT1, bboxQ1, whd1(0), whd1(1), whd1(2), "bbox1");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "bbox1");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 1.0, 0.0, "bbox1");viewer.addArrow(pcaX, op, 1.0, 0.0, 0.0, false, "arrow_X");viewer.addArrow(pcaY, op, 0.0, 1.0, 0.0, false, "arrow_Y");viewer.addArrow(pcaZ, op, 0.0, 0.0, 1.0, false, "arrow_Z");viewer.addCoordinateSystem(0.5f * sc1);while (!viewer.wasStopped()){viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(10000));}return 0;
}

三、效果展示

图1 为本实验代码效果图
在这里插入图片描述
图2 为在包围盒基础上计算并显示该物体方向、序号及点云质心
在这里插入图片描述

四、总结

PCL 获取点云AABB包围盒+OBB包围盒+特征值+特征向量等

PCL 计算点云包围盒
问题:在计算包围盒中经常遇到一个问题,即计算出的包围盒在可视化时,不能显示在输入点云上,而是在空间中的宁一个区域,看起来就像这个计算出的矩形包围盒被旋转过。

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

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

相关文章

Linux复习3——管理文件系统2

修改文件权限命令 chmod 功能&#xff1a; chmod 命令主要用于修改文件或者目录的权限 只有文件所有者和超级用户可以修改文件或目录的权限 (1)使用数字表示法修改权限 所谓数字表示法是指将读取(r)、写入(w)和执行(x)分别以4、2、1来表示&#xff0c;没有授予的部分就表示…

微机接口课设——基于Proteus和8086的打地鼠设计(8255、8253、8259)

原理图设计 汇编代码 ; I/O 端口地址定义 IOY0 EQU 0600H IOY1 EQU 0640H IOY2 EQU 0680HMY8255_A EQU IOY000H*2 ; 8255 A 口端口地址 MY8255_B EQU IOY001H*2 ; 8255 B 口端口地址 MY8255_C EQU IOY002H*2 ; 8255 C 口端口地址 MY8255_MODE EQU IOY003H*2 ; …

代码随想录day25 | leetcode 491.递增子序列 46.全排列 回溯总结

考试周连考不复习就挂科了 一直没更新十分抱歉 今天开始在周日前补回来 491.递增子序列 在90.子集I中我们是通过排序&#xff0c;再加一个标记数组来达到去重的目的。 而本题求自增子序列&#xff0c;是不能对原数组进行排序的&#xff0c;排完序的数组都是自增子序列了。 …

车载U盘制作教程:轻松享受个性化音乐

车载U盘播放音乐相较于蓝牙播放具有一些明显的优势&#xff0c;这些优势主要体现在音质、稳定性、音乐管理以及兼容性等方面。以下是车载U盘播放音乐的一些优势&#xff1a; 音质更佳&#xff1a;车载U盘播放音乐时&#xff0c;音乐文件是直接被解码并播放的&#xff0c;这意味…

C语言从入门到放弃教程

C语言从入门到放弃 1. 介绍1.1 特点1.2 历史与发展1.3 应用领域 2. 安装2.1 编译器安装2.2 编辑器安装 3. 第一个程序1. 包含头文件2. 主函数定义3. 打印语句4. 返回值 4. 基础语法4.1 注释4.1.1 单行注释4.1.2 多行注释 4.2 关键字4.2.1 C语言标准4.2.2 C89/C90关键字&#xf…

重温设计模式--8、命令模式

文章目录 命令模式的详细介绍C 代码示例C代码示例2 命令模式的详细介绍 定义与概念 命令模式属于行为型设计模式&#xff0c;它旨在将一个请求封装成一个对象&#xff0c;从而让你可以用不同的请求对客户端进行参数化&#xff0c;将请求的发送者和接收者解耦&#xff0c;并且能…

oracle怎样使用logmnr恢复误删除的数据

如果有同事误删除数据了&#xff0c;可以用logmnr挖掘归档日志&#xff0c;生成回滚sql&#xff0c;快速恢复数据&#xff0c;比用整个库的备份恢复要快得多。 一 操作步骤 1.1 创建目录 su - oracle mkdir logmnr create directory logmnr_dir as /home/oracle/logmnr; …

读取文件内容、修改文件内容、识别文件夹目录(Web操作系统文件文件夹详解)

前言 因 Unicode IDE 编辑器导入文件、文件夹需要&#xff0c;研究了下导入文件/文件夹的功能实现&#xff0c;发现目前相关文章有点少&#xff0c;故而记录下过程&#xff0c;如果有误&#xff0c;还望指正。(API的兼容性及相关属性、接口定义&#xff0c;请自行查看文件系统…

第6章 图论

2024年12月25日一稿 &#x1f430;6.1 图的基本概念 6.1.1 图的定义和表示 6.1.2 图的同构 6.1.3 完全图与正则图 6.1.4 子图与补图 6.1.5 通路与回路 6.2 图的连通性 6.2.1 无向图的连通性 6.2.2 有向图的连通性 6.3 图的矩阵表示 6.3.1 关联矩阵 6.3.2 有向图的邻接矩阵…

网络管理(Network Management,NM)(一)

1.什么是AUTOSAR的网络管理&#xff1f;为什么要网络管理 ? 2.网络管理的三种模式&#xff1f; 上电时&#xff0c;进入总线睡眠模式&#xff0c;如果有唤醒源唤醒&#xff0c;则进入网络模式。其中。唤醒源唤醒分为主动唤醒和被动唤醒&#xff0c;主动唤醒指的是ecu自己想使…

三维扫描在汽车/航空行业应用

三维扫描技术应用范围广泛&#xff0c;从小型精密零件到大型工业设备&#xff0c;都能实现快速、准确的测量。 通过先进三维扫描技术获取产品和物体的形面三维数据&#xff0c;建立实物的三维图档&#xff0c;满足各种实物3D模型数据获取、三维数字化展示、3D多媒体开发、三维…

机器学习实战32-利用机器学习对电商销售数据进行归因分析的方法,旨在找出销量下降的原因

大家好,我是微学AI,今天给大家介绍一下机器学习实战32-利用机器学习对电商销售数据进行归因分析的方法,旨在找出销量下降的原因。文章详细介绍了代码编写过程、应用场景及其具体操作,通过实际案例分析,帮助读者深入了解如何运用机器学习技术对电商销售数据进行分析,从而为…

录播检测原理是什么?

直播间录播的检测可以通过多种方式进行。以下是一些常见的检测方法&#xff1a; 1、水印识别&#xff1a;直播平台可以在实时直播画面中嵌入特定的水印&#xff0c;通过识别水印来判断是否存在录播行为。 2、特征分析:直播平台可以通过对直播画面进行特征分析&#xff0c;检测…

WebSocket | 背景 概念 原理 使用 优缺点及适用场景

1 背景 在 WebSocket 出现之前&#xff0c;为了实现推送技术&#xff0c;所用的技术都是轮询&#xff0c;轮询是指浏览器每隔一段时间向服务器发出 HTTP 请求&#xff0c;服务器再返回最新的数据给客户端 常见的轮询方式分为轮询与长轮询&#xff0c;它们的区别如下图所示&…

硬件设计-传输线匹配

目录 简介&#xff1a; 主题&#xff1a; 终端匹配 始端匹配 始端匹配的阻值 始端匹配的输出驱动电流 中间匹配 电阻阻值的选择 简介&#xff1a; 系统何时需要匹配电阻&#xff1f;按照第四章的内容来看有两种情况&#xff1a;长线传输造成信号反射的情况和短线传输造成…

设计模式的主要分类是什么?请简要介绍每个分类的特点。

大家好&#xff0c;我是锋哥。今天分享关于【设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。】面试题。希望对大家有帮助&#xff1b; 设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。 1000道 互联网大厂Java工程师 精选面试题-Java资源分…

基于微信小程序的校园访客登记系统

基于微信小程序的校园访客登记系统 功能列表 用户端功能 注册与登录 &#xff1a;支持用户通过手机号短信验证码注册和登录。个人资料管理 &#xff1a;允许用户编辑和更新个人信息及其密码。站内信消息通知&#xff1a;通知公告。来访预约&#xff1a;提交来访预约支持车牌…

重温设计模式--观察者模式

文章目录 观察者模式&#xff08;Observer Pattern&#xff09;概述观察者模式UML图作用&#xff1a;实现对象间的解耦支持一对多的依赖关系易于维护和扩展 观察者模式的结构抽象主题&#xff08;Subject&#xff09;&#xff1a;具体主题&#xff08;Concrete Subject&#xf…

CH32V307VCT6---工程template创建

一、硬件&#xff1a;沁恒官网申请的CH32V307VCT6开发板 二、开发环境&#xff1a;Mounriver 三、最终效果 1.PB9连接LED1&#xff0c;使其闪烁 2.OLED屏幕显示&#xff1a;软件IIC&#xff0c;PB10----SDA&#xff0c;PB11---SCL 3.工程链接&#xff1a;CH32V307VCT6 lo…

分布式协同 - 分布式事务_2PC 3PC解决方案

文章目录 导图Pre2PC&#xff08;Two-Phase Commit&#xff09;协议准备阶段提交阶段情况 1&#xff1a;只要有一个事务参与者反馈未就绪&#xff08;no ready&#xff09;&#xff0c;事务协调者就会回滚事务情况 2&#xff1a;当所有事务参与者均反馈就绪&#xff08;ready&a…