运用PCL计算点云的法向量并显示,其理论介绍在《点云库PCL从入门到精通》书中讲的十分详细。可以参考PCL估计点云的表面法向量
对于其中比较难以理解的部分,做出自己一点通俗的解释。
对法向量定向的直观理解:
pcl::Normal的定义
compute(*normal)里计算出来的结果是:法向量的x,y,z坐标和表面曲率curvature。其内部结构为:
/*brief A point structure representing normal coordinates and the surface curvature estimate. (SSE friendly)ingroup common*/
struct Normal : public _Normal
{
inline Normal (const _Normal &p)
{
normal_x = p.normal_x;
normal_y = p.normal_y;
normal_z = p.normal_z;
data_n[3] = 0.0f;
curvature = p.curvature;
}
inline Normal ()
{
normal_x = normal_y = normal_z = data_n[3] = 0.0f;
curvature = 0;
}
inline Normal (float n_x, float n_y, float n_z)
{
normal_x = n_x; normal_y = n_y; normal_z = n_z;
curvature = 0;
data_n[3] = 0.0f;
}
friend std::ostream& operator << (std::ostream& os, const Normal& p);
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
pcl::Normal的几种输出方式:
cout<<normals->points[0]<<endl;
cout<<"["<<normals->points[0].normal_x<<" "
<<normals->points[0].normal_y<<" "
<<normals->points[0].normal_z<<" "
<<normals->points[0].curvature<<"]"<<endl;
cout<<"["<<normals->points[0].normal[0]<<" "
<<normals->points[0].normal[1]<<" "
<<normals->points[0].normal[2]<<" "
<<normals->points[0].curvature<<"]"<<endl;
cout<<"["<<normals->points[0].data_n[0]<<" "
<<normals->points[0].data_n[1]<<" "
<<normals->points[0].data_n[2]<<" "
<<normals->points[0].curvature<<"]"<<endl;
完整代码展示:
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/features/normal_3d_omp.h>//使用OMP需要添加的头文件
using namespace std;
int main()
{
//加载点云数据
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("horse.pcd", *cloud) == -1)
{
PCL_ERROR("Could not read file\n");
}
//计算法线
pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;//OMP加速
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
//建立kdtree来进行近邻点集搜索
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
//为kdtree添加点云数据
//tree->setInputCloud(cloud);
n.setNumberOfThreads(10);//设置openMP的线程数
//n.setViewPoint(0,0,0);//设置视点,默认为(0,0,0)
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(10);//点云法向计算时,需要所搜的近邻点大小
//n.setRadiusSearch(0.03);//半径搜素
n.compute(*normals);//开始进行法向计
/*图形显示*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D viewer"));
//viewer->initCameraParameters();//设置照相机参数,使用户从默认的角度和方向观察点云
//设置背景颜色
viewer->setBackgroundColor(0.3, 0.3, 0.3);
viewer->addText("faxian", 10, 10, "text");
//设置点云颜色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 225, 0);
//添加坐标系
viewer->addCoordinateSystem(0.1);
viewer->addPointCloud<pcl::PointXYZ>(cloud, single_color, "sample cloud");
viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 20, 0.02, "normals");
//设置点云大小
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud");
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}