首页 > 其他分享 >PCL 点云表面法线估算

PCL 点云表面法线估算

时间:2024-09-26 09:53:45浏览次数:12  
标签:法线 PCL viewer 表面 pcl normals 点云 cloud

估算点云表面法线
表面法线是几何表面的重要属性,在许多领域(例如计算机图形应用程序)中大量使用,以应用正确的光源以产生阴影和其他视觉效果。

给定一个几何表面,通常很难将表面某个点的法线方向推断为垂直于该点表面的向量。但是,由于我们获取的点云数据集是真实表面上的一组点样本,因此有两种可能性:

使用表面网格化技术从获取的点云数据集中获取基础表面,然后从网格中计算表面法线;
使用近似值直接从点云数据集中推断表面法线。
我们将使用后者,即给定点云数据集,直接计算云中每个点的表面法线。

理论基础
尽管有许多不同的法线估计方法,我们先了解其中最简单也是最常见的一个,确定表面一点法线的问题近似于估计表面的一个相切面法线的问题,因此转换过来以后就变成一个最小二乘法平面拟合估计问题。

法线方向问题
没有直接的数学方法可以解决法线的朝向问题,如下边的左图和中图,该数据及来自厨房环境的一部分。很明显图中显示出的法线方向并非朝着一个方向。可以观察右图,对所有法线合并成的扩展高斯图(EGI),也称为法线球体(Normal Sphere),它描述了点云中所有法线的方向。由于数据是2.5维的,即数据只从单一视角获取,其法线也应该仅是一个半球体的扩展高斯图,由于我们没有定下法线的方向,所以这些法线遍布球体。

image-20200516192216734

选取其朝向视点的那个方向即可:

image-20200516192721669

则可以观察到将所有法线重新定向之后的效果和其对应的扩展高斯图EGI。

选择合适的比例
如前所述,需要根据该点的周围点邻域支持,也称为k-neighborhood(k邻域)来估算该点的表面法线。 最近邻估计问题的细节提出了正确的比例因子的问题:给定采样点云数据集,如何选择正确的k(通过pcl::Feature::setKSearch给出)或r(通过pcl::Feature::setRadiusSearch 给出)值来确定点的最近邻居?

image-20200516182945375

这个问题非常重要,并且构成了点特征表示的自动估计(即在没有用户给定阈值的情况下)的限制因素。为了更好地说明此问题,下图显示了选择较小的比例(即较小的r或k)与较大的比例(即较大的r或k)的效果。图的左侧部分描绘了一个合理选择的比例因子,其中估计的表面法线大致垂直于两个平面,并且在整个桌子上可见小的边缘。但是,如果比例因子太大(右侧部分),则相邻对象的集合会覆盖来自相邻表面的较大点,则估计的点要素表示会失真,在两个平面边缘处旋转的曲面法线会被涂抹边缘和压制的精细细节。

_images/normals_different_radii.jpg
在这里插入图片描述

无需赘述太多,只需假设现在必须根据应用所需的详细程度来选择确定点的邻域的比例即可。简而言之,如果杯子的手柄和圆柱部分之间的边缘处的曲率很重要,则比例因子必须足够小以捕获这些细节,否则要大。

计算表面法向量内部伪代码:

// 遍历每个点云P中的点p
for each point p in cloud P 
    // 得到p点的最近邻
    1. get the nearest neighbors of p
    // 计算p点的表面法线n
    2. compute the surface normal n of p
    // 检查n的方向是否指向视点,如果不是则进行反转
    3. check if n is consistently oriented towards the viewpoint and flip otherwise

代码实现
normal_estimation.cpp

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

/**
 * 评估法向量
 */
int
main() {
    // load point cloud
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("./data/target.pcd", *cloud);

    // estimate normals
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

    // Object for normal estimation.
    pcl::NormalEstimation<pcl::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::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
    normalEstimation.setSearchMethod(kdtree);
    // Calculate the normals.
    normalEstimation.compute(*normals);

    // visualize normals
    pcl::visualization::PCLVisualizer viewer("PCL Viewer");
    viewer.setBackgroundColor(0.0, 0.0, 0.5);
    viewer.addPointCloud<pcl::PointXYZ>(cloud, "cloud");
    // 参数int level=2 表示每n个点绘制一个法向量
    // 参数float scale=0.01 表示法向量长度缩放为0.01倍
    viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 2, 0.01, "normals");
//    viewer.addCoordinateSystem(1.0);

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

实现效果

在这里插入图片描述

积分图估算点云法线
此方法进行法线估计只适用于有序点云,对于无序点云就只能采用其他方法。

代码实现
integral_image_normal.cpp

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

int
main() {
    // load point cloud
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("./data/table_scene_mug_stereo_textured.pcd", *cloud);

    // estimate normals
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

    // 创建一个用于法线估计的对象并计算法线
    pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    // 有以下可选的估算方式:
    /**
    enum NormalEstimationMethod
    {
      COVARIANCE_MATRIX,
      AVERAGE_3D_GRADIENT,
      AVERAGE_DEPTH_CHANGE
    };
     COVARIANCE_MATRIX模式创建9个积分图像,以根据其局部邻域的协方差矩阵为特定点计算法线。
     AVERAGE_3D_GRADIENT模式创建6个积分图像以计算水平和垂直3D渐变的平滑版本,并使用这两个渐变之间的叉积计算法线。
     AVERAGE_DEPTH_CHANGE模式仅创建单个积分图像,并根据平均深度变化计算法线。
     */
    ne.setNormalEstimationMethod(ne.AVERAGE_3D_GRADIENT);
    ne.setMaxDepthChangeFactor(0.02f);
    ne.setNormalSmoothingSize(10.0f);
    ne.setInputCloud(cloud);
    ne.compute(*normals);

    // visualize normals
    pcl::visualization::PCLVisualizer viewer("PCL Viewer");
    viewer.setBackgroundColor(0.0, 0.0, 0.5);
    viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals);

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

实现效果
在这里插入图片描述

标签:法线,PCL,viewer,表面,pcl,normals,点云,cloud
From: https://blog.csdn.net/m0_37302966/article/details/142525395

相关文章

  • PCL 3D特征描述子
    特征描述子FeatureDescriptor是每个特征点独特的身份认证同一空间点在不同视角的特征点具有高度相似的描述子不同特征点的描述子差异性尽量大通常描述子是一个具有固定长度的向量描述子可以分为以下几种类型:基于不变性的描述子、基于直方图的描述子、二进制描述子PC......
  • PCL 计算点云距离
    文章目录一、简介二、实现代码三、实现效果参考资料一、简介顾名思义,这个就是计算点云中每个点到另一个点云最近的距离,之后我们可以基于这些距离做一些预处理工作。思路其实很简单,通过对点云构建kdtree并采用并行的方式实现该计算过程。二、实现代码ColorR......
  • 11 - TCPClient实验
    在上一个章节的UDP通信测试中,尽管通信的实现过程相对简洁,但出现了通信数据丢包的问题。因此,本章节将基于之前建立的WIFI网络连接,构建一个基础的TCPClient连接机制。我们利用网络调试助手工具来发送数据,测试网络通信中接收到的数据能够准确无误地回传。本节课目标:在本次实验......
  • httpclient PoolingHttpClientConnectionManager 连接池使用举例
    1.1TIME_WAIT状态连接的原因和解决策略大量短连接大量短暂的连接会导致短时间内生成大量的TIME_WAIT状态连接。解决方案:尽量使用长连接,减少连接的创建和销毁次数。TCP时间等待池溢出如果服务器短时间内有大量的连接进入TIME_WAIT状态,可能会导致TCP时间等待池溢出。解决方案:可以......
  • 保持使用全局 HttpClient,但确保不同请求的 HttpRequestMessage 独立
    保持使用全局HttpClient,但确保不同请求的HttpRequestMessage独立这是推荐的最佳实践,因为HttpClient是设计为可重用的,你可以使用独立的HttpRequestMessage来确保每个请求有独立的请求头,而不影响其他请求。 privatestaticreadonlyHttpClientclient=newHtt......
  • HttpClient 和 HttpGet 都设置了,setConnectTimeout 和 setReadTimeout/setSocketTimeo
    在使用ApacheHttpClient时,如果你分别在HttpClient和HttpGet(或其他请求对象)上都设置了setConnectTimeout和setReadTimeout(也叫setSocketTimeout),那么最终生效的配置是HttpGet(或请求对象)的配置优先,即请求对象上的超时设置会覆盖全局HttpClient的设置。具体规则说明:H......
  • Open3D 基于法线的双边滤波
    目录一、概述1.1原理1.2实现步骤1.3应用场景二、代码实现2.1关键函数输入参数:输出参数:参数影响:2.2完整代码三、实现效果3.1原始点云3.2滤波后点云Open3D点云算法汇总及实战案例汇总的目录地址:Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客一、概......
  • TPAMI 2024 | 点云分割领域自适应的组合语义混合
    CompositionalSemanticMixforDomainAdaptationinPointCloudSegmentation点云分割领域自适应的组合语义混合CristianoSaltori,FabioGalasso,GiuseppeFiameni,NicuSebe,FabioPoiesi,ElisaRicci代码:https://github.com/saltoricristiano/cosmix-uda摘......
  • java学习之HttpClient忽略安全证书(SSLContext)
    1.我们在写https请求时候,经常会遇见安全证书(SSL)验证失败的情况,如下图。 上图异常就是因为SSL验证失败导致的,常规的做法是忽略证书认证。方法如下:第一步:需要重写认证的证书类 X509ExtendedTrustManager。第二步:创建SSLContext对象。第三步:将SSLContext对象设置到HttpClien......
  • PointNet++改进策略 :模块改进 | SWA| PVT,融入Transformer的点云与体素的模块同时提升
    目录介绍PVT原理PVT的核心思想和结构PVT模块结构体素分支点分支代码实现论文题目:PVT:Point-VoxelTransformerforPointCloudLearning发布期刊:InternationalJournalofIntelligentSystems通讯地址:杭州电子科技大学&伦敦大学学院代码地址:https://github.com/......