【PCL-8】方向包围盒OBB

news2025/1/19 11:17:31

 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博客

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

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

相关文章

AI聊天机器人原来有这么多作用

AI聊天机器人是一种能够模拟人类对话并利用人工智能技术进行自主学习和适应的计算机程序。它们能够根据用户的输入内容来分析用户的需求&#xff0c;并提供相应的回答和建议。今天looklook就来和大家详细讲一下AI聊天机器人到底有什么作用吧。 AI聊天机器人的作用 1、客户服务…

【springboot】mongoTemplate增删改查操作

目录 一、代码示例1.1 pom依赖1.2 application配置1.3 controller1.4 service 二、截图示例2.1 新增2.2 修改2.3 详情2.4 分页2.5 删除 一、代码示例 1.1 pom依赖 <!-- mongodb --> <dependency><groupId>org.springframework.boot</groupId><art…

2023 年 4 款适用于安卓手机的最佳 PDF 转 Word 转换器

尝试在 Android 上将 PDF 文档转换为 Word 文件&#xff1f;好吧&#xff0c;您可能会发现要让它发挥作用几乎是不可能的&#xff0c;至少在没有任何额外工具的情况下是这样。Web 上有用于此类转换的选项&#xff0c;但本地不一定会发生任何情况&#xff08;可能除了一个应用程…

金融语言模型:FinGPT

项目简介 FinGPT是一个开源的金融语言模型&#xff08;LLMs&#xff09;&#xff0c;由FinNLP项目提供。这个项目让对金融领域的自然语言处理&#xff08;NLP&#xff09;感兴趣的人们有了一个可以自由尝试的平台&#xff0c;并提供了一个与专有模型相比更容易获取的金融数据。…

axios / fetch 实现 stream 流式请求

axios 是一个支持node端和浏览器端的易用、简洁且高效的http库。本文主要介绍 axios 如何实现 stream 流式请求&#xff0c;注意这里需要区分 node 环境和浏览器环境。 一、node端 代码演示&#xff1a; const axios require(axios);axios({method: get,url: http://tiven.c…

intern()的使用和理解

如果不是用双引号声明的String对象&#xff0c;可以使用String提供的intern方法&#xff1a;intern方法会从字符串常量池中查询当前字符串是否存在&#xff0c;若不存在就会将当前字符串放入常量池中。比如&#xff1a;String myinfo new String&#xff08;"I Love CSDN…

网络安全--负载均衡

负载均衡 webshell实践 一、负载均衡配置 1.在全局的http下写下它&#xff1a; upstream nginx_boot{# 30s内检查心跳发送两次包&#xff0c;未回复就代表该机器宕机&#xff0c;请求分发权重比为1:2server 192.168.0.000:8080 weight100 max_fails2 fail_timeout30s; ser…

ARM64 程序调用标准

ARM64 程序调用标准 1 Machine Registers1.1 General-purpose Registers1.2 SIMD and Floating-Point Registers 2 Processes, Memory and the Stack2.1 Memory Addresses2.2 The Stack2.2.1 Universal stack constraints2.2.2 Stack constraints at a public interface 2.3 Th…

堆 和 优先级队列(超详细讲解,就怕你学不会)

优先级队列 一、堆的概念特性二、堆的创建1、向下调整算法2、向下调整建堆3、向下调整建堆的时间复杂度 三、堆的插入1、向上调整算法实现插入2、插入创建堆的时间复杂度 三、堆的删除四、Java集合中的优先级队列1、PriorityQueue 接口概述及模拟实现2、如何创建大根堆&#xf…

基于YOLOv8模型的五类动物目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的五类动物目标检测系统可用于日常生活中检测与定位动物目标&#xff08;狼、鹿、猪、兔和浣熊&#xff09;&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与…

【Java 动态数据统计图】动态数据统计思路案例(动态,排序,数组)四(116)

需求&#xff1a;&#xff1a;前端根据后端的返回数据&#xff1a;画统计图&#xff1b; 1.动态获取地域数据以及数据中的平均值&#xff0c;按照平均值降序排序&#xff1b; 说明&#xff1a; X轴是动态的&#xff0c;有对应区域数据则展示&#xff1b; X轴 区域数据降序排序…

加速出海丨美格智能SLM320模组再获德国电信认证

近日&#xff0c;美格智能Cat.1模组SLM320再获国际顶尖运营商德国电信认证&#xff0c;可以支持客户在德国电信网络所覆盖的德国、荷兰、波兰、奥地利、捷克、斯洛伐克、匈牙利等欧洲多国市场部署物联网应用&#xff0c;是美格智能走向全球市场的又一重要突破。 日前&#xff0…

通达信指标:显示全部的DRAWICON函数图标

**指标使用说明&#xff1a;**指标名称&#xff08;DRAWICON图标&#xff0c;幅图显示&#xff09;&#xff0c;需要查看图标的时候&#xff0c;要选择上市天数>92天的股票&#xff0c;才能正常的显示全部的图标&#xff0c;否则是无法显示的&#xff0c;以下的写法也是指标…

客服如何减轻工作压力?浅析客服压力管理方法

在现代商业领域中&#xff0c;客服是一项非常重要的工作&#xff0c;负责根据客户需求提供解决方案。客服工作不仅需要一定的专业知识和技能&#xff0c;还需要面对各种复杂、多变的情况&#xff0c;并拥有强大的应对压力的能力。客服从业人员的工作压力往往非常大&#xff0c;…

C++初阶语法——内部类

前言&#xff1a;内部类&#xff0c;顾名思义是定义在类中的类&#xff0c;许多人会以为它属于外部的类&#xff0c;实际上并不是&#xff0c;它们是两个独立的类&#xff0c;但是内部类受外部类类域的限制。 目录 一.概念二.特性1.内部类和外部类相互独立2.内部类是外部类的友…

极客时间-茹炳晟《软件测试52讲》-学习笔记-

测试基础知识篇&#xff08;11讲&#xff09; 01 你真的懂测试吗&#xff1f;从“用户登录”测试谈起 测试用例设计框架 基于功能性需求和非功能性需求思考&#xff1a; 功能性需求使用等价类划分、边界值分析、错误推断法设计用例 非功能性需求考虑安全&#xff08;信息的保存…

《Java极简设计模式》第04章:建造者模式(Builder)

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 源码地址&#xff1a;https://github.com/binghe001/java-simple-design-patterns/tree/master/j…

星际争霸之小霸王之小蜜蜂(三)--重构模块

目录 前言 一、为什么要重构模块 二、创建game_functions 三、创建update_screen() 四、修改alien_invasion模块 五、课后思考 总结 前言 前两天我们已经成功创建了窗口&#xff0c;并将小蜜蜂放在窗口的最下方中间位置&#xff0c;本来以为今天将学习控制小蜜蜂&#xff0c;结…

基于IMX6ULLmini的Linux裸机开发系列三:按键检测输入

目录 开启GPIO5对应的时钟 设置引脚复用 设置GPIO5_IO1输入模式 设置检测电平 部分代码 button.c led.c main.c 在原理图上找到对应的引脚后即可以根据对应的图表找到真正在板字上的引脚&#xff0c;这里的 SNVS_TAMPER1对应实际的引脚是GPIO5_IO1 P1357页附近有GPIO5对…

华为OD机试 - 数字字符串组合倒序 - 正则表达式(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路1、熟读题意&#xff0c;大概理解为&#xff1a;2、我理解 “-”作为连接符使用时作为字符串的一部分 的意思是&#xff1a;3、解决本题的关键是正则表达式的使用。 五、Java算法源码六、效果展示1、输入2、输出…