PCL:计算点云法向量并可视化

文章目录

    • 1 点云法向量(法线)估计
    • 2 法线估计与可视化
    • 3 OpenMP加速法线估计

1 点云法向量(法线)估计

PCL法线估计是通过寻找待估计点与其邻域点共同构成的局部平面的法向量实现的。通过主成分分析,最小特征向量就是该点法向量,通常法向量具有二义性,需要指定视点 V p V_p Vp 进行法向量定向。

对所有法线 n i n_i ni 定向,只需要使它们一致指向视点方向,满足下面的方程:
n i ⋅ ( V p − P i ) > 0 n_i·(V_p-P_i)>0 ni(VpPi)>0

邻域点的选择方式有两种,一种是K近邻,指定邻域点的数量;一种是R近邻,指定邻域半径。

K近邻

pcl::Feature::setKSearch

R近邻

pcl::Feature::setRadiusSearch

2 法线估计与可视化

代码:

#include 
#include 
#include 
#include 
#include 
VTK_MODULE_INIT(vtkRenderingOpenGL);

using namespace std;

typedef pcl::PointXYZ PointT;

int main()
{
	//--------------------------- 加载点云 ---------------------------
	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	if (pcl::io::loadPCDFile("table.pcd", *cloud) < 0)
	{
		PCL_ERROR("->点云文件不存在!\a\n");
		system("pause");
		return -1;
	}
	//===============================================================
	
	
	//--------------------------- 法线估计 ---------------------------
	pcl::NormalEstimation<PointT, pcl::Normal> ne;		//创建法线估计对象
	ne.setInputCloud(cloud);							//设置法线估计输入点云
	pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>());	//创建一个空的kdtree
	ne.setSearchMethod(tree);													//将空kdtree传递给法线估计对象 ne
	pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//法向量计算结果
	ne.setKSearch(10);			//设置K近邻的个数
	//ne.setRadiusSearch(0.05);	//设置半径邻域的大小,两种方式二选一
	ne.setViewPoint(0, 0, 1);	//设置视点向量,默认0向量(0,0,0),没有方向
	ne.compute(*normals);		//执行法线估计,并将结果保存到normals中
	//===============================================================


	//-------------------------- 法线可视化 --------------------------
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer")); //创建视窗对象,定义标题栏名称“3D Viewer”
	viewer->addPointCloud<PointT>(cloud, "original_cloud");	//将点云添加到视窗对象中,并定义一个唯一的ID“original_cloud”
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0.5, "original_cloud"); //点云附色,三个字段,每个字段范围0-1
	viewer->addPointCloudNormals<PointT, pcl::Normal>(cloud, normals, 10, 0.05, "normals");	//每十个点显示一个法线,长度为0.05

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}
	//===============================================================
	
	return 0;
}

结果展示:

PCL:计算点云法向量并可视化_第1张图片

要计算一个点的法线,可使用 computePointNormal 函数:

  • 输入参数:原始点云cloud、要估计法线的点的索引 indices
  • 输出参数:法线plane_parameters(nx, ny, nz, nc)、曲率curvature
computePointNormal (const pcl::PointCloud<PointInT> &cloud, const std::vector<int> &indices, Eigen::Vector4f &plane_parameters, float &curvature);

3 OpenMP加速法线估计

PCL官网:法线估计是一个比较耗时的操作,PCL提供了OpenMP 加速法线估计的方法,在8核处理器下,可提高6~8倍。

代码:

#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef pcl::PointXYZ PointT;

int main()
{
	//--------------------------- 加载点云 ---------------------------
	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	if (pcl::io::loadPCDFile("table.pcd", *cloud) < 0)
	{
		PCL_ERROR("->点云文件不存在!\a\n");
		system("pause");
		return -1;
	}
	cout << "->加载点云个数:" << cloud->points.size() << endl;
	//===============================================================
	
	pcl::console::TicToc time;
	time.tic();
	//--------------------------- 法线估计 ---------------------------
	pcl::NormalEstimation<PointT, pcl::Normal> ne;		//创建法线估计对象
	ne.setInputCloud(cloud);							//设置法线估计输入点云
	pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>());	//创建一个空的kdtree
	ne.setSearchMethod(tree);													//将空kdtree传递给法线估计对象 ne
	pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//法向量计算结果
	ne.setKSearch(10);			//设置K近邻的个数
	//ne.setRadiusSearch(0.05);	//设置半径邻域的大小,两种方式二选一
	ne.setViewPoint(0, 0, 1);	//设置视点向量,默认0向量(0,0,0),没有方向
	ne.compute(*normals);		//执行法线估计,并将结果保存到normals中
	//===============================================================
	double t1 = time.toc() / 1000;
	cout << "->法线估计用时:" << t1 << " s" << endl;


	pcl::console::TicToc time_omp;
	time_omp.tic();
	//---------------------- OpenMP加速法线估计 ----------------------
	pcl::NormalEstimationOMP<PointT, pcl::Normal> omp;
	omp.setInputCloud(cloud);
	pcl::search::KdTree<PointT>::Ptr tree_omp(new pcl::search::KdTree<PointT>());
	omp.setSearchMethod(tree_omp);
	omp.setNumberOfThreads(8);		//设置线程数
	omp.setKSearch(10);
	ne.setViewPoint(0, 0, 1);
	ne.compute(*normals);
	//===============================================================
	double t_omp = time_omp.toc() / 1000;
	cout << "->OpenMP加速法线估计用时:" << t_omp << " s" << endl;

	cout << "->OpenMP效率是原来的 " << t1 / t_omp << " 倍" << endl;

	return 0;
}

输出结果:

->加载点云个数:41049
->法线估计用时:3.888 s
->OMP加速法线估计用时:3.569 s
->OMP效率是原来的 1.08938

实际加速效果并不明显!!!


相关链接:

PCL可视化点云法向量异常Errer:no override found for “VtkActor“

PCL点云数据处理基础❤️❤️❤️目录

你可能感兴趣的:(PCL,点云数据处理基础,算法)