估计点云曲面法向量

本文介绍了点云数据集中计算法向量的方法,包括最小二乘平面拟合、协方差矩阵与PCA分析。内容涵盖理论基础,如通过近邻点的协方差矩阵估计法向量,以及选择合适尺度对点云进行处理的重要性。同时,讨论了视点对法向量一致性的影响以及在PCL库中实现法向量估计的代码示例。此外,还强调了正确选择近邻点数量(k值)对点云特征表示的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.理论基础

计算曲面上一点的法向量类似于估计与曲面相切的平面的法向量,这就转化成了最小二乘平面拟合估计问题。
在查询点的近邻处创建的协方差矩阵,因此估计曲面法向量的求解便简化为,对协方差矩阵特征向量和特征值的分析。具体来讲,对任意一个点pi,我们从下式中计算协方差矩阵:
在这里插入图片描述
其中k是pi点的近邻点个数, p_hat表示近邻点的三维质心λj表示协方差矩阵的第j个特征值,Vj表示第j个特征向量。
从一组点中估计协方差矩阵可以使用:

  // Placeholder for the 3x3 covariance matrix at each surface patch
  Eigen::Matrix3f covariance_matrix;
  // 16-bytes aligned placeholder for the XYZ centroid of a surface patch
  Eigen::Vector4f xyz_centroid;

  // Estimate the XYZ centroid
  compute3DCentroid (cloud, xyz_centroid);

  // Compute the 3x3 covariance matrix
  computeCovarianceMatrix (cloud, xyz_centroid, covariance_matrix);

一般来说,由于没有数学方法来求解法线的符号,因此通过主成分分析(PCA)计算的法线方向不明确,并且在整个点云数据集上的方向不一致。下图显示了代表厨房环境一部分的较大数据集的两个部分的这些影响。左下角的图显示了扩展高斯图像(EGI),也称为法线球体,它描述了点云中所有法线的方向。由于数据集是2.5维的,因此是从单个视点获取的,法线应仅出现在EGI中球体的一半上。但是,由于方向不一致,它们分布在整个球体上。
在这里插入图片描述
如果视点Vp实际上是已知的,那么解决这个问题很容易。要使所有的法向量ni全部朝向视点,它们需要满足方程:
在这里插入图片描述
下图显示了上图中数据集中的所有法线始终朝向视点后的结果。
在这里插入图片描述
要在PCL中手动重新定位给定点法线,可以使用:

flipNormalTowardsViewpoint (const PointT &point, float vp_x, float vp_y, float vp_z, Eigen::Vector4f &normal);

2.选择合适的尺度

估计曲面上一个点的法向量需要找到这个点的最近邻,最近邻估计问题的细节提出了正确比例因子的问题:给出一个点云数据集,那么如何选择合适的近邻k值?
这个问题是非常重要的,并且在点特征表示的自动估计(即,没有用户给定的阈值)中构成限制因素。为了更好的说明这个问题,下图展示了选择小尺度对比大尺度的效果。
在这里插入图片描述
图的左侧部分描述了一个合理的精心选择的比例因子,估计的曲面法线与两个平面近似垂直,小边缘在整个桌子上都可见。但是,如果比例因子太大(右部分),因此近邻点集比相邻曲面的覆盖点更大,则估计的点特征表示会失真,在两个平面曲面的边缘上旋转曲面法线,并涂抹边缘和抑制精细细节。在不涉及太多细节的情况下,假设现在,必须根据应用程序所需的细节级别来选择用于确定点的邻域的比例就足够了。简单地说,如果杯子把手和圆柱形部分之间边缘的曲率很重要,则比例因子需要足够小才能捕捉到这些细节,否则就需要足够大。

3.估计法向量

#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>

{
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

  ... read, pass in or create a point cloud ...

  // Create the normal estimation class, and pass the input dataset to it
  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
  ne.setInputCloud (cloud);

  // Create an empty kdtree representation, and pass it to the normal estimation object.
  // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
  ne.setSearchMethod (tree);

  // Output datasets
  pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);

  // Use all neighbors in a sphere of radius 3cm
  ne.setRadiusSearch (0.03);

  // Compute the features
  ne.compute (*cloud_normals);

  // cloud_normals->size () should have the same size as the input cloud->size ()*
}

从NormalEstimation类的compute的调用仅做了下面的事:

对于点云P中的每个点p
1.获取p的最近邻
2.计算p的曲面法向量n
3.检查n是否始终朝向视点,否则翻转

视点默认在(0,0,0)处,可以通过函数改变:

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

要计算单个点的法向量,使用:

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

其中cloud是输入点云,indices表示cloud的k近邻集合,plane_parameters和curvature表示法向量的估计输出,plane_parameters的前三个参数表示法向量(nx,ny,nz),第四个参数D=nc.p_plane(这里表示质心)+p。输出曲面曲率估计为协方差矩阵的特征值之间的关系(如上所述):
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值