目录
一、概述
1.1原理
1.2实现步骤
1.3应用场景
二、代码实现
2.1关键函数
2.1.1 计算协方差矩阵和质心
2.1.2 计算特征值和特征向量
2.1.3 构建包围盒并可视化
2.2完整代码
三、实现效果
PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
点云包围盒(Bounding Box)是描述三维空间中点云数据外边界的最小矩形盒,用于精确描述物体的大小、位置、方向等信息。在处理3D数据时,计算包围盒可以有效地简化碰撞检测、缩放、旋转等几何操作。通过主成分分析(PCA)技术,可以根据点云的主轴方向构建包围盒,使包围盒的方向与物体的几何形状更加接近,从而提高空间占用效率。
1.1原理
PCA(主成分分析)通过计算点云的协方差矩阵来提取点云的主方向,协方差矩阵的特征向量表示点云的主方向,而特征值则代表每个主方向上的数据分布。通过对协方差矩阵的特征分解,可以获得点云的主要方向及大小。利用这些信息,可以构建一个旋转包围盒(OBB),并且通过质心和特征向量计算包围盒的大小和方向。
1.2实现步骤
- 读取点云数据:加载点云数据,准备进行PCA分析。
- 计算协方差矩阵:使用 pcl::compute3DCentroid 和 pcl::computeCovarianceMatrixNormalized 来计算质心和协方差矩阵。
- 计算特征值与特征向量:对协方差矩阵进行特征分解,获得特征向量和特征值。
- 构建变换矩阵:通过特征向量构建旋转矩阵,将点云变换至原点。
- 计算包围盒:在原点上计算包围盒的大小和方向。
- 将结果可视化:使用 PCLVisualizer 将原始点云和包围盒一起展示出来。
1.3应用场景
- 用于三维物体识别中的物体包围检测。
- 机器人路径规划中,避障检测时使用OBB来精确表示物体的空间位置。
- 点云分割后的物体配准与对齐。
- 各类场景中的物体紧密包围盒计算。
二、代码实现
2.1关键函数
2.1.1 计算协方差矩阵和质心
该函数计算点云的协方差矩阵和质心。
Eigen::Matrix3f computeCovarianceAndCentroid(pcl::PointCloud<PointType>::Ptr cloud, Eigen::Vector4f& pcaCentroid) {pcl::compute3DCentroid(*cloud, pcaCentroid); // 计算质心Eigen::Matrix3f covariance;pcl::computeCovarianceMatrixNormalized(*cloud, pcaCentroid, covariance); // 计算协方差矩阵return covariance;
}
2.1.2 计算特征值和特征向量
该函数分解协方差矩阵,获取特征值和特征向量。
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> computePCA(Eigen::Matrix3f covariance) {Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);return eigen_solver;
}
2.1.3 构建包围盒并可视化
该函数通过PCA计算的结果,构建OBB,并可视化展示包围盒和点云。
void visualizeOBB(pcl::PointCloud<PointType>::Ptr cloud,pcl::PointCloud<PointType>::Ptr transformedCloud,Eigen::Vector3f whd,Eigen::Vector3f whd1,Eigen::Vector3f bboxT,Eigen::Quaternionf bboxQ,Eigen::Vector3f bboxT1,Eigen::Quaternionf bboxQ1)
{pcl::visualization::PCLVisualizer viewer;viewer.setBackgroundColor(1.0, 1.0, 1.0);viewer.setWindowName("PCA获取点云包围盒");// 原始点云pcl::visualization::PointCloudColorHandlerCustom<PointType> color_handler(cloud, 255, 0, 0);viewer.addPointCloud(cloud, color_handler, "cloud");viewer.addCube(bboxT, bboxQ, whd.x(), whd.y(), whd.z(), "OBB");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");// 变换后的点云pcl::visualization::PointCloudColorHandlerCustom<PointType> tc_handler(transformedCloud, 0, 255, 0);viewer.addPointCloud(transformedCloud, tc_handler, "transformedCloud");viewer.addCube(bboxT1, bboxQ1, whd1.x(), whd1.y(), whd1.z(), "OBB1");viewer.addCoordinateSystem(1.0);while (!viewer.wasStopped()) {viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(10000));}
}
2.2完整代码
#include <iostream>
#include <Eigen/Core>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>using namespace std;
typedef pcl::PointXYZ PointType;int main(int argc, char** argv)
{// 1. 读取点云数据pcl::PointCloud<PointType>::Ptr cloud(new pcl::PointCloud<PointType>());pcl::io::loadPCDFile("bunny.pcd", *cloud);// 2. 计算点云质心和协方差矩阵Eigen::Vector4f pcaCentroid;pcl::compute3DCentroid(*cloud, pcaCentroid);Eigen::Matrix3f covariance;pcl::computeCovarianceMatrixNormalized(*cloud, pcaCentroid, covariance);// 3. 协方差矩阵分解求特征值和特征向量Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors();Eigen::Vector3f eigenValuesPCA = eigen_solver.eigenvalues();// 4. 校正主方向eigenVectorsPCA.col(2) = eigenVectorsPCA.col(0).cross(eigenVectorsPCA.col(1));// 5. 将输入点云转换至原点Eigen::Matrix4f tm = Eigen::Matrix4f::Identity();tm.block<3, 3>(0, 0) = eigenVectorsPCA.transpose();tm.block<3, 1>(0, 3) = -1.0f * (eigenVectorsPCA.transpose()) * (pcaCentroid.head<3>());pcl::PointCloud<PointType>::Ptr transformedCloud(new pcl::PointCloud<PointType>);pcl::transformPointCloud(*cloud, *transformedCloud, tm);// 6. 计算包围盒PointType min_p1, max_p1;pcl::getMinMax3D(*transformedCloud, min_p1, max_p1);Eigen::Vector3f c1 = 0.5f * (min_p1.getVector3fMap() + max_p1.getVector3fMap());Eigen::Vector3f whd = max_p1.getVector3fMap() - min_p1.getVector3fMap();// 7. 构建四元数和位移向量Eigen::Quaternionf bboxQ(eigenVectorsPCA); // 使用PCA的特征向量构建四元数Eigen::Vector3f bboxT = pcaCentroid.head<3>(); // 使用质心作为位移// 8. 可视化pcl::visualization::PCLVisualizer viewer;viewer.setBackgroundColor(1.0, 1.0, 1.0);viewer.setWindowName("PCA获取点云包围盒");// 输入的初始点云pcl::visualization::PointCloudColorHandlerCustom<PointType> color_handler(cloud, 255, 0, 0);viewer.addPointCloud(cloud, color_handler, "cloud");// 添加OBB包围盒viewer.addCube(bboxT, bboxQ, whd.x(), whd.y(), whd.z(), "OBB");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "OBB");//viewer.addCoordinateSystem(1.0);while (!viewer.wasStopped()){viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(10000));}return 0;
}