利用PCA建立点云局部坐标系
摘要
在利用给定目标模型和现场可视点云评价二者相似程度的任务中,需要确定离线模型可视点云和现场分割各部点云的局部坐标系,用于在同一坐标系下注册模型可视点云和分割点云用于后续相似性度量。本文使用PCA方法确定给定点云的特征值和特征向量,使用特征向量作为三个主轴,构建局部坐标系。对于相似的两个点云,其主轴方向是相似的,所以基于PCA的局部坐标系构建有利于提高后续使用最近邻方法选择对应点进行相似性度量的准确性。
实现
pca转换
void pca_centriod(PointCloudT::Ptr cloud_in,PointCloudT::Ptr &cloud_out)
{
Eigen::Vector4f pcaCentroid;
pcl::compute3DCentroid(*cloud_in, pcaCentroid);
Eigen::Matrix3f covariance;
pcl::computeCovarianceMatrixNormalized(*cloud_in, pcaCentroid, covariance);
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);
Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors();
Eigen::Matrix4f transform(Eigen::Matrix4f::Identity());
transform.block<3, 3>(0, 0) = eigenVectorsPCA.transpose();
transform.block<3, 1>(0, 3) = -1.0f * (transform.block<3, 3>(0, 0)) * (pcaCentroid.head<3>());
pcl::transformPointCloud(*cloud_in, *cloud_out, transform);
}
测试
#include <string>
#include <iostream>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <vector>
#include <pcl/visualization/pcl_visualizer.h>
#include <Eigen/Core>
#include <pcl/common/transforms.h>
bool con_info = false;
using namespace std;
using namespace pcl;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<pcl::PointXYZ> PointCloudT;
typedef pcl::Normal NormalType;
void pca_centriod(PointCloudT::Ptr cloud_in,PointCloudT::Ptr &cloud_out)
{
Eigen::Vector4f pcaCentroid;
pcl::compute3DCentroid(*cloud_in, pcaCentroid);
Eigen::Matrix3f covariance;
pcl::computeCovarianceMatrixNormalized(*cloud_in, pcaCentroid, covariance);
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);
Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors();
Eigen::Matrix4f transform(Eigen::Matrix4f::Identity());
transform.block<3, 3>(0, 0) = eigenVectorsPCA.transpose();
transform.block<3, 1>(0, 3) = -1.0f * (transform.block<3, 3>(0, 0)) * (pcaCentroid.head<3>());
pcl::transformPointCloud(*cloud_in, *cloud_out, transform);
}
void visualize_pca_centriod(PointCloudT::Ptr cloud_in, PointCloudT::Ptr &cloud_out)
{
visualization::PCLVisualizer::Ptr view(new visualization::PCLVisualizer);
visualization::PointCloudColorHandlerCustom<PointT>cloud_color(cloud_in, 200, 0, 0);
visualization::PointCloudColorHandlerCustom<PointT>result_color(cloud_out, 100, 255, 200);
view->addPointCloud(cloud_in, cloud_color, "cloud");
view->addPointCloud(cloud_out, result_color, "result");
view->setBackgroundColor(0, 0, 0);
view->addCoordinateSystem(0.1f);
while (!view->wasStopped())
{
view->spinOnce(100);
}
}
int main() {
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile("C:/Users/chensi/Desktop/data/pcl/cup.pcd", *cloud) == -1)
{
PCL_ERROR("filed load target point cloud \n");
return (-1);
}
PointCloudT::Ptr result(new PointCloudT);
pca_centriod(cloud, result);
visualize_pca_centriod(cloud, result);
return 0;
}