这里写目录标题

  • 程序
    • 第一种
    • 第二种
  • 原理

程序

计算协方差矩阵:

法线估计类NormalEstimation的实际计算调用程序内部执行以下操作:
对点云P中的每个点p
1.得到p点的最近邻元素
2.计算p点的表面法线n
3.检查n的方向是否一致指向视点,如果不是则翻转
在PCL内估计一点集对应的协方差矩阵,可以使用以下函数调用实现:
//定义每个表面小块的3x3协方差矩阵的存储对象
Eigen::Matrix3fcovariance_matrix;
//定义一个表面小块的质心坐标16-字节对齐存储对象
Eigen::Vector4fxyz_centroid;
//估计质心坐标
compute3DCentroid(cloud,xyz_centroid);
//计算3x3协方差矩阵
computeCovarianceMatrix(cloud,xyz_centroid,covariance_matrix);

注意,以下两种方法输入的点云数据都必须是XYZ格式,不能是XYZRGB

第一种

 // =====【2】计算法线========创建法线估计类======pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud(cloud_ptr);// 添加搜索算法 kdtree search  最近的几个点 估计平面 协方差矩阵PCA分解 求解法线pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setSearchMethod(tree);//设置近邻搜索算法 // 输出点云 带有法线描述pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ptr(new pcl::PointCloud<pcl::Normal>);pcl::PointCloud<pcl::Normal>& cloud_normals = *cloud_normals_ptr;// Use all neighbors in a sphere of radius 3cmne.setRadiusSearch(0.03);//半价内搜索临近点 3cm// 计算表面法线特征ne.compute(cloud_normals);

第二种

 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//存储估计的法线pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;//法线估计对象pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);//定义kd树指针tree->setInputCloud(cloud);                        //用cloud构建tree对象n.setInputCloud(cloud);                            //为法线估计对象设置输入点云n.setSearchMethod(tree);                          //设置搜索方法n.setKSearch(10);                                 //设置k搜索的k值为20//n.setRadiusSearch(0.005);n.compute(*normals);                              //估计法线存储结果到normals中std::cerr << "法线计算   完成" << std::endl;//由于XYZ坐标字段和法线字段需要在相同PointCloud对象中,//所以创建一个新的PointNormal类型的点云来存储坐标字段和法线连接后的点云。pcl::concatenateFields(*cloud, *normals, *cloud_with_normals);//连接字段,cloud_with_normals存储有向点云

原理

这篇是我看到的最全讲的最好的感觉,把我零零散散学的都串起来啦,终于知道为什么了!
PCL:从法线计算到曲率计算并可视化

----------------法线求解原理--------------

表面法线是几何体表面的重要属性,在很多领域都有大量应用,例如:在进行光照渲染时产生符合可视习惯的效果时需要表面法线信息才能正常进行,对于一个已知的几何体表面,根据垂直于点表面的矢量,因此推断表面某一点的法线方向通常比较简单。然而,由于我们获取的点云数据集在真实物体的表面表现为一组定点样本,这样就会有两种解决方法:

(1)使用曲面重建技术,从获取的点云数据集中得到采样点对应的曲面,然后从曲面模型中计算表面法线;曲面方程f(x,y,z)=0的一个法向量可以表示为n={e(df/dx), e(df/dy), e(df/dz)}.)

(2)直接从点云数据集中近似推断表面法线。

下面以已知一个点云数据集,在其中的每个点处直接近似计算表面法线。为例进行展开:

确定表面一点法线的问题近似于估计表面的一个相切面法线的问题,因此转换过来以后就变成一个最小二乘法平面拟合估计问题。

最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小。最小二乘法还可用于曲线拟合。其他一些优化问题也可通过最小化能量或最大化熵用最小二乘法来表达。

对空间中的一系列散点,寻求一个近似平面:(按最小原则选择的拟合平面为最小二乘拟合平面)

上述使用最小二乘我们已经可以根据某点的临近点阈,可以拟合出一个平面。接下来就是求平面的法线。表面法线是几何体面的重要属性。而点云数据集在真实物体的表面表现为一组定点样本。对点云数据集的每个点的法线估计,可以看作是对表面法线的近似推断。在PCL库中有专门针对法向量计算的库,但是必须了解计算原理才能记得更加深刻。

确定表面一点法线的问题近似于估计表面的一个相切面法线的问题,因此转换过来以后就变成一个最小二乘法平面拟合估计问题。

下一张图说明怎么是由求法线转换到求最小特征值对应的特征向量就是代表法线。

类似于上图中的平面方程求解,只是换了一种平面表示方法。(由一般式转换为法线式方程)

  

由上述推导过程可知,求法线就是求最小特征值对应的特征向量。

----

还可以观察上述右边图片中的A矩阵其实是个协方差矩阵;

在PCL内估计一点集对应的协方差矩阵,可以使用以下函数调用实现:

  1. //定义每个表面小块的3x3协方差矩阵的存储对象
  2. Eigen::Matrix3fcovariance_matrix;
  3. //定义一个表面小块的质心坐标16-字节对齐存储对象
  4. Eigen::Vector4fxyz_centroid;
  5. //估计质心坐标
  6. compute3DCentroid(cloud,xyz_centroid);
  7. //计算3x3协方差矩阵
  8. computeCovarianceMatrix(cloud,xyz_centroid,covariance_matrix);

通常,没有数学方法能解决法线的正负向问题,如上所示,通过主成分分析法(PCA)来计算它的方向也具有二义性,无法对整个点云数据集的法线方向进行一致性定向。图1显示出对一个更大数据集的两部分产生的影响,此数据集来自于厨房环境的一部分,很明显估计的法线方向并非完全一致,图2展现了其对应扩展的高斯图像(EGI),也称为法线球体(normal sphere),它描述了点云中所有法线的方向。由于数据集是2.5维,其只从一个单一的视角获得,因此法线应该仅呈现出一半球体的扩展高斯图像(EGI)。然而,由于定向的不一致性,它们遍布整个球体,如图2所示。

如果实际知道视点,那么这个问题的解决是非常简单的。对所有法线定向只需要使它们一致朝向视点方向,满足下面的方程式:

下面的图3展现了上面图1中的数据集的所有法线被一致定向到视点后的结果演示。

在PCL中对一个已知点的法线进行手动重新定向,你可以使用:

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

注意:如果数据集是从多个捕获视点中配准后集成的,那么上述法线的一致性定向方法就不适用了。需要使用更复杂的算法。更详细的信息见:http://pointclouds.org/documentation/tutorials/how_features_work.php#id1

选择合适的尺度

如之前介绍的,在估计一个点的表面法线时,我们需要从周围支持这个点的邻近点着手(也称作k邻域)。最近邻估计问题的具体内容又提出了另一个问题“合适的尺度”:已知一个取样点云数据集,k的正确取值是多少(k通过pcl::Feature::setKSearch给出)或者确定一个点r为半径的圆内的最近邻元素集时使用的半径r应该取什么值(r通过pcl::Feature::setRadiusSearch给出)。这个问题非常重要,并且在一个点特征算子的自动估计时(例如:用户没有给定阈值)是一个限制因素。为了更好地说明这个问题,以下图示表现了选择更小尺度(如:r值或k取相对小)与选择更大尺度(如:r值或k值比较大)时的两种不同效果。图4和图5分别为近视图和远视图,两图中左边部分展示选择了一个合理的比例因子,估计的表面法线近似垂直于两个平面,即使在互相垂直的边沿部分,可明显看到边沿。如果这个尺度取的太大(右边部分),这样邻近点集将更大范围地覆盖邻近表面的点,估计的点特征表现就会扭曲失真,在两个平面边缘处出现旋转表面法线,以及模糊不清的边界,这样就隐藏了一些细节信息。

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

估计法线实例详解:http://pointclouds.org/documentation/tutorials/index.php#features-tutorial

法线估计类NormalEstimation的实际计算调用程序内部执行以下操作:

  1. 对点云P中的每个点p
  2. 1.得到p点的最近邻元素
  3. 2.计算p点的表面法线n
  4. 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是点的k-最近邻元素集索引,plane_parameters和curvature是法线估计的输出,plane_parameters前三个坐标中,以(nx, ny, nz)来表示法线,第四个坐标D = nc . p_plane (centroid here) + p。输出表面曲率curvature通过协方差矩阵的特征值之间的运算估计得到,如:

使用OpenMP加速法线估计

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

-------------------曲率求解-----------------

曲率大小反映模型表面的凹凸程度。

利用上面法向量估计的PCA方法,在法向量估算的基础上进行数据点的曲率估算,曲率的估算方法如上式:

入描述了曲面沿法向量的变化,而表示数据点在切平面上的分布情况。定义下式为数据点,在k邻域内的曲面变分。

点云模型在数据点的曲率可近似为在该点的曲面变分,即

该式的基本思想实际上是使用曲面变分来近似曲率信息[1]。

曲率基础知识:
平均曲率、主曲率和高斯曲率是曲率的三个基本要素。
法曲率:曲面在一点沿着不同方向的弯曲程度不同。或者说曲面离开切平面的速度不同。这个弯曲属性可以用这一点的沿着这个方法的法曲率刻画
主曲率:过曲面上某个点上具有无穷个正交曲率,其中存在一条曲线使得该曲线的曲率为极大,这个曲率为极大值Kmax,垂直于极大曲率面的曲率为极小值Kmin。这两个曲率属性为主曲率。他们代表着法曲率的极值。
平均曲率:是空间上曲面上某一点任意两个相互垂直的正交曲率的平均值。如果一组相互垂直的正交曲率可表示为K1,K2,那么平均曲率则为:K = (K1 +K2 ) / 2。
高斯曲率:两个主曲率的乘积即为高斯曲率,又称总曲率,反映某点上总的完全程度。

  1. #include <iostream>
  2. #include <vector>
  3. #include <pcl/io/pcd_io.h>
  4. #include <pcl/point_types.h>
  5. #include <pcl/features/normal_3d.h>
  6. #include <pcl/features/principal_curvatures.h>
  7. using namespace std;
  8. int main (int argc, char** argv){
  9. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  10. pcl::io::loadPCDFile<pcl::PointXYZ>("A3 - Cloud.pcd", *cloud); //读取点云
  11. cout << "Loaded " << cloud->points.size() << " points." << std::endl;//显示读取点云的点数
  12. // 计算点云的法线
  13. pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
  14. normalEstimation.setInputCloud (cloud);
  15. //设置邻域点搜索方式
  16. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
  17. normalEstimation.setSearchMethod (tree);
  18. //定义一个新的点云储存含有法线的值
  19. pcl::PointCloud<pcl::Normal>::Ptr cloudWithNormals (new pcl::PointCloud<pcl::Normal>);
  20. //设置KD树搜索半径
  21. // normalEstimation.setRadiusSearch (0.03);
  22. normalEstimation.setKSearch(10);
  23. //计算出来法线的值
  24. normalEstimation.compute (*cloudWithNormals);
  25. // 建立主曲率计算
  26. pcl::PrincipalCurvaturesEstimation<pcl::PointXYZ, pcl::Normal, pcl::PrincipalCurvatures> principalCurvaturesEstimation;
  27. // 提供原始点云(没有法线)
  28. principalCurvaturesEstimation.setInputCloud (cloud);
  29. // 为点云提供法线
  30. principalCurvaturesEstimation.setInputNormals(cloudWithNormals);
  31. // 使用与法线估算相同的KdTree
  32. principalCurvaturesEstimation.setSearchMethod (tree);
  33. //principalCurvaturesEstimation.setRadiusSearch(1.0);
  34. principalCurvaturesEstimation.setKSearch(10);
  35. // 计算主曲率
  36. pcl::PointCloud<pcl::PrincipalCurvatures>::Ptr principalCurvatures (new pcl::PointCloud<pcl::PrincipalCurvatures> ());
  37. principalCurvaturesEstimation.compute (*principalCurvatures);
  38. std::cout << "output points.size: " << principalCurvatures->points.size () << std::endl;
  39. // 显示和检索第0点的主曲率。
  40. cout << "最大曲率;"<< principalCurvatures->points[0].pc1 << endl;//输出最大曲率
  41. cout << "最小曲率:"<< principalCurvatures->points[0].pc2 << endl;//输出最小曲率
  42. //输出主曲率方向(最大特征值对应的特征向量)
  43. cout << "主曲率方向;" << endl;
  44. cout << principalCurvatures->points[0].principal_curvature_x << endl;
  45. cout << principalCurvatures->points[0].principal_curvature_y << endl;
  46. cout << principalCurvatures->points[0].principal_curvature_z << endl;
  47. return 0;
  48. }

[1]

PCL法线计算及原理相关推荐

  1. pcl::compute3DCentroid()计算质心算法原理

    质心计算公式 质心指的是质量的中心,认为是物体质量集中于此点的假想点. 通常物体质心坐标PcP_cPc​计算公式如下: Pc=1M∑i=0nmiriP_c = \frac{1}{M} \sum_{i= ...

  2. 点云的平滑与法线计算

    需要平滑的情况: 1.用RGB-D激光扫描仪等设备扫描物体,尤其是比较小的物体时,往往会有测量误差.这些误差所造成的不规则数据如果直接拿来曲面重建的话,会使得重建的曲面不光滑或者有漏洞,而且这种不规则 ...

  3. 写给笨人的法线贴图原理

    我算个笨人吧.笨人以前弄懂一些东西后,讲给笨人听往往更有效.看之前请自行具备图形学关于光照的基础知识. >> world/object space normal map 我们先讲基于世界或 ...

  4. 计算机组原理ppt,计算机组原理第三章.ppt

    计算机组原理第三章 计算机组成原理 毛典辉 北京工商大学计算机与信息工程学院 Email: amaode@ 进一步结论: 当最高有效位产生进位而符号位无进位时,产生上溢: 当最高有效位无进位而符号位有 ...

  5. 通俗易懂量子计算的原理

    转自知乎 如有侵权 望告知 立即删除 量子计算/量子计算机的概念是著名物理学家费曼于1981年首先提出的. 后来大家试了试才知道,原来真的可以这么玩. [费曼还首先在Tiny Machine的课堂上首 ...

  6. Excel-个人所得税计算与原理推导

    Excel-个人所得税计算与原理推导 题目: 个人所得税的计算应为(工资-3500)*对应级别的税率-速扣数. 工资少于3500不扣税. 速扣数的意义是工资减去3500后直接乘以对应级别的税率所多扣除 ...

  7. html打折代码,HTML打折计算价格原理与脚本代码

    大概原理就是设置计算价格事件函数,取不同下拉打折数,计算结果送入文字框,感兴趣的朋友可以参考下 代码如下: 打折后价格计算 function calculator(){ var prices=docu ...

  8. 如何用 IT 业者能听懂的话介绍量子计算的原理?

    如何用 IT 业者能听懂的话介绍量子计算的原理? 赞同642 反对,不会显示你的姓名 Summer Clover,机器学习&量子算法 收起 陈旭鹏.杨发枝.彭磊 等人赞同 谢邀. 量子计算/量 ...

  9. 毕业论文ppt的研究方法及过程计算机专业,计算思维原理研究与实现数据组织毕业论文4喜欢就下吧(全文完整版)...

    <计算思维原理研究与实现数据组织毕业论文.doc>由会员分享,可免费在线阅读全文,更多与<计算思维原理研究与实现数据组织毕业论文(4)(喜欢就下吧)>相关文档资源请在帮帮文库( ...

最新文章

  1. mysql 字段授权_mysql授权管理
  2. php mssql image,php5连接mssql2005数据库表中的image字段图片显示
  3. Mysql数值型字符串按照数值进行排序
  4. sklearn自学指南(part49)--字典学习
  5. 重温.NET下Assembly的加载过程
  6. Android 自定义View实现QQ运动积分抽奖转盘
  7. [vue] vue-loader是什么?它有什么作用?
  8. (转)Java atomic原子类的使用方法和原理(一)
  9. Queue - 一种线程安全的FIFO实现
  10. Python操作PostgreSQL数据库的方法
  11. html5 天地图,天地图API
  12. 【物联网控制技术复习】【复数的概念】【拉普拉斯变换】
  13. “幸运盒子”可悲的命运
  14. Batch Normalization :深度网络中的BN层
  15. img: SVG格式在vue中的使用
  16. iOS判断当前设备机型 (包含至iPhone XS Max)
  17. 当面试官问 promise 的时候,他们希望听到什么(二)
  18. uni-app使用map组件开发map地图,获取后台返回经纬度进行标点
  19. 6.redis-哨兵
  20. 微信小程序直传腾讯云COS并对图片持久化文字水印案例

热门文章

  1. Android通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
  2. 到底什么是 路由器(router)、交换机(switch)
  3. [翻译Pytorch教程]NLP从零开始:使用序列到序列网络和注意力机制进行翻译
  4. 微信公众号网页授权--前端获取code及用户信息(vue)【简单详细版】
  5. 自定义View将圆角矩形绘制在Canvas上
  6. 深度学习--卷积神经网络
  7. 【WPF】后台切换前台图片
  8. windows下gfortran编译error:Note: The following floating-point exceptions are signalling: IEEE_UNDERFLOW
  9. ionic项目打包apk遇到的问题
  10. Linux 安装locust