sql2008做网站,旅游网站域名应该如何设计,wordpress和django哪个好,一款app开发需要多少钱估算点云表面法线 *
表面法线是几何表面的重要属性#xff0c;在许多领域#xff08;例如计算机图形应用程序#xff09;中大量使用#xff0c;以应用正确的光源以产生阴影和其他视觉效果。
给定一个几何表面#xff0c;通常很难将表面某个点的法线方向推断为垂直于该点…估算点云表面法线 *¶
表面法线是几何表面的重要属性在许多领域例如计算机图形应用程序中大量使用以应用正确的光源以产生阴影和其他视觉效果。
给定一个几何表面通常很难将表面某个点的法线方向推断为垂直于该点表面的向量。但是由于我们获取的点云数据集是真实表面上的一组点样本因此有两种可能性
使用表面网格化技术从获取的点云数据集中获取基础表面然后从网格中计算表面法线使用近似值直接从点云数据集中推断表面法线。
我们将使用后者即给定点云数据集直接计算云中每个点的表面法线。
理论基础¶
尽管有许多不同的法线估计方法我们先了解其中最简单也是最常见的一个确定表面一点法线的问题近似于估计表面的一个相切面法线的问题因此转换过来以后就变成一个最小二乘法平面拟合估计问题。
参见官网介绍
算法论文链接RusuDissertation
法线计算¶ // 定义一小块表面区域的协方差矩阵
Eigen::Matrix3f covariance_matrix;
// 定义一小块表面区域的质心坐标
Eigen::Vector4f xyz_centroid;
// 计算质心坐标
pcl::compute3DCentroid(*cloud, xyz_centroid);
// 计算3x3的协方差矩阵
pcl::computeCovarianceMatrix(*cloud , xyz_centroid, covariance_matrix);法线方向问题¶
没有直接的数学方法可以解决法线的朝向问题如下边的左图和中图该数据及来自厨房环境的一部分。很明显图中显示出的法线方向并非朝着一个方向。可以观察右图对所有法线合并成的扩展高斯图EGI也称为法线球体Normal Sphere它描述了点云中所有法线的方向。由于数据是2.5维的即数据只从单一视角获取其法线也应该仅是一个半球体的扩展高斯图由于我们没有定下法线的方向所以这些法线遍布球体。 则可以观察到将所有法线重新定向之后的效果和其对应的扩展高斯图EGI。
选择合适的比例¶
如前所述需要根据该点的周围点邻域支持也称为k-neighborhoodk邻域来估算该点的表面法线。 最近邻估计问题的细节提出了正确的比例因子的问题给定采样点云数据集如何选择正确的k通过pcl::Feature::setKSearch给出或r通过pcl::Feature::setRadiusSearch 给出值来确定点的最近邻居 这个问题非常重要并且构成了点特征表示的自动估计即在没有用户给定阈值的情况下的限制因素。为了更好地说明此问题下图显示了选择较小的比例即较小的r或k与较大的比例即较大的r或k的效果。图的左侧部分描绘了一个合理选择的比例因子其中估计的表面法线大致垂直于两个平面并且在整个桌子上可见小的边缘。但是如果比例因子太大右侧部分则相邻对象的集合会覆盖来自相邻表面的较大点则估计的点要素表示会失真在两个平面边缘处旋转的曲面法线会被涂抹边缘和压制的精细细节。 无需赘述太多只需假设现在必须根据应用所需的详细程度来选择确定点的邻域的比例即可。简而言之如果杯子的手柄和圆柱部分之间的边缘处的曲率很重要则比例因子必须足够小以捕获这些细节否则要大。
默认视点坐标为(0,0,0)(0,0,0)可以使用以下代码修改
setViewPoint(float vpx, float vpy, float vpx);计算表面法向量内部伪代码
// 遍历每个点云P中的点p
for each point p in cloud P // 得到p点的最近邻1. get the nearest neighbors of p// 计算p点的表面法线n2. compute the surface normal n of p// 检查n的方向是否指向视点如果不是则进行反转3. check if n is consistently oriented towards the viewpoint and flip otherwise#include pcl/visualization/cloud_viewer.h
#include iostream
#include pcl/io/io.h
#include pcl/io/pcd_io.h
#include pcl/features/normal_3d.hint
main() {// load point cloudpcl::PointCloudpcl::PointXYZ::Ptr cloud(new pcl::PointCloudpcl::PointXYZ);pcl::io::loadPCDFile(person.pcd, *cloud);// estimate normalspcl::PointCloudpcl::Normal::Ptr normals(new pcl::PointCloudpcl::Normal);// Object for normal estimation.pcl::NormalEstimationpcl::PointXYZ, pcl::Normal normalEstimation;//normalEstimation.setIndices()normalEstimation.setInputCloud(cloud);// For every point, use all neighbors in a radius of 3cm.normalEstimation.setRadiusSearch(0.03);// A kd-tree is a data structure that makes searches efficient. More about it later.// The normal estimation object will use it to find nearest neighbors.pcl::search::KdTreepcl::PointXYZ::Ptr kdtree(new pcl::search::KdTreepcl::PointXYZ);normalEstimation.setSearchMethod(kdtree);// Calculate the normals.normalEstimation.compute(*normals);// visualize normalspcl::visualization::PCLVisualizer viewer(PCL Viewer);viewer.setBackgroundColor(0.0, 0.0, 0.5);viewer.addPointCloudpcl::PointXYZ(cloud, cloud);// 参数int level2 表示每n个点绘制一个法向量// 参数float scale0.01 表示法向量长度缩放为0.01倍viewer.addPointCloudNormalspcl::PointXYZ, pcl::Normal(cloud, normals, 2, 0.01, normals);// viewer.addCoordinateSystem(1.0);while (!viewer.wasStopped()) {viewer.spinOnce();}return 0;
}