pcl里面的法线估计

法线估计是一个很重要的特征,常常在被使用在很多计算机视觉的应用里面,比如可以用来推出光源的位置,通过阴影与其他视觉影响。

给一个几何表面,去推断给定点的法线方向,即垂直向量的方向往往是不容易的。然而,在我们获取物体表面的点云数据后,有两大选择:

1.从已获取的点云数据集中得到潜在表面,并用表面网格化技术,来计算网格的表面法线。

2.使用近似值来推断点云数据集的表面法线。

尽管有很多法线估计的方法存在,但是我们这次将会讲的是最简单的方法。表面法线的问题可以近似化解为切面的问题,这个切面的问题又会变成最小二乘法拟合平面的问题。

解决表面法线估计的问题可以最终化简为对一个协方差矩阵的特征向量和特征值的分析(或者也叫PCA-Principal Component Analysis 主成分分析),这个协方差矩阵是由查询点的最近邻产生的。对于每个点Pi,我们假设协方差矩阵C如下:

这里K指的是离点的最近的K个点,是最近邻的中心,是第j个特征值,是第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);

总的来说,因为数学上没有方法解决法线的符号,比如一个球面,法线可以指向球心,也可以背向球心。下面的两幅图像是描述厨房的点云图,右边的图像是通过高斯扩展图(EGI Extended Gaussian Image),也常常叫做法线球。法线球是一个描述点云里面所有法线方向的一种方式。因为数据集是2.5D的,何为2.5D,你可以把上下,左右,前后看成一个D,然后现实生活里面往往不可能每个方向都兼顾,比如摄像机只能拍到前面的,所有是1(上下)+1(左右)+0.5(前)叫2.5D,当然这是建立在摄像机为单一视角的情况下,即摄像机不会动,一直是固定的。所以理论上,EGI图,即高斯球也应该是2.5D的,因为你摄像机是向前拍摄的,所以物体的法线也是向前的,然而因为这个算法的原因。主成分分析这个算法,不能解决法线的符号,所以导致了法线指向可能往前,也可能往后,导致整个球里面各个方向都可能存在着法线。



解决上面的法线方向不定的问题,我们得知道视角的向量,这就很简单了,只要法线和  视角与点的连线,这两条线的夹角是锐角,即这两个向量的点积大于0即可。

我们经过上述的处理后,图片就变成了这样

PCL(Point Cloud Library)是一个开源的点云处理库,广泛用于计算机视觉和机器人学领域。其中的法线滤波器(Normal Filtering)是一种常见的预处理步骤,用于估计每个表面点的法线方向,从而提高形状和纹理的描述。 在PCL中,法线滤波可以通过`pcl::NormalEstimation`类结合`pcl::MeanShiftNormalEstimation`或者其他方法来实现。这里是一个简单的C++示例,演示如何使用`pcl::MeanShiftNormalEstimation`进行法线滤波: ```cpp #include <pcl/point_cloud.h> #include <pcl/features/normal_3d.h> #include <pcl/io/pcd_io.h> #include <pcl/console/print.h> int main() { // 读取点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); if (pcl::io::loadPCDFile<pcl::PointXYZ> ("input.pcd", *cloud) == -1) { PCL_ERROR ("Cloud read error.\n"); return (-1); } // 创建法线计算器并设置参数 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud(cloud); ne.setKSearch(50); // 设置搜索邻居的范围 // 使用Mean Shift算法计算法线 pcl::MeanShiftNormalEstimation<pcl::PointXYZ, pcl::Normal> msne; msne.setInputCloud(cloud); msne.setRadiusSearch(0.03); // 设置搜索半径 msne.setKernelSigma(0.01); // 设置核函数的带宽 // 计算法线并保存到新的点云 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>); msne.compute(*cloud_normals); // 将法线附加到原始点云 pcl::concatenateFields(*cloud, *cloud_normals, *cloud); // 输出处理后的点云 pcl::io::savePCDFile("output_with_normals.pcd", *cloud); return 0; } ``` 在这个例子中,我们首先读取点云数据,然后创建`NormalEstimation`对象来执行法线估计。接着,我们使用`MeanShiftNormalEstimation`来优化这个过程,并将结果保存为一个新的`pcl::PointCloud<pcl::Normal>`。最后,我们将计算出的法线信息添加回原始点云并保存为新文件
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值