在pcl/common自带pca计算,其主要功能包括计算特征值、特征向量、投影、reconstruction。
特征值特征向量计算,放在initCompute ()函数中,pca核心代码,源码如下:
template<typename PointT> bool
pcl::PCA<PointT>::initCompute ()
{
if(!Base::initCompute ())
{
PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::initCompute] failed");
}
if(indices_->size () < 3)
{
PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::initCompute] number of points < 3");
}
// Compute mean
mean_ = Eigen::Vector4f::Zero ();
compute3DCentroid (*input_, *indices_, mean_);
// Compute demeanished cloud
Eigen::MatrixXf cloud_demean;
demeanPointCloud (*input_, *indices_, mean_, cloud_demean);
assert (cloud_demean.cols () == int (indices_->size ()));
// Compute the product cloud_demean * cloud_demean^T
const Eigen::Matrix3f alpha = (1.f / (float (indices_->size ()) - 1.f))
* cloud_demean.topRows<3> () * cloud_demean.topRows<3> ().transpose ();
// Compute eigen vectors and values
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> evd (alpha);
// Organize eigenvectors and eigenvalues in ascendent order
for (int i = 0; i < 3; ++i)
{
eigenvalues_[i] = evd.eigenvalues () [2-i];
eigenvectors_.col (i) = evd.eigenvectors ().col (2-i);
}
// If not basis only then compute the coefficients
if (!basis_only_)
coefficients_ = eigenvectors_.transpose() * cloud_demean.topRows<3> ();
compute_done_ = true;
return (true);
}
//通过以下函数获取特征值,特征向量,点云中心(均值),系数,投影到局部坐标系下,reconstruction(我也不知道这个函数是什么意思)
Eigen::Matrix3f& getEigenVectors ()
Eigen::Vector3f& getEigenValues ()
Eigen::Vector4f& getMean ()
Eigen::MatrixXf& getCoefficients ()
void project (const PointCloud& input,PointCloud&projection);
void project (const PointT& input, PointT& projection)
void reconstruct (const PointCloud& projection, PointCloud& input)
应用
//功能求解点云特征值特征向量并投影
#include <iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/point_cloud.h>
#include<pcl/common/pca.h>
#include<Eigen/core>
typedef pcl::PointXYZ point;
typedef pcl::PointCloud<point> cloud;
int main()
{
cloud cloud_in;
if (pcl::io::loadPCDFile<point>("plane.pcd", cloud_in) < 0)
{
PCL_ERROR("读取文件错误");
return -1;
}
pcl::PCA<point>pca;
pca.setInputCloud(cloud_in.makeShared());
//求特征值与其对应的特征向量,矩阵的列向量为特征向量
Eigen::Vector3f eigen_values;
eigen_values=pca.getEigenValues();
std::cout << eigen_values << std::endl;
Eigen::Matrix3f eigen_vector;
eigen_vector=pca.getEigenVectors();
std::cout << eigen_vector << std::endl;
//将点或者点云投影到特征向量(正交)建立的局部坐标系下
cloud cloud_out(cloud_in);
cloud_out.clear();
point p;
p.getVector3fMap();
pca.project(cloud_in, cloud_out);
pcl::io::savePCDFile<point>("plane_projected.pcd", cloud_out);
std::cout << "Hello World!\n";
}
实验结果:
特征值与特征向量
实验数据为平面点云,理论上投影后点云平面应该与坐标轴平面平行:
左侧为投影后点云,pca得到的局部坐标系的原点为(0,0,0),所以二者有一定的偏离量。
可以发现投影后,点云平面与坐标轴平面重合,理论与实验结果符合。