PCL学习:点云特征-法线估计(1)

表面法线计算,两种解决方法:
(1 )使用曲面重建技术,从获取的点云数据集中得到采样点对应的曲面,然后从曲面模型中计算表面法线;
(2 )直接从点云数据集中近似推断表面法线。
本小节将针对后一种情况进行介绍,已知一个点云数据集在其中的每个点处直接近似计算表面法线。

1. 理论基础

(1) 法线估算方法

确定表面一点法线的问题近似于估计表面的一个相切面法线的问题,因此转换过来以后就变成一个最小二乘法平面拟合估计问题;因此估计表面法线的解决方案就变成了分析一个协方差矩阵的特征矢量和特征值(或者 PCA一主成分分析) ,这个协方差矩阵从查询点的近邻元素中创建。更具体地说,对于每一个点Pi,对应的协方差矩阵 C 如下:

(2)法线定向:一致朝向视点方向

2. 选择合适的尺度

在估计一个点的表面法线时,我们需要从周围支持这个点的邻近点着手〈也称做 h 邻域〉。最近邻估计问题的具体内容又提出了另一个问题“合适的尺度”:已知一个取样点云数据集,h 的正确取值是多少 ω 通过 pcl: :Feature : :setKSearch 给出〉或者确定一个点 r 为半径的圆内的最近邻元素集时使用的半径 r 应该取什么值 ( r 通过 pcl: : Feature: : setRadiusSearch 给出〉:

可粗略假设,以应用程序所需的细节需求为参考,选择确定点的邻域所用的尺度。简言之,如果杯子手柄和圆柱体部分之间边缘的曲率是重要 的,那么需要足够小的尺度来捕获这些细节信息 ,而在其他不需要细节信息的应用中可选择大的尺度。

 3. 法线估计示例

实现对输入点云数据集中的点估计一组表面法线。执行的操作是,对应点云P中每一个点p:

得到p点最近邻元素,计算p点的表面的法线N,检查N的方向是否指向视点如果不是则翻转。

#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/integral_image_normal.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>

int
main ()
 {
//加载点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile ("..\\..\\source\\table_scene_lms400.pcd", *cloud);
//估计法线
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (cloud);
//创建一个空的kdtree对象,并把它传递给法线估计对象
//基于给出的输入数据集,kdtree将被建立
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (tree);
//输出数据集
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
//使用半径在查询点周围3厘米范围内的所有邻元素
ne.setRadiusSearch (0.03);
//计算特征值
ne.compute (*cloud_normals);
// cloud_normals->points.size ()应该与input cloud_downsampled->points.size ()有相同尺寸
//法线可视化
pcl::visualization::PCLVisualizer viewer("PCL Viewer");
viewer.setBackgroundColor (0.0, 0.0, 0.0);
viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, cloud_normals);

while (!viewer.wasStopped ())
{
     viewer.spinOnce ();
}

return 0;
}

.\normal_estimation.exe 

说明:

1,视点默认坐标是(0,0,0)可使用如下函数替换:

setViewPoint (float vpx, float vpy, float vpz);

2,如果要计算单个点的法线,使用

computePointNormal (const pcl::PointCloud<PointInT> &cloud, const std::vector<int> &indices, Eigen::Vector4f &plane_parameters, float &curvature);

此处, cloud 是包含点的输入点云, indices 是点的 k-最近邻元素集索引, plane_parameters 和 curvature 是法线估计的输出, plane _ parameters 前 三个 坐标中,以( nx, ny, nz )来表示法线,第四个坐标 D = nc . p_ plane (centroid here) + p . 输出表面曲率 curvature 通过协方差矩阵的特征值之间的运算估计得到,如下:

\sigma = \frac{\lambda_0}{\lambda_0 + \lambda_1 + \lambda_2}

3,使用 OpenMP 加速法线估计

对于对运算速度有要求的用户,PCL 点云库提供了一个表面法线的附加实现程序,它使用多核/多线程开发规范利用 OpenMP 来提高计算速度。它的类命名为pcl: : NormaleEstimationOMP,并且它的应用程序接口 CAPD lOO%兼容单线程 pcl: :
NormalEstimation ,这使它适合作为一个可选提速方法。在 8 核系统中可以轻松提6-8倍。

猜你喜欢

转载自blog.csdn.net/zfjBIT/article/details/93620439