最近因为项目,需要计算点云的法向量,所以在网上看了一些资料,然后知道pcl库里面有这些功能,pcl的法向量计算的原理:
pcl里面计算点云(自己的理解)
根据顶点采样最近的局部点云(k个),根据自己的点云拟合出一个局部平面,然后计算平面的法向量。就是顶点的向量。
计算可以通过PCA那种,可以计算顶点的三个方向的主成分,然后得到最次的主成分对应的法向量,就是平面法向量。
以下是自己使用PCL计算法向量的过程,因为引用都是PCL库,所以只需要理解这个库的使用就可以了。
#include<pcl\point_types.h>
#include<pcl\kdtree\kdtree_flann.h>
#include<pcl\features\normal_3d.h>
#include<pcl\point_cloud.h>
bool CaculateNormals()
{
if (HasNormal() && vertices_normals_.size() == vertices_.size())
return true;
std::cout << "start compute normal..." << std::endl;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
for (int i = 0; i < vertices_.size(); ++i) //这是一个类里面的函数,需要自己提供点云
{
pcl::PointXYZ p(vertices_[i](0), vertices_[i](1), vertices_[i](2));
cloud->points.emplace_back(p);
}
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> cloud_normals;
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
//在flann中找到kdtree搜索机制
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
//为kdtree增加搜索的点云
tree->setInputCloud(cloud);
cloud_normals.setInputCloud(cloud);
cloud_normals.setSearchMethod(tree);
cloud_normals.setKSearch(20);
std::clock_t start_read = std::clock();
cloud_normals.compute(*normals);
std::clock_t end_read = std::clock();
const float parsing_time = static_cast<float>(double(end_read - start_read)) / 1000.f;
std::cout << "\t compute normal time parsing " << parsing_time << " seconds " << std::endl;
std::cout << "normal num is: " << normals->size() << std::endl;
std::cout << "end compute the cloud normals." << std::endl;
//清空
vertices_normals_.swap(std::vector<Eigen::Vector3f>());
for (int i = 0; i < normals->size(); ++i)
{
Eigen::Vector3f tmp(normals->points[i].normal_x,
normals->points[i].normal_y, normals->points[i].normal_z);
vertices_normals_.emplace_back(tmp);
}
return true;
}
这样就得到点云中的法向量。