主成分分析法(PCA)求OBB包围盒

目录

1 原理介绍

2 数学公式推导

数据中心化:

协方差矩阵:

特征值分解:

3 算法流程

4 示例代码

        主成分分析(Principal Component Analysis, PCA)是一种统计学方法,用于降维、特征提取以及数据分析。PCA不仅可以用于数据的降维,还可以用于计算点云的最优拟合包围盒,即最小包围盒(Oriented Bounding Box, OBB)。与AABB不同,OBB可以任意旋转,能够更紧密地包围点云数据。

1 原理介绍

        PCA的基本思想是通过线性变换,将原始数据投影到一个新的坐标系中,这个坐标系由数据的主要方向组成。对于点云数据,PCA可以找出点云的主要方向,从而计算出一个与主要方向对齐的最小包围盒。

2 数学公式推导

数据中心化

  1. 对于给定点云 P={p1,p2,…,pn},首先计算点云的质心 pˉ​:

  • 将点云中心化:

协方差矩阵

  • 计算中心化点云的协方差矩阵 Σ:

特征值分解

  • 对协方差矩阵进行特征值分解,得到特征值和特征向量:

  1. 计算OBB

    • 利用特征向量组成的新坐标系,对点云进行变换,计算在新坐标系下的AABB,即为OBB。

3 算法流程

  1. 数据准备

    • 输入点云数据。
  2. PCA分析

    • 计算点云的质心并中心化,计算协方差矩阵。
  3. 特征值分解

    • 获取协方差矩阵的特征值和特征向量。
  4. 计算OBB

    • 将点云投影到特征向量构成的新坐标系中,计算最小包围盒。
  5. 结果输出

    • 返回OBB的尺寸、位置以及方向。

4 示例代码

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/common/common.h>
#include <pcl/common/pca.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>

int main(int argc, char** argv) {
    // 创建点云对象并加载点云数据
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("bunny.pcd", *cloud) == -1) {
        PCL_ERROR("Couldn't read file input.pcd \n");
        return (-1);
    }

    // 创建PCA对象并进行计算
    pcl::PCA<pcl::PointXYZ> pca;
    pca.setInputCloud(cloud);

    // 获取点云的质心
    Eigen::Vector4f centroid;
    pcl::compute3DCentroid(*cloud, centroid);

    // 获取特征向量
    Eigen::Matrix3f eigen_vectors = pca.getEigenVectors();

    // 将点云变换到PCA坐标系
    Eigen::Matrix4f projection_transform(Eigen::Matrix4f::Identity());
    projection_transform.block<3, 3>(0, 0) = eigen_vectors.transpose();
    projection_transform.block<3, 1>(0, 3) = -1.0f * (projection_transform.block<3, 3>(0, 0) * centroid.head<3>());

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_transformed(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::transformPointCloud(*cloud, *cloud_transformed, projection_transform);    
    // 计算变换后的AABB
    pcl::PointXYZ min_point, max_point;
    pcl::getMinMax3D(*cloud_transformed, min_point, max_point);

    // OBB尺寸
    Eigen::Vector3f obb_dimensions = 0.5f * (max_point.getVector3fMap() + min_point.getVector3fMap());
	// OBB变换矩阵的创建
	Eigen::Matrix4f projection_transform_inv = projection_transform.inverse();
	Eigen::Affine3f obb_transform(projection_transform_inv);
	Eigen::Vector3f obb_dimensions2;
	pcl::transformPoint(obb_dimensions, obb_dimensions2, obb_transform);
	
	Eigen::Vector3f whd;
	whd = max_point.getVector3fMap() - min_point.getVector3fMap();
	const Eigen::Quaternionf bboxQ(projection_transform_inv.block<3, 3>(0, 0));
	const Eigen::Vector3f    bboxT(obb_dimensions2);

    // 可视化
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);
    viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");

    // 通过变换矩阵和尺寸添加OBB
    viewer->addCube(bboxT, bboxQ,  whd(0), whd(1), whd(2), "OBB");
    viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");

    viewer->addCoordinateSystem(0.01);
    viewer->initCameraParameters();

    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);
      
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点云学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值