pcl中MomentOfInertiaEstimation计算有向包围盒

news2024/11/18 15:48:26

pcl::MomentOfInertiaEstimation 是 Point Cloud Library (PCL) 中的一个类,用于计算点云中物体的矩。它可以提供点云物体的三个主轴及其长度,以及物体的惯性矩阵等信息。通过使用 pcl::MomentOfInertiaEstimation 类,可以实现物体形状分析、分类和识别等功能。

具体来说, pcl::MomentOfInertiaEstimation 类将点云中的点看作质点,并在空间中构建一个二次型矩阵,该矩阵描述了点云物体的惯性特性。然后通过对二次型矩阵进行特征值分解,可以得到物体的惯性矩阵及其特征向量和特征值,从而计算出物体的三个主轴及其长度、长宽高、体积等信息。

在点云处理中,矩特征分析是一个常用的工具,例如可以通过矩特征来计算物体的质心、面积、方向、形心、协方差矩阵等,从而实现物体分类、跟踪、位姿估计以及三维重建等应用。

template <typename PointT> void
pcl::MomentOfInertiaEstimation<PointT>::computeOBB ()
{
  obb_min_point_.x = std::numeric_limits <float>::max ();
  obb_min_point_.y = std::numeric_limits <float>::max ();
  obb_min_point_.z = std::numeric_limits <float>::max ();

  obb_max_point_.x = std::numeric_limits <float>::min ();
  obb_max_point_.y = std::numeric_limits <float>::min ();
  obb_max_point_.z = std::numeric_limits <float>::min ();

  unsigned int number_of_points = static_cast <unsigned int> (indices_->size ());
  for (unsigned int i_point = 0; i_point < number_of_points; i_point++)
  {
    float x = (input_->points[(*indices_)[i_point]].x - mean_value_ (0)) * major_axis_ (0) +
              (input_->points[(*indices_)[i_point]].y - mean_value_ (1)) * major_axis_ (1) +
              (input_->points[(*indices_)[i_point]].z - mean_value_ (2)) * major_axis_ (2);
    float y = (input_->points[(*indices_)[i_point]].x - mean_value_ (0)) * middle_axis_ (0) +
              (input_->points[(*indices_)[i_point]].y - mean_value_ (1)) * middle_axis_ (1) +
              (input_->points[(*indices_)[i_point]].z - mean_value_ (2)) * middle_axis_ (2);
    float z = (input_->points[(*indices_)[i_point]].x - mean_value_ (0)) * minor_axis_ (0) +
              (input_->points[(*indices_)[i_point]].y - mean_value_ (1)) * minor_axis_ (1) +
              (input_->points[(*indices_)[i_point]].z - mean_value_ (2)) * minor_axis_ (2);

    if (x <= obb_min_point_.x) obb_min_point_.x = x;
    if (y <= obb_min_point_.y) obb_min_point_.y = y;
    if (z <= obb_min_point_.z) obb_min_point_.z = z;

    if (x >= obb_max_point_.x) obb_max_point_.x = x;
    if (y >= obb_max_point_.y) obb_max_point_.y = y;
    if (z >= obb_max_point_.z) obb_max_point_.z = z;
  }

  obb_rotational_matrix_ << major_axis_ (0), middle_axis_ (0), minor_axis_ (0),
                            major_axis_ (1), middle_axis_ (1), minor_axis_ (1),
                            major_axis_ (2), middle_axis_ (2), minor_axis_ (2);

  Eigen::Vector3f shift (
    (obb_max_point_.x + obb_min_point_.x) / 2.0f,
    (obb_max_point_.y + obb_min_point_.y) / 2.0f,
    (obb_max_point_.z + obb_min_point_.z) / 2.0f);

  obb_min_point_.x -= shift (0);
  obb_min_point_.y -= shift (1);
  obb_min_point_.z -= shift (2);

  obb_max_point_.x -= shift (0);
  obb_max_point_.y -= shift (1);
  obb_max_point_.z -= shift (2);

  obb_position_ = mean_value_ + obb_rotational_matrix_ * shift;
}

这段代码是 pcl::MomentOfInertiaEstimation 类中的 computeOBB() 函数的实现,用于计算点云的最小有向边界盒(OBB)。

首先,通过遍历待计算的点云,计算每个点相对于主轴、中轴和次轴的投影,并更新 OBB 盒的最大、最小边界坐标。其中,主轴、中轴和次轴通过矩阵分解得到,并存储在类中的 major_axis_middle_axis_minor_axis_ 中。

然后,将计算出的主轴、中轴和次轴组成旋转矩阵,并计算 OBB 盒的位置(即重心)和边界框大小。最后,将 OBB 盒边界坐标减去重心坐标,得到相对于 OBB 盒中心的坐标。

首先,通过以下语句初始化 OBB 盒顶点坐标的最小值和最大值:

obb_min_point_.x = std::numeric_limits <float>::max ();
obb_min_point_.y = std::numeric_limits <float>::max ();
obb_min_point_.z = std::numeric_limits <float>::max ();

obb_max_point_.x = std::numeric_limits <float>::min ();
obb_max_point_.y = std::numeric_limits <float>::min ();
obb_max_point_.z = std::numeric_limits <float>::min ();

 然后遍历待计算的点云,对每个点计算其相对于主轴、中轴和次轴的投影,并根据这些投影来更新 OBB 盒的最大、最小边界坐标:

for (unsigned int i_point = 0; i_point < number_of_points; i_point++)
{
  float x = (input_->points[(*indices_)[i_point]].x - mean_value_ (0)) * major_axis_ (0) +
            (input_->points[(*indices_)[i_point]].y - mean_value_ (1)) * major_axis_ (1) +
            (input_->points[(*indices_)[i_point]].z - mean_value_ (2)) * major_axis_ (2);
  float y = (input_->points[(*indices_)[i_point]].x - mean_value_ (0)) * middle_axis_ (0) +
            (input_->points[(*indices_)[i_point]].y - mean_value_ (1)) * middle_axis_ (1) +
            (input_->points[(*indices_)[i_point]].z - mean_value_ (2)) * middle_axis_ (2);
  float z = (input_->points[(*indices_)[i_point]].x - mean_value_ (0)) * minor_axis_ (0) +
            (input_->points[(*indices_)[i_point]].y - mean_value_ (1)) * minor_axis_ (1) +
            (input_->points[(*indices_)[i_point]].z - mean_value_ (2)) * minor_axis_ (2);

  if (x <= obb_min_point_.x) obb_min_point_.x = x;
  if (y <= obb_min_point_.y) obb_min_point_.y = y;
  if (z <= obb_min_point_.z) obb_min_point_.z = z;

  if (x >= obb_max_point_.x) obb_max_point_.x = x;
  if (y >= obb_max_point_.y) obb_max_point_.y = y;
  if (z >= obb_max_point_.z) obb_max_point_.z = z;
}

这里首先计算了每个点相对于重心坐标系下的主轴、中轴和次轴的投影坐标,并将其保存在 xyz 变量中。然后,根据这些投影坐标来更新 OBB 盒的最大、最小边界坐标。

接下来,通过以下代码将主轴、中轴和次轴组成旋转矩阵:

obb_rotational_matrix_ << major_axis_ (0), middle_axis_ (0), minor_axis_ (0),
                          major_axis_ (1), middle_axis_ (1), minor_axis_ (1),
                          major_axis_ (2), middle_axis_ (2), minor_axis_ (2);

这里使用了 Eigen 矩阵库来创建一个 3x3 的旋转矩阵,并将主轴、中轴和次轴作为矩阵的列向量。

然后,通过以下代码计算 OBB 盒的位置(即重心)和边界框大小:

Eigen::Vector3f shift (
  (obb_max_point_.x + obb_min_point_.x) / 2.0f,
  (obb_max_point_.y + obb_min_point_.y) / 2.0f,
  (obb_max_point_.z + obb_min_point_.z) / 2.0f);

obb_position_ = mean_value_ + obb_rotational_matrix_ * shift;

obb_min_point_.x -= shift (0);
obb_min_point_.y -= shift (1);
obb_min_point_.z -= shift (2);

obb_max_point_.x -= shift (0);
obb_max_point_.y -= shift (1);
obb_max_point_.z -= shift (2);

这里首先计算了 OBB 盒的重心坐标 shift,即将盒子最大和最小顶点的坐标平均值作为重心。然后,通过旋转矩阵将盒子的重心坐标从重心坐标系转换到原始坐标系中,并将其保存在 obb_position_ 变量中。最后,再将盒子顶点坐标减去盒子的重心坐标,得到相对于盒子中心的坐标。这里使用了 Eigen 矢量库来计算向量之间的加法和减法。

总的来说,这段代码实现了计算点云 OBB 盒的全部步骤,并用各种成员变量来存储计算结果,方便后续应用程序进行分析和处理。

PCL官网中的例子:

#include <vector>
#include <thread>
 
#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>
 
using namespace std::chrono_literals;
 
int main(int argc, char** argv)
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
    if (pcl::io::loadPCDFile("table_scene_lms400.pcd", *cloud) == -1)
        return (-1);
 
    pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;
    feature_extractor.setInputCloud(cloud);
    feature_extractor.compute();
 
    std::vector <float> moment_of_inertia;
    std::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);
    feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
    feature_extractor.getEigenValues(major_value, middle_value, minor_value);
    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(0, 0, 0);
    viewer->addCoordinateSystem(1.0);
    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, 1.0, 0.0, "AABB");
    viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_POINTS, "AABB");
 
    //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");
 
    //中心点处加坐标
    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);
        std::this_thread::sleep_for(100ms);
    }
 
    return (0);
}

feature_extractor.getMomentOfInertia(moment_of_inertia) 用于获取点云的惯性矩。具体来说,该方法将计算得到的点云惯性矩赋值给输入的 moment_of_inertia 向量。这个向量的长度为 6,分别存储了点云绕 x、y、z 坐标轴旋转的惯性矩以及旋转坐标系后的三对相互垂直的惯性矩。这些数据是计算点云形状特征的重要信息。

点云的惯性矩与点云的形状密切相关。惯性矩是描述物体沿不同坐标轴旋转惯性大小的物理量,它可以被用来计算物体的质心、轴向方差和惯性轴等特征,是描述物体形状和旋转状态的重要信息。例如,在三维空间中,一个点云的长、宽、高等尺寸特征可以通过惯性矩计算得到。此外,惯性矩也可以用于识别旋转中的点云,如最小外接立方体 (OBB) 的方向就可以通过点云的惯性矩计算得出,并进一步展示点云在三维空间中的方向和大小。

getEccentricity(eccentricity)函数接收一个名为 eccentricity 的变量作为参数,并将计算得到的偏心率值赋值给该变量。在三维点云处理领域,偏心率用于描述点云形状的离心程度。在数学和物理学中,偏心率是一个描述椭圆形状的参数,其值介于 0 和 1 之间,当偏心率为 0 时,表示椭圆退化成圆形,而当偏心率越接近 1,表示椭圆越扁平。在计算机视觉和图像处理领域中,偏心率通常被用作图像特征的一种度量方式,用于描述图像中目标物体的形状偏向程度。

偏心率是指点云中每个点到定点(焦点)的距离与到定直线(准线)的距离之比,也可定义为二阶矩的长轴与短轴之比。对于点云形状更接近椭球形或圆柱形的物体,其偏心率值会较小,表示形状趋近于圆心对称;而对于点云形状离心程度较大的物体,例如长条形的木板等,其偏心率值会较大。

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

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

相关文章

C++类和对象-3

承接上一篇博客中内容&#xff0c;讲述完类和对象中构造函数内容之后&#xff0c;这篇博客我们来讲述类和对象中&#xff0c;析构函数的内容。 目录 1.析构函数 2.拷贝构造函数 3.浅拷贝与深拷贝 1.析构函数 在类和对象的构建当中&#xff0c;类中的对象会通过构造函数来…

Jenkins配置邮箱发送报告

本文以qq邮箱为例 1.下载Email Extension Plugin插件 2.在Manage Jenkins--System&#xff0c;Jenkins Location下配置理员邮件 Extended E-mail Notification 下配置Jenkins SMTP server&#xff08;邮箱服务&#xff09;、SMTP Port&#xff08;邮箱端口&#xff09;、Cred…

c++学习(day4)

文章目录 一. 友元&#xff08;friend&#xff09;1 友元函数1.1 全局函数作为友元函数1.2 类的成员函数作为友元函数&#xff08;了解&#xff09; 2. 友元类3. 使用友元的注意事项 二. 常成员函数和常对象&#xff08;const&#xff09;1. 常成员函数2. 常对象3. mutable关键…

【微服务笔记17】微服务组件之Gateway实现动态路由、配置路由规则、路由过滤器

这篇文章&#xff0c;主要介绍微服务组件之Gateway实现动态路由、配置路由映射规则、路由过滤器。 目录 一、动态路由配置 1.1、动态URI路由配置 &#xff08;1&#xff09;引入eureka客户端依赖 &#xff08;2&#xff09;添加路由配置 1.2、服务名称转发配置 二、断言配…

基于 Windows 安装 ESP32 Arduino 软件开发环境

ESP32 Arduino 源码库&#xff1a;arduino-esp32ESP32 Arduino 环境搭建说明&#xff1a;About Arduino ESP32 其他软件环境需求&#xff1a; Git 环境 1、安装 Arduino 软件 可在 Arduino 官网 获取 Windows 端 Arduino 安装包&#xff0c;如下&#xff1a; 使用如下 .exe 一…

JVM类加载过程

文章目录 1、加载2、链接2.1 验证2.2 准备2.3 解析 3、初始化3.1 类初始化练习3.2 懒汉式单例练习 4、类加载器4.1 启动类加载器4.2 扩展类加载器4.3 双亲委派模式4.4 线程上下文类加载器4.4 自定义类加载器 5、运行时优化5.1 即时编译逃逸分析方法内联&#xff08;Inlining&am…

StressAppTest的简介

StressAppTest的全称是Stressful Application Test (stressapptest) 的简称http://code.google.com/p/stressapptest/ 这里我们可以将其简化为SAT。 SAT试图让来自处理器和I/O到内存的数据尽量随机化,以创造出模拟现实的环境来测试现在的硬件设备是否稳定。 SAT的大概作用如…

【Mysql 学习笔记】

Mysql 笔记记录 MySQL学习笔记一、 DDL1. DDL 查询和创建数据库2. DDL 修改、删除、使用数据库3. DDL 查询数据表4. DDL 创建数据表5. DDL 修改数据表6. DDL 删除数据表 二、DML MySQL学习笔记 一、 DDL 1. DDL 查询和创建数据库 #查询所有数据库 SHOW DATABASES; #查询某个数…

PMP项管2023年5月的备考准备攻略!现在看还来得及!

2023年共有4次PMP考试&#xff0c;分别是3月、5月、8月、11月&#xff0c;由于3月份考试不开放新报名&#xff0c;所以第一次备考PMP的同学可以选择参加5月份考试。那么&#xff0c;现在备考5月份PMP考试还来得及吗&#xff1f; 现在开始备考5月PMP考试&#xff0c;时间是非常…

蓝牙技术|消息称三星正研发智能戒指Galaxy Ring

根据韩媒 MT 报道&#xff0c;三星内部正在开发继 Galaxy Watch、Galaxy Fit 之后的另一款健康追踪设备 Galaxy Ring。 报道称这款智能戒指配备 PPG&#xff08;光电容积脉搏波&#xff09;传感器和 ECG&#xff08;心电图&#xff09;传感器&#xff0c;可以准确追踪佩戴者的…

云智慧助力MLOps加速落地

背景 随着数字化和计算能力的发展&#xff0c;机器学习&#xff08;Machine Learning&#xff09;技术在提高企业生产力方面所涌现的潜力越来越被大家所重视&#xff0c;然而很多机器学习的模型及应用在实际的生产环境并未达到预期&#xff0c;大量的ML项目被证明是失败的。从…

云计算中的网络安全技术及其应用

云计算已经成为当今企业信息化的主要选择之一。它提供了可靠的数据存储和处理能力&#xff0c;同时降低了企业的IT成本。然而&#xff0c;云计算的安全问题也随之而来。网络安全技术的应用对于保护云计算的安全至关重要。本文将探讨云计算中的网络安全技术及其应用&#xff0c;…

Golang每日一练(leetDay0041) 股票买卖4题

目录 121. 买卖股票的最佳时机 &#x1f31f; 122. 买卖股票的最佳时机 II &#x1f31f;&#x1f31f; 123. 买卖股票的最佳时机 III &#x1f31f;&#x1f31f;&#x1f31f; 188. 买卖股票的最佳时机 IV &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每…

2023第六届世界燕窝及天然滋补品博览会

2023上海燕窝展|上海燕博会|虫草节、鱼胶、灵芝、海参、滋补品展|滋补大会 摘要&#xff1a;燕博会、上海燕窝展、上海燕博会、2023上海燕博会、2023上海燕窝展、2023中国燕窝展、2023燕窝展&#xff0c;2023原装进口燕窝展&#xff0c;2023干制燕窝展,2023即食燕窝展,2023燕窝…

前端开发中有哪些常用的数组操作方法?

javascript数组 简介 JavaScript 数组用于在单一变量中存储多个值。 JavaScript数组是无类型的&#xff0c;数组元素可以是任意类型&#xff0c;并且同一个数组中元素类型也可以不同。 实例 var cars ["Saab", "Volvo", "BMW"];什么是数组&…

探索【Stable-Diffusion WEBUI】的插件:画布扩绘(Outpaint)

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;局部重绘&#xff08;Inpaint&#xff09;&#xff08;二&#xff09;画布扩绘&#xff08;Outpaint&#xff09;&#xff08;2.1&#xff09;图片画布扩大&#xff08;插件&#xff1a;OpenOutpaint&#x…

回炉重造九---DNS服务器

1、DNS服务器的相关概念和技术 1.1 DNS服务器的类型 主DNS服务器从DNS服务器缓存DNS服务器&#xff08;forward DNS服务器{转发器}&#xff09; 1.1.1 主DNS服务器的作用 管理和维护所负责解析的域内解析库的服务器1.1.2 从DNS服务器的作用 从主服务器或从服务器“复制”解…

检测并打印C++编译器支持的feature(附Visual Studio 2022和gcc-12测试、对比结果)

C标准快速迭代&#xff0c;不同的系统平台和编译器对C各种新功能的支持不同&#xff0c;通过这个程序可以测试所用编译器对各个版本C的支持情况。另一方面&#xff0c;可以在代码中通过这些宏针对不同版本编写不同的代码分支。 源码下面附上Visual Studio 2022的测试结果&#…

32道子网划分习题详细解析

目录 1 子网划分概念&#xff1a; 2 划分方法&#xff1a; 子网划分方法&#xff1a;段&#xff0c;块&#xff0c;数的计算三步。 段就是确定ip地址段中既有网络地址&#xff0c;又有主机地址的那一段是四段中的那一段&#xff1f; 块就确定上一步中确定的那一段中的主机…

【C语言】21-结构体

本文目录 • 一、什么是结构体 • 二、结构体的定义 • 三、结构体变量的定义 • 四、结构体的注意点 • 五、结构体的初始化 • 六、结构体的使用 • 七、结构体数组 • 八、结构体作为函数参数 • 九、指向结构体的指针 说明&#xff1a;这个C语言专题&#xff0c;是学习iOS开…