1.使用PCA计算点云主方向,并进行矫正
#include"vtkAutoInit.h"
#ifndef VTK_MODULE_INIT
VTK_MODULE_INIT(vtkRenderingOpenGL); // VTK was built with vtkRenderingOpenGL
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#endif
#include<vtkRenderingFreeTypeModule.h> //屏蔽vtk警告显示窗口
#include <iostream>
#include <string>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <Eigen/Core>
#include <pcl/common/transforms.h>
#include <pcl/common/common.h>
#include <pcl/visualization/pcl_visualizer.h>
using namespace std;
typedef pcl::PointXYZ PointType;
int main(int argc, char **argv)
{
pcl::PointCloud<PointType>::Ptr cloud(new pcl::PointCloud<PointType>());
//std::cout << "请输入需要显示的点云文件名:";
//std::string fileName("rabbit");
//getline(cin, fileName);
//fileName += ".pcd";
std::string fileName(argv[1]);
pcl::io::loadPCDFile(fileName, *cloud);
Eigen::Vector4f pcaCentroid;
pcl::compute3DCentroid(*cloud, pcaCentroid);//计算点云质心
Eigen::Matrix3f covariance;
pcl::computeCovarianceMatrixNormalized(*cloud, pcaCentroid, covariance);//计算目标点云协方差矩阵
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);//构造一个特定的自伴随矩阵类便于后续分解
Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors();//计算特征向量
Eigen::Vector3f eigenValuesPCA = eigen_solver.eigenvalues();//计算特征值
eigenVectorsPCA.col(2) = eigenVectorsPCA.col(0).cross(eigenVectorsPCA.col(1)); //校正主方向间垂直
eigenVectorsPCA.col(0) = eigenVectorsPCA.col(1).cross(eigenVectorsPCA.col(2));
eigenVectorsPCA.col(1) = eigenVectorsPCA.col(2).cross(eigenVectorsPCA.col(0));
std::cout << "特征值va(3x1):\n" << eigenValuesPCA << std::endl;
std::cout << "特征向量ve(3x3):\n" << eigenVectorsPCA << std::endl;
std::cout << "质心点(4x1):\n" << pcaCentroid << std::endl;
/*
// 另一种计算点云协方差矩阵特征值和特征向量的方式:通过pcl中的pca接口,如下,这种情况得到的特征向量相似特征向量
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPCAprojection (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PCA<pcl::PointXYZ> pca;
pca.setInputCloud(cloudSegmented);
pca.project(*cloudSegmented, *cloudPCAprojection);
std::cerr << std::endl << "EigenVectors: " << pca.getEigenVectors() << std::endl;//计算特征向量
std::cerr << std::endl << "EigenValues: " << pca.getEigenValues() << std::endl;//计算特征值
*/
Eigen::Matrix4f tm = Eigen::Matrix4f::Identity();
Eigen::Matrix4f tm_inv = Eigen::Matrix4f::Identity();
tm.block<3, 3>(0, 0) = eigenVectorsPCA.transpose(); //R.
tm.block<3, 1>(0, 3) = -1.0f * (eigenVectorsPCA.transpose()) *(pcaCentroid.head<3>());// -R*t
tm_inv = tm.inverse();
std::cout << "变换矩阵tm(4x4):\n" << tm << std::endl;
std::cout << "逆变矩阵tm'(4x4):\n" << tm_inv << std::endl;
pcl::PointCloud<PointType>::Ptr transformedCloud(new pcl::PointCloud<PointType>);
pcl::transformPointCloud(*cloud, *transformedCloud, tm);
//x方向与z方向互换
for (auto it = transformedCloud->begin(); it != transformedCloud->end(); it++)
{
float temp_x = it->x;
float temP_z = it->z;
it->x = temP_z;
it->z = temp_x;
}
pcl::io::savePCDFileBinary("transformedCloud.pcd", *transformedCloud);
}
2 computeCovarianceMatrixNormalized 计算给点云的协方差矩阵
/** \简介计算给定点集的3x3协方差矩阵归一化。
*结果作为eigen :: matrix3f返回。
*归一化意味着每个条目都已除以点云中的点数。
*对于少量的积分,或者如果要明确的样品变量,请使用ComputeCovarianCematrix
*并用1 /(n-1)缩放协方差矩阵,其中n是用于计算的点数
*协方差矩阵,并由ComputeCovarianCematrix函数返回。
* \ param [in]云输入点云
* \ param [in] centroid云中点集的质心
* \ param [out] covariance_matrix结果3x3协方差矩阵
* \返回数量的有效点用于确定协方差矩阵。
*如果有密集的点云,则与输入云的大小相同。
* \ group common
*/
/** \brief Compute normalized the 3x3 covariance matrix of a given set of points.
* The result is returned as a Eigen::Matrix3f.
* Normalized means that every entry has been divided by the number of points in the point cloud.
* For small number of points, or if you want explicitly the sample-variance, use computeCovarianceMatrix
* and scale the covariance matrix with 1 / (n-1), where n is the number of points used to calculate
* the covariance matrix and is returned by the computeCovarianceMatrix function.
* \param[in] cloud the input point cloud
* \param[in] centroid the centroid of the set of points in the cloud
* \param[out] covariance_matrix the resultant 3x3 covariance matrix
* \return number of valid points used to determine the covariance matrix.
* In case of dense point clouds, this is the same as the size of input cloud.
* \ingroup common
*/
template <typename PointT, typename Scalar> inline unsigned int
computeCovarianceMatrixNormalized (const pcl::PointCloud<PointT> &cloud,
const Eigen::Matrix<Scalar, 4, 1> ¢roid,
Eigen::Matrix<Scalar, 3, 3> &covariance_matrix);
3 协方差矩阵
https://www.zhihu.com/tardis/zm/art/37609917?source_id=1005
https://zhuanlan.zhihu.com/p/464822791
4 自伴随矩阵
https://zhuanlan.zhihu.com/p/550779050
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);//
构造一个自伴随举证类便于后续分解
5.总体算法思路分析
1首先将点云归一化后计算其3*3协方差矩阵
2.创建一个伴随矩阵的,并基于次对于分解得到特征向量以及值
3.由于特征矩阵只有x\y\z三个方向需要将其矫正垂直
4.后续这一步已经完全看不懂了
Eigen::Matrix4f tm = Eigen::Matrix4f::Identity();
Eigen::Matrix4f tm_inv = Eigen::Matrix4f::Identity();
tm.block<3, 3>(0, 0) = eigenVectorsPCA.transpose(); //R 计算PCA矩阵的转置矩阵
tm.block<3, 1>(0, 3) = -1.0f * (eigenVectorsPCA.transpose()) *(pcaCentroid.head<3>());// -R*t
tm_inv = tm.inverse();
标签:tm,PCA,点云主,矩阵,covariance,eigenVectorsPCA,PCL,include,Eigen
From: https://www.cnblogs.com/codeAndlearn/p/17483736.html