【PCL-8】方向包围盒OBB

2023-10-30

 AABB包围盒:边平行于坐标轴的最小六面体;

方向包围盒OBB:相对于坐标轴方向任意的最小立方体。

最小包围盒计算流程:

1、利用PCA主元分析法获得点云的三个主方向,获取质心,计算协方差,得到协方差矩阵,求取协方差矩阵的特征值和特征向量,特征向量即为主方向;

2、根据1获得的主方向和质心,将输入点云转换至原点,且主方向与坐标系方向重合,建立变换到原点的点云包围盒;

3、给输入点云设置主方向和包围盒,通过输入点云到原点点云变换的逆变换实现。

实现代码:

1、直接利用addcube生成立方体。

#include <pcl/features/moment_of_inertia_estimation.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/transforms.h>


int main(int argc, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
	if (pcl::io::loadPCDFile("..\\testdata\\point0817-3.pcd", *cloud) == -1)
		return (-1);
	//创建惯性矩估算对象,设置输入点云,并进行计算
	pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;
	feature_extractor.setInputCloud(cloud);
	feature_extractor.compute();

	vector <float> moment_of_inertia;
	vector <float> eccentricity;
	//pcl::PointXYZ min_point_AABB;
	//pcl::PointXYZ max_point_AABB;
	pcl::PointXYZ min_point_OBB;
	pcl::PointXYZ max_point_OBB;
	pcl::PointXYZ position_OBB;
	//矩阵特征值、特征向量
	Eigen::Matrix3f rotational_matrix_OBB;
	float major_value, middle_value, minor_value;
	Eigen::Vector3f major_vector, middle_vector, minor_vector;
	Eigen::Vector3f mass_center;
	//获取惯性矩
	feature_extractor.getMomentOfInertia(moment_of_inertia);
	//获取离心率
	feature_extractor.getEccentricity(eccentricity);
	//feature_extractor.getAABB(min_point_AABB, max_point_AABB);
	//获取OBB盒子
	feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
	cout << min_point_OBB.x << endl;
	feature_extractor.getEigenValues(major_value, middle_value, minor_value);
	//获取主轴major_vector,中轴middle_vector,辅助轴minor_vector
	feature_extractor.getEigenVectors(major_vector, middle_vector, minor_vector);
	//获取质心
	feature_extractor.getMassCenter(mass_center);

	//AABB外接立方体
	pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0);
	viewer->addCoordinateSystem(0.1);
	viewer->initCameraParameters();
	viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
	//viewer->addCube(min_point_AABB.x, max_point_AABB.x, min_point_AABB.y, max_point_AABB.y, min_point_AABB.z, max_point_AABB.z, 1.0, 0.0, 0.0, "AABB", 0);
	//viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_POINTS, "AABB");

	//OBB外接立方体,添加OBB包容盒
	Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
	Eigen::Quaternionf quat(rotational_matrix_OBB);
	viewer->addCube(position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, "OBB");
	viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");
	//最小外接立方体的长、宽、高;quat:旋转矩阵;position:中心位置
	cout << max_point_OBB.x << endl;
	cout << max_point_OBB.y << endl;
	cout << min_point_OBB.x << endl;
	cout << min_point_OBB.y << endl;
	cout << position_OBB.x << endl;
	cout << position_OBB.y << endl;
	cout << position_OBB.z << endl;
	cout << max_point_OBB.x - min_point_OBB.x << endl;
	cout << max_point_OBB.y - min_point_OBB.y << endl;
	cout << max_point_OBB.z - min_point_OBB.z << endl;
	cout << rotational_matrix_OBB << endl;
	//中心点处加坐标
	//pcl::PointXYZ center(mass_center(0), mass_center(1), mass_center(2));
	//pcl::PointXYZ x_axis(major_vector(0) + mass_center(0), major_vector(1) + mass_center(1), major_vector(2) + mass_center(2));
	//pcl::PointXYZ y_axis(middle_vector(0) + mass_center(0), middle_vector(1) + mass_center(1), middle_vector(2) + mass_center(2));
	//pcl::PointXYZ z_axis(minor_vector(0) + mass_center(0), minor_vector(1) + mass_center(1), minor_vector(2) + mass_center(2));


	//viewer->addLine(center, x_axis, 1.0f, 0.0f, 0.0f, "major eigen vector");
	//viewer->addLine(center, y_axis, 0.0f, 1.0f, 0.0f, "middle eigen vector");
	//viewer->addLine(center, z_axis, 0.0f, 0.0f, 1.0f, "minor eigen vector");

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

	return (0);
}

测试效果:

2、获取每个角点坐标,利用addLine划线。

//addLine画线
Eigen::Vector3f p1 (min_point_OBB.x, min_point_OBB.y, min_point_OBB.z);
Eigen::Vector3f p2 (min_point_OBB.x, min_point_OBB.y, max_point_OBB.z);
Eigen::Vector3f p3 (max_point_OBB.x, min_point_OBB.y, max_point_OBB.z);
Eigen::Vector3f p4 (max_point_OBB.x, min_point_OBB.y, min_point_OBB.z);
Eigen::Vector3f p5 (min_point_OBB.x, max_point_OBB.y, min_point_OBB.z);
Eigen::Vector3f p6 (min_point_OBB.x, max_point_OBB.y, max_point_OBB.z);
Eigen::Vector3f p7 (max_point_OBB.x, max_point_OBB.y, max_point_OBB.z);
Eigen::Vector3f p8 (max_point_OBB.x, max_point_OBB.y, min_point_OBB.z);

p1 = rotational_matrix_OBB * p1 + position;
p2 = rotational_matrix_OBB * p2 + position;
p3 = rotational_matrix_OBB * p3 + position;
p4 = rotational_matrix_OBB * p4 + position;
p5 = rotational_matrix_OBB * p5 + position;
p6 = rotational_matrix_OBB * p6 + position;
p7 = rotational_matrix_OBB * p7 + position;
p8 = rotational_matrix_OBB * p8 + position;

pcl::PointXYZ pt1 (p1 (0), p1 (1), p1 (2));
pcl::PointXYZ pt2 (p2 (0), p2 (1), p2 (2));
pcl::PointXYZ pt3 (p3 (0), p3 (1), p3 (2));
pcl::PointXYZ pt4 (p4 (0), p4 (1), p4 (2));
pcl::PointXYZ pt5 (p5 (0), p5 (1), p5 (2));
pcl::PointXYZ pt6 (p6 (0), p6 (1), p6 (2));
pcl::PointXYZ pt7 (p7 (0), p7 (1), p7 (2));
pcl::PointXYZ pt8 (p8 (0), p8 (1), p8 (2));

viewer->addLine (pt1, pt2, 1.0, 0.0, 0.0, "1 edge");
viewer->addLine (pt1, pt4, 1.0, 0.0, 0.0, "2 edge");
viewer->addLine (pt1, pt5, 1.0, 0.0, 0.0, "3 edge");
viewer->addLine (pt5, pt6, 1.0, 0.0, 0.0, "4 edge");
viewer->addLine (pt5, pt8, 1.0, 0.0, 0.0, "5 edge");
viewer->addLine (pt2, pt6, 1.0, 0.0, 0.0, "6 edge");
viewer->addLine (pt6, pt7, 1.0, 0.0, 0.0, "7 edge");
viewer->addLine (pt7, pt8, 1.0, 0.0, 0.0, "8 edge");
viewer->addLine (pt2, pt3, 1.0, 0.0, 0.0, "9 edge");
viewer->addLine (pt4, pt8, 1.0, 0.0, 0.0, "10 edge");
viewer->addLine (pt3, pt4, 1.0, 0.0, 0.0, "11 edge");
viewer->addLine (pt3, pt7, 1.0, 0.0, 0.0, "12 edge");

测试效果:

 

坐标系:

 点云数据坐标系为右手坐标系,红色是X轴,绿色是Y轴,蓝色是Z轴。

参考链接 pcl_包围盒_基于惯性矩与偏心率的描述子_yamgyutou的博客-CSDN博客

pcl中MomentOfInertiaEstimation计算有向包围盒_pclobb包围盒_chen_jared的博客-CSDN博客

 PCL ——最小包围盒(画出了最小包围盒并求出顶点坐标)_包围盒算法_云初的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【PCL-8】方向包围盒OBB 的相关文章

  • 数据结构(一)数组

    概述 说起数组我们都不陌生 几乎在每一种编程语言中 基本上都会有数组这种数据类型 不仅如此它还是是最基础最简单的数据结构 尽管如此 可能还是有一些人并没有真正的理解这个基础数据结构的精髓所在 首先 我们都知道 在java中数组是从 0 开始
  • Linux-epoll机制

    主要接口 epoll create epoll ctl epoll wait epoll create 头文件 include
  • Windows核心编程:字符和字符串处理

    Windows核心编程 字符和字符串处理 1 字符编码 ANSI 字符 一个字符一字节 8位 最多只能表达256个字符 UTF 的全称是Unicode Transformation Format Unicode转换格式 UTF 16 将 每
  • Transformer哲学

    一切苦痛 皆为过往 当我们科研遇到困难时 请大胆寻求Transformer的帮助吧 Transformer用一种苍老的声音问询 你有什么 你要什么 你怎么给我这些东西 一个翻译任务 我有英文 我需要中文 我以embedding形式给 一个目

随机推荐

  • Spring的@Component 、@Value 和 Springboot 的 @Component 、@ConfigurationProperties 使用

    application yml配置 book name 一个人的朝圣 author 蕾秋 乔伊斯 age 35 Spring的 Value 程序代码里 Spring主要在 Value注解的参数中使用EL表达式 注入普通字符串 注入操作系统属
  • C++异常处理机制的详细介绍

    1 C 异常处理的套路 1 1 C 异常处理机制之抛出异常关键字 throw 1 2throw关键字的使用 在哪可能出现异常就在哪里使用throw关键字抛出异常 这个异常可以使用一个常量 字符串 或类对象 都可以来抛出 throw 常量 字
  • 最佳买卖股票时机含冷冻期

    题目 给定一个整数数组 其中第 i 个元素代表了第 i 天的股票价格 设计一个算法计算出最大利润 在满足以下约束条件下 你可以尽可能地完成更多的交易 多次买卖一支股票 你不能同时参与多笔交易 你必须在再次购买前出售掉之前的股票 卖出股票后
  • 手游SDK-悬浮球

    一 游戏内显示悬浮球 手游SDK的悬浮球和一般的悬浮窗有点不一样 它只需要在游戏内显示即可 不需要也不能在桌面中显示出来 所以如果使用WindowManager创建悬浮窗 需要监听App是否在前台 如果在 则显示 如果不在则隐藏悬浮窗 而A
  • yolov7 姿态 pose训练部署笔记

    目录 pytorch开源相关资料 有tensorrtc 代码 预测时间测试结果 导出onnx代码
  • oppor15android版本8.1,OPPO R15搭载最新ColorOS 5.0系统,基于安卓8.1更好用

    原标题 OPPO R15搭载最新ColorOS 5 0系统 基于安卓8 1更好用 手机的发展十分之快 硬件性能普遍过剩 而手机系统的更新迭代变得异常重要 而越来越多的消费者也意识到这个问题 想获得更好的使用体验 不仅仅是硬件上的支持 操作系
  • Unity学习日志_动画系统简介

    Unity学习日志 动画系统简介 Animation Legacy动画系统 若要使用Animation 需要在创建Clip之前为物体手动添加Animation组件 Animation组件面板 属性 Animation 动画片段 Animat
  • Linux安装cuda如何修改目录,Ubuntu 18.04下安装CUDA 9.1或者9.2详细步骤

    在Ubuntu 18 04操作系统下安装CUDA 9 1 9 1 85 或者CUDA 9 2 9 2 148 版本的详细步骤 本文以安装CUDA 9 1为例 如果是安装CUDA 9 2 则相关参数修改为CUDA 9 2匹配的即可 1 下载c
  • vue项目运行至ipad白屏问题

    Vue做了一个单页面应用 它在一切设备上都工作正常 在调试另一个dug时 发现了这个问题 项目在其他端都可以正常打开 只有在paid上打开时 显示的是白屏状态 在刚开始解决这个问题时 花费了好几个小时都没解决 都准备从新编译代码了 发现并没
  • 数学建模学习笔记——线性规划

    数学建模学习笔记 线性规划 一 基础知识储备 1 线性规划 1 1标准形式 1 2非标准形式 1 3多目标规划 2 运输问题 3 指派问题 4 对偶理论与灵敏度分析 二 章节习题解答 Q3 Q4 Q5 Q6 Q8 Q9 本文章为 数学建模算
  • Unity 3D 博客汇总

    附录 X4 作业优秀博客汇总 目录 文章目录 附录 X4 作业优秀博客汇总 1 最有价值个人博客 Valuable Person Blogs 2 博客表达技巧与游戏创新 2 1 写读者欢迎的游戏博客 2 2 师兄师姐谈游戏创新 竞赛经验谈
  • Vector、deque、list三者之间的区别!!!

    vector 是一段连续的内存块 而deque 是多个连续的内存块 list 是所有 数据元素分开保存 可以是任何两个元素没有连续 vector 的查询性能最好 并且在末端增加数据也很好 除非它重新申请内存段 适合高效地随机存储 list
  • Java问题诊断和排查工具(查看JVM参数、内存使用情况及分析等)

    JDK自带的工具 在JDK的bin目录下有很多命令行工具 我们可以看到各个工具的大小基本上都稳定在27kb左右 这个不是JDK开发团队刻意为之的 而是因为这些工具大多数是jdk lib tools jar类库的一层薄包装而已 他们的主要功能
  • Windows批处理(cmd/bat)快速新建文件夹

    Windows批处理 cmd bat 快速新建文件夹 在进行毕业设计时 随着每日的任务不同 需要新建不同文件夹来区分任务 但手敲新建重命名太过繁琐 经过资料的查找 找到了在windows系统下bat文件的快速新建文件夹的方法 效果展示如下
  • 怎么让一个APP没有桌面图标!

    直入正题 在AndroidManifest xml中 注意 包含 action android name android intent action MAIN 的activity必须是application标签中第一个activity
  • C语言中将数字转换为字符串的方法

    C语言提供了几个标准库函数 可以将任意类型 整型 长整型 浮点型等 的数字转换为字符串 以下是用itoa 函数将整数转换为字符串的一个例子 include
  • 若依框架加入element-ui的input输入框,远程搜索用后端数据的,简单易上手

    我先展示一个最终效果 两种 设备信息用的是 el select gt 设备借还记录用的是el autocomplete gt 用的若依框架 做一个element ui的input输入框 远程搜索用后端数据的 我先说一下 我是三个表 一个厂家
  • 虚继承详解及其内存分布

    什么是虚继承 根据百度百科 虚继承 是面向对象编程中的一种技术 是指一个指定的基类 在继承体系结构中 将其成员数据实例共享给也从这个基类型直接或间接派生的其它类 虚拟继承是多重继承中特有的概念 虚拟基类是为解决多重继承而出现的 如上图 假设
  • 学习笔记 JavaScript ES6 Set

    学习内容 常用方法 遍历 应用场景 WeakSet 一种新的数据结构 set和array数组很像 不过array中可以有重复的值 而set里的值是唯一的 let s new Set console log s let s1 new Set
  • 【PCL-8】方向包围盒OBB

    AABB包围盒 边平行于坐标轴的最小六面体 方向包围盒OBB 相对于坐标轴方向任意的最小立方体 最小包围盒计算流程 1 利用PCA主元分析法获得点云的三个主方向 获取质心 计算协方差 得到协方差矩阵 求取协方差矩阵的特征值和特征向量 特征向