基于惯性矩和偏心率的描述子

今天学习这段关于基于惯性矩和偏心率的描述子的内容,从理论到代码逐部分拆解:

一、整体功能与目标

这段代码的作用是:用 pcl::MomentOfInertiaEstimation 类,计算点云的 惯性矩、偏心率 等描述子,同时提取 轴对齐包围盒(AABB)和有向包围盒(OBB) ,最后可视化点云、包围盒和特征向量( eigen vectors )。

简单说,就是分析点云的几何形状,用惯性矩、偏心率描述它的 “形状特点”,用包围盒框住它,还能可视化这些结果,帮你理解点云的整体几何特征~

二、理论基础(Theoretical Primer )

1. 关键概念
  • 惯性矩(Moment of Inertia):描述点云绕某个轴的 “惯性”,反映点云在该方向的分布情况(值越大,分布越广 );
  • 偏心率(Eccentricity):描述点云投影的 “椭圆扁度”,反映点云在某个方向的伸展程度;
  • AABB(Axis-Aligned Bounding Box):轴对齐包围盒,边与坐标轴平行,计算简单但可能不够贴合;
  • OBB(Oriented Bounding Box):有向包围盒,边与点云的主方向对齐,更贴合形状但计算稍复杂;
  • 特征向量(Eigen Vectors):点云的主方向,代表点云延伸最长、次长、最短的三个方向。
2. 核心思路
  • 协方差矩阵与特征分解:先算点云的协方差矩阵,提取它的 特征值和特征向量。你可以认为所得特征向量是归一化的,并且总是形成右手坐标系(主特征向量代表 X 轴,次特征向量代表 Z 轴);

  • 迭代旋转与不变性:通过旋转主特征向量(保持旋转顺序不变 ),让描述子对 点云整体旋转不敏感(不管点云怎么转,描述子差不多 );

    _images/eigen_vectors.png

  • 惯性矩与偏心率计算:对每个旋转后的主方向,计算惯性矩;同时把点云投影到该方向,计算投影的偏心率;

    _images/projected_cloud.png

  • 包围盒提取:AABB 是轴对齐的长方体,OBB 是根据特征向量方向对齐的长方体(更贴合点云形状 )。

三、代码结构与流程拆解

#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)
{
  if (argc != 2)
    return (0);

  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ> ());
  if (pcl::io::loadPCDFile (argv[1], *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);

  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_WIREFRAME, "AABB");

  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);
}

代码分 点云加载、特征计算、结果提取、可视化 几个步骤,逐个讲:

1. 点云加载
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ> ());
if (pcl::io::loadPCDFile (argv[1], *cloud) == -1)
  return (-1);

作用:从命令行参数指定的 .pcd 文件加载点云数据。

2. 特征计算
pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;
feature_extractor.setInputCloud (cloud);
feature_extractor.compute ();
  • 实例化 MomentOfInertiaEstimation 类,设置输入点云,调用 compute 计算惯性矩、偏心率、包围盒、特征向量等。
3. 结果提取
std::vector <float> moment_of_inertia; // 惯性矩
std::vector <float> eccentricity;     // 偏心率
pcl::PointXYZ min_point_AABB, max_point_AABB; // AABB 的最小、最大点
pcl::PointXYZ min_point_OBB, max_point_OBB, position_OBB; // OBB 的参数
Eigen::Matrix3f rotational_matrix_OBB; // OBB 的旋转矩阵
float major_value, middle_value, minor_value; // 特征值(主、中、次 )
Eigen::Vector3f major_vector, middle_vector, minor_vector; // 特征向量
Eigen::Vector3f mass_center; // 质心

// 从 feature_extractor 中提取结果
feature_extractor.getMomentOfInertia (moment_of_inertia);
feature_extractor.getEccentricity (eccentricity);
feature_extractor.getAABB (min_point_AABB, max_point_AABB);
feature_extractor.getOBB (...);
feature_extractor.getEigenValues (...);
feature_extractor.getEigenVectors (...);
feature_extractor.getMassCenter (mass_center);
  • 这些变量存储了计算出的形状描述子、包围盒参数、特征值和特征向量。
4. 可视化
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"); // 添加点云

// 添加 AABB(黄色线框 )
viewer->addCube (min_point_AABB.x, max_point_AABB.x, ..., "AABB");
viewer->setShapeRenderingProperties(..., PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "AABB");

// 添加 OBB(红色线框 )
Eigen::Quaternionf quat (rotational_matrix_OBB); // 从旋转矩阵转四元数
viewer->addCube (position, quat, ..., "OBB");
viewer->setShapeRenderingProperties(..., PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");

// 添加特征向量(红、绿、蓝线 )
pcl::PointXYZ center (mass_center (0), ...); // 质心
pcl::PointXYZ x_axis (major_vector (0)+mass_center (0), ...); // 主特征向量末端点
viewer->addLine (center, x_axis, 1.0f, 0.0f, 0.0f, "major eigen vector"); // 红线
// 同理添加中、次特征向量(绿、蓝线 )

// 保持可视化窗口显示
while(!viewer->wasStopped())
{
  viewer->spinOnce (100);
  std::this_thread::sleep_for(100ms);
}
  • AABB:用黄色线框显示,边与坐标轴平行;

  • OBB:用红色线框显示,边与点云主方向对齐,更贴合形状;

  • 特征向量:从质心出发,沿主、中、次特征向量方向画红、绿、蓝线,直观展示点云的主方向。

    _images/moment_of_inertia.png

四、编译与运行

运行命令
./moment_of_inertia lamppost.pcd
  • lamppost.pcd 是点云文件名,替换成你自己的点云路径即可;
  • 运行后会弹出 3D 窗口,显示点云、AABB(黄色 )、OBB(红色 )和特征向量(红、绿、蓝 )。

五、总结

这段代码完整流程是:
加载点云 → 计算惯性矩、偏心率、包围盒、特征向量 → 提取结果 → 可视化点云、包围盒、特征向量

核心是理解:

  1. 惯性矩和偏心率是描述点云形状的 “数值特征”,能区分不同几何分布的点云;
  2. AABB 简单但可能宽松,OBB 更贴合点云形状,但计算依赖特征向量;
  3. 特征向量代表点云的主方向,可视化后能直观看到点云 “延伸最长、次长、最短” 的方向。

你可以换不同的点云(比如立方体、球体 ),观察惯性矩、偏心率和包围盒的变化,感受这些描述子对形状的刻画能力~

Ps.

内容源自pcl官方文档:基于转动惯量和偏心率的描述符 — 点云库 0.0 文档 — Moment of inertia and eccentricity based descriptors — Point Cloud Library 0.0 documentation

内容源自pcl官方文档Introduction — Point Cloud Library 0.0 documentation

本文为基于 PCL 官方文档的学习整理与个人理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值