PCL学习七:Features-特征

news2024/12/27 11:58:52

参考引用

  • Point Cloud Library
  • 黑马机器人 | PCL-3D点云

1. 特征描述与提取

  • 3D 点云特征描述与提取是点云信息处理中的最基础也是最关键的部分,点云识别、分割、重采样、配准和曲面重建等大部分算法,都十分依赖特征描述与提取的结果

  • 从尺度上来划分,一般分为局部特征描述全局特征描述。例如局部的法线等几何形状特征的描述,全局的拓扑特征描述,都属于 3D 点云特征描述与提取范畴。在 PCL 中,目前已有很多基本的特征描述子与提取算法

  • 理想情况下,在使用同一种度量规则情况下,相同或相似的表面上的点的特征值应该非常相似,不同表面上的点的特征描述子有明显的差异。通过以下几个条件变化仍能获取相同或相似的局部表面特征,则说明该特征表示方式比较优秀

    • 刚性变换(rigid transformations):即数据中的 3D 旋转和 3D 平移不应影响结果特征向量 F 的估计
    • 多种采样密度(varying sampling density):原则上,在一个局部表面或多或少采样密度的应具有相同的特征向量
    • 噪声(noise):在数据中存在轻微噪声的情况下,由特征点描述的特征向量必须相同或非常相近
  • 通常,PCL 功能使用近似的方法通过快速的 kd-tree 查询来计算查询点的最近邻居,查询方法主要有两种

    • k 搜索:确定查询点的 k 个(用户给定参数)邻居
    • 半径搜索:确定半径为 r 的球面内查询点的所有邻居
  • 3D 形状内容描述子(3D shape contexts)
    利用描述子建立曲面间的对应点在 3D 物体识别领域有广发的应用,采用一个向量描述曲面上指定点及邻域的形状特征,通过匹配向量的值来建立不同曲面点的对应关系,此相邻则则称为指定点的俄描述子,经典描述子的 3D 形状内容描述子结构简单,辨别力强且对噪声不敏感
  • 旋转图像(spin iamge)
    旋转图像最早是由 johnson 提出的特征描述子,主要用于 3D 场景中的曲面匹配和模型识别

2. 法向量估算示例

  • 查询点的相邻点可以用于估计局部特征表示,该局部特征表示捕获查询点周围的基础采样表面的几何形状。描述表面几何形状的一个重要问题是首先推断其在坐标系中的方向,即估算其法线。表面法线是表面的重要属性,在许多领域(例如计算机图形应用程序)中大量使用,以应用正确的光源来生成阴影和其他视觉效果
    // 为输入数据集中的所有点估计一组表面法线
    #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 ...
        
        // 创建法向量估算类,传递输入数据集
        pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
        ne.setInputCloud (cloud);
        
        // 创建一个空的kdtree,将值传递给法向量估算对象
        // 这个tree对象将会在ne内部根据输入的数据集进行填充(这里设置没有其他的search surface)
        pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
        ne.setSearchMethod (tree);
        
        // 定义输出数据集
        pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
        
        // 使用一个半径为3cm的球体中的所有邻居点
        ne.setRadiusSearch (0.03);
        
        // 计算特征
        ne.compute (*cloud_normals);
        
        // cloud_normals->points.size () 输出特征的点个数应当定于输入的点个数 cloud->points.size ()
    }
    
    // 从一个点云的子集中进行表面法线估算
    #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 ...
        
        // 准备一个indices索引集合,为了简单起见,我们直接使用点云的前10%的点
        std::vector<int> indices (std::floor (cloud->points.size () / 10));
        for (std::size_t i = 0; i < indices.size (); ++i) indices[i] = i;
        
        // 创建法向量估算类,设置输入点云
        pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
        ne.setInputCloud (cloud);
        
        // 设置indices索引
        boost::shared_ptr<std::vector<int> > indicesptr (new std::vector<int> (indices));
        ne.setIndices (indicesptr);
        
        // 创建一个空的kdtree,将值传递给法向量估算对象
        // 这个tree对象将会在ne内部根据输入的数据集进行填充(这里设置没有其他的search surface)
        pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
        ne.setSearchMethod (tree);
        
        // 定义输出数据集
        pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
        
        // 使用一个半径为3cm的球体中的所有邻居点
        ne.setRadiusSearch (0.03);
        
        // 计算特征
        ne.compute (*cloud_normals);
        
        // cloud_normals->points.size () 输出特征的点个数应当定于输入的点个数 cloud->points.size ()
    }
    
    // 为输入数据集中的所有点估算一组表面法线,但将使用另一个数据集(原始点云)估计其最近的邻居
    // 如前所述,一个很好的方式是降采样版本作为输入input cloud
    #include <pcl/point_types.h>
    #include <pcl/features/normal_3d.h>
    
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsampled (new pcl::PointCloud<pcl::PointXYZ>);
        
        ... read, pass in or create a point cloud ...
        
        ... create a downsampled version of it ...
        
        // 创建法向量估算类,将降采样后的数据作为输入点云
        pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
        ne.setInputCloud (cloud_downsampled);
        
        // 传入降采样之前的原始数据作为search surface
        ne.setSearchSurface (cloud);
        
        // 创建一个空的kdtree,将值传递给法向量估算对象
        // 这个tree对象将会在ne内部根据输入的数据集进行填充(这里设置没有其他的search surface)
        pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
        ne.setSearchMethod (tree);
        
        // 定义输出数据集
        pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
        
        // 使用一个半径为3cm的球体中的所有邻居点
        ne.setRadiusSearch (0.03);
        
        // 计算特征
        ne.compute (*cloud_normals);
        
        // cloud_normals->points.size()输出特征的点个数应当定于输入的点个数cloud->points.size()
    }
    

3. 点云表面法线估算

3.1 引言

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

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

    • 使用表面网格化技术从获取的点云数据集中获取基础表面,然后从网格中计算表面法线
    • 使用近似值直接从点云数据集中推断表面法线(下文将使用这个方法)

3.2 理论基础

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

  • 法线计算

    • 将平面表示为一个点 c c c 和一个法向量 n ⃗ \vec{n} n ,则从一个点 p i ∈ P k p_{i}\in P^{k} piPk 到平面的距离可以定义为: x x x n n n 的值是通过最小二乘法以使 d i = 0 d_i=0 di=0 得到的,则中心点
      c = p ˉ = 1 k ⋅ ∑ i = 1 k p i c=\bar{p}=\frac{1}{k}\cdot\sum_{i=1}^{k}p_i c=pˉ=k1i=1kpi

    • 假如有一堆点 p i p_i pi ,查找一个超平面,使通过点 c c c 的一个法向量 n ⃗ \vec{n} n 满足
      min ⁡ c , n ⃗ , ∥ n ⃗ ∥ = 1 ∑ i = 1 k ( ( p i − c ) T n ⃗ ) 2 \min\limits_{\mathbf{c},\vec{\mathbf{n}},\|\vec{\mathbf{n}}\|=1}\sum\limits_{i=1}^k\left(\left(\mathbf{p}_i-\mathbf{c}\right)^T\vec{\mathbf{n}}\right)^2 c,n ,n =1mini=1k((pic)Tn )2

    • 周围点的向量 ( p i − c ) T (p_i-c)^T (pic)T 在法向量 n ⃗ \vec{n} n 上的投影之和最小(两个向量的乘积即是一个向量在另一个向量上的投影)
      在这里插入图片描述

    • c c c 作为 P k P^k Pk 的中心,法向 n ⃗ \vec{n} n 的值是通过分析点集合 P k P^k Pk 协方差矩阵 C ∈ R 3 × 3 \mathcal{C}\in R^{3\times3} CR3×3 的特征值和特征向量得到的(PCA—主成分分析),对于指定区域的点集合 P k P^k Pk,其协方差矩阵定义如下
      C = 1 k ∑ i = 1 k ( p i − p ˉ ) ⋅ ( p i − p ˉ ) T , C ⋅ v ⃗ j = λ j ⋅ v ⃗ j , j ∈ { 0 , 1 , 2 } \mathcal{C}=\frac{1}{k}\sum_{i=1}^k\left(p_i-\bar{p}\right)\cdot\left(p_i-\bar{p}\right)^T,\mathcal{C}\cdot\vec{v}_j=\lambda_j\cdot\vec{v}_j,j\in\{0,1,2\} C=k1i=1k(pipˉ)(pipˉ)T,Cv j=λjv j,j{0,1,2}

    • C \mathcal{C} C 是一个对称的半正定矩阵, k k k 是点数目, p ˉ \bar{p} pˉ 是周围点的质心, λ j \lambda_j λj 是协方差矩阵的第 j j j 个特征值。 v ⃗ j \vec{v}_j v j是协方差矩阵的第 j j j 个特征向量。通过以下代码可以计算质心和协方差矩阵

    // 定义一小块表面区域的协方差矩阵
    Eigen::Matrix3f covariance_matrix;
    // 定义一小块表面区域的质心坐标
    Eigen::Vector4f xyz_centroid;
    // 计算质心坐标
    pcl::compute3DCentroid(*cloud, xyz_centroid);
    // 计算 3x3 的协方差矩阵
    pcl::computeCovarianceMatrix(*cloud, xyz_centroid, covariance_matrix);
    
    • 表面曲率 Surface Curvature 通过协方差矩阵的特征值进行估算得到
      σ p = λ 0 λ 0 + λ 1 + λ 2 \sigma_p=\frac{\lambda_0}{\lambda_0+\lambda_1+\lambda_2} σp=λ0+λ1+λ2λ0
      • 这里 λ 0 = m i n ( λ j ) \lambda_0=min(\lambda_j) λ0=min(λj),即三个特征值中的最小值
  • 法线方向问题

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

    • 但是,如果有了视点 V p V_p Vp,则此问题就很好解决了,让所有法 n ⃗ \vec{n} n 选取其朝向视点的那个方向即可,则可以观察到将所有法线重新定向之后的效果和其对应的扩展高斯图(EGI)
      n ⃗ i ⋅ ( V p − p i ) > 0 \vec{n}_i\cdot\left(V_p-p_i\right)>0 n i(Vppi)>0
      在这里插入图片描述

  • 选择合适的比例

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

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

    • 默认视点坐标为 (0,0,0),可以使用以下代码修改

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

3.3 代码实现

#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() {
    // 导入点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("../data/table_scene_mug_stereo_textured.pcd", *cloud);

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

    // 创建一个用于法线估计的对象并计算法线
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
    // normalEstimation.setIndices()
    normalEstimation.setInputCloud(cloud);
    normalEstimation.setRadiusSearch(0.03); // 对每个点,使用半径为 3cm 的所有邻居
    // 使用 kd-tree 方法来寻找最近邻
    pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
    normalEstimation.setSearchMethod(kdtree);
    normalEstimation.compute(*normals);    // 计算法线

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

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

4. 积分图估算点云法线

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

  • 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() {
        // 导入点云
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
        pcl::io::loadPCDFile("../data/table_scene_mug_stereo_textured.pcd", *cloud);
    
        // 法线
        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);
    
        // 法线可视化操作
        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;
    }
    
  • 配置文件 CMakeLists.txt

    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    
    project(integral_image_normal)
    
    find_package(PCL 1.2 REQUIRED)
    
    include_directories(${PCL_INCLUDE_DIRS})
    link_directories(${PCL_LIBRARY_DIRS})
    add_definitions(${PCL_DEFINITIONS})
    
    add_executable(integral_image_normal integral_image_normal.cpp)
    target_link_libraries(integral_image_normal ${PCL_LIBRARIES})
    
  • 编译并执行

    $ mkdir build
    $ cd build
    $ cmake ..
    $ make
    
    $ ./integral_image_normal
    

在这里插入图片描述

5. 3D 特征描述子

5.1 定义与分类

  • 特征描述子(Feature Descriptor)

    • 是每个特征点独特的身份认证
    • 同一空间点在不同视角的特征点具有高度相似的描述子
    • 不同特征点的描述子差异性比较大
    • 通常描述子是一个具有固定长度的向量
  • 描述子可以分为以下几种类型

    • 基于不变性的描述子、基于直方图的描述子、二进制描述子
  • PCL 主要实现了

    • NARF 特征点描述子、PFH(FPFH)点特征直方图描述子、RoPs 特征、VFH 视点特征直方图描述子、GASD 全局对齐的空间分布描述子、基于惯性矩和偏心率的描述子

5.2 PFH(Point Feature Histograms)点特征直方图描述子

  • 表面法线和曲率估计是某个点周围的几何特征的基本表示方法。虽然计算起来比较容易,但是能够提供的信息并不多。因为他们只是用很少的几个参数值近似地表示一个点的 k 邻域几何特征。大部分场景下都会有很多相同或相似的特征值,故而只采用点特征就会少了很多全局的特征信息

    • 可以通过点特征直方图(Point Feature Histograms, PFH)来采集全局的特征信息
  • 理论基础

    • PFH 通过参数化查询点与邻域点之间的空间差异信息,形成一个多维直方图对点的 k 邻域的几何特征进行描述。直方图所在的高维超空间为特征的表示提供了一个可度量的信息空间,使点云对应的 6DoF 姿态来说具有不变性,并且在不同的采样密度或邻域噪音等级下具有鲁棒性
      在这里插入图片描述

    • 在 VR 的应用中也分为 3DoF 和 6DoF
      在这里插入图片描述

    • PFH 表示法是基于点与其 k 邻域之间的关系以及他们所构成的法线而建立的。他考虑了法线之间的关系,并较好的获取了样品表面的变化情况,进而描述了样本的几何特征。下图表示的是查询点 P q P_q Pq 的 PFH 计算影响区域。 P q P_q Pq 为中间的红色点,虚线圆内是半径为 r 的所有邻域点,他们相互连接在一个网络中,PFH 描述子是通过计算邻域内所有两点之间的关系而得到的直方图
      在这里插入图片描述

    • 为了计算两个点 P s P_s Ps P t P_t Pt 以及他们对应法 n ⃗ s \vec{n}_s n s n ⃗ t \vec{n}_t n t 之间的关系,在其中一个点上定义一个固定的局部坐标系
      在这里插入图片描述

    • 坐标系 u v w uvw uvw 的定义算法
      { u = n s v = u × ( P t − P s ) ∥ P t − P s ∥ 2 w = u × v \left\{\begin{array}{l}u=n_s\\ v=u\times\frac{(P_t-P_s)}{\|P_t-P_s\|_2}\\ w=u\times v\end{array}\right. u=nsv=u×PtPs2(PtPs)w=u×v

    • 使用上图中的 u v w uvw uvw 坐标系,我们可以用一组角度来表示法线 n ⃗ s \vec{n}_s n s n ⃗ t \vec{n}_t n t 之间的关系(偏差)
      θ = arctan ⁡ ( v ⋅ n t , u ⋅ n t ) α = v ⋅ n t ϕ = u ⋅ ( P t − P s ) d \begin{aligned}\theta&=\arctan\left(\text{v}\cdot\boldsymbol{n}_t,\text{u}\cdot\boldsymbol{n}_t\right)\\ \alpha&=\text{v}\cdot\boldsymbol{n}_t\\ \phi&=\text{u}\cdot\frac{\left(P_t-P_s\right)}{d}\end{aligned} θαϕ=arctan(vnt,unt)=vnt=ud(PtPs)

      • 这里 d d d 表示 P t P_t Pt P s P_s Ps 之间的欧氏距离,即 d = ∥ P t − P s ∥ 2 d=\|P_t-P_s\|_2 d=PtPs2,通过计算 k 邻域内的每一对点的 < α , ϕ , θ , d > <\alpha,\phi,\theta,d> <α,ϕ,θ,d> 四个值,就可以把之前两个点和其法向量相关的 12 个参数(两个点的 x y z xyz xyz 坐标和法向量)减少到 4 个。为每个点估算 PFH 四元组,可以使用以下代码
      #include <pcl/features/pfh_tools.h>
      /** \brief 计算点对的PFH特征的4个特征元素值,包含3个角度值和一个两点间的距离值
          * \param[in] p1 the first XYZ point 第一个点的xyz坐标
          * \param[in] n1 the first surface normal 第一个点所在区域的表面法向量
          * \param[in] p2 the second XYZ point 第二个点的xyz坐标
          * \param[in] n2 the second surface normal 第二个点所在区域的表面法向量
        * \param[out] f1 第一个角度特征值 Θ (angle between the projection of nq_idx and u)
        * \param[out] f2 第二个角度特征值 α (angle between nq_idx and v)
        * \param[out] f3 第三个角度特征值 Φ (angle between np_idx and |p_idx - q_idx|)
        * \param[out] f4 两点间的欧式距离 d (p_idx - q_idx)
        */
      computePairFeatures (const Eigen::Vector4f &p1, const Eigen::Vector4f &n1, 
                           const Eigen::Vector4f &p2, const Eigen::Vector4f &n2, 
                           float &f1, float &f2, float &f3, float &f4);
      
  • 直方图的统计方式

    • 1、将 < α , ϕ , θ , d > <\alpha,\phi,\theta,d> <α,ϕ,θ,d> 中的每个特征值范围划分为 b 个子区间(默认为 5,这个数值可以自行计算并设置),则 4 个特征共有 b 4 b^4 b4 个区间
    • 2、统计对应特征值落在每个子区间的点的数目,由于 < α , ϕ , θ > <\alpha,\phi,\theta> <α,ϕ,θ> 三个特征都是法线之间的角度信息,则它们的值很可能会归为同一个空间
    • 3、计算每一个点对的特征值,直方图中对应于该点对四个特征值区间的统计个数 +1

    注意,在一些情况下,第四个特征 d 通常跟设备捕获 2.5D 深度数据是相关的,邻近点的距离 d 是从视点开始递增的,在不同视角下,这些值的变化意义不大,所以在扫描局部点密度影响特征时,省略距离 d 效果会更好

    • 以下是两个点的PFH直方图演示
      在这里插入图片描述

    • 默认 PFH 的实现,对每个特征都使用 5 个子区间进行分类,这里不包括距离 d。这样就组成了一个 125 个浮点数元素的特征向量( 5 3 5^3 53),保存在数据类型 pcl::PFHSignature125 中。以下是根据 3D 点与法线的空间邻域估计单个点的三个角特征的 PFH(点特征直方图)

    /*
        * features for a given point based on its spatial neighborhood of 3D points with normals
        * \param[in] cloud 包含xyz坐标点信息的数据集
        * \param[in] normals 数据集中点的法向量信息
        * \param[in] indices 指定查询点,数据集中 k 邻域点的索引
        * \param[in] nr_split 每个角特征的区间数
        * \param[out] pfh_histogram 结果 PFH 直方图,表示查询点处的特征
    */
    void 
    computePointPFHSignature (const pcl::PointCloud<PointInT> &cloud,
                              const pcl::PointCloud<PointNT> &normals, 
                              const std::vector<int> &indices, int nr_split,
                              Eigen::VectorXf &pfh_histogram);
    

5.3 FPFH(Fast Point Feature Histograms)快速点特征直方图描述子

  • 如果点云 P 中有 n 个点,则其点特征直方图 PFH 的理论计算复杂度 O ( n k 2 ) O(nk^2) O(nk2),其中 k 是点云 P 中每个点 p 计算特征向量时要考虑的邻域数量。对于实时应用或近实时应用,密集点云的点特征直方图 PFH 的计算,是一个主要的性能瓶颈,故而可以将之进行简化,称为快速点特征直方图 FPFH(Fast Point Feature Histograms)。这个 FPFH 将计算复杂度降到了 O ( n k ) O(nk) O(nk),但是仍然保留了 PFH 大部分的识别特性

  • FPFH 计算过程

    • 1、为查询点求得它和其 k 邻域内每个点之间的三个特征元素值,然后统计成一个 SimplePFH
    • 2、分别对 k 邻域中的每个点确定 k 邻域,按第一步分别形成自己的 SPFH
    • 3、对邻域中的各个SPFH进行加权统计,得到最终的 FPFH 公式如下
      F P F H ( p q ) = S P F H ( p q ) + 1 k ∑ i = 1 k 1 ω k ⋅ S P F H ( p k ) \mathrm{FPFH}(\boldsymbol{p}_q)=\mathrm{SPFH}(\boldsymbol{p}_q)+\frac{1}{k}\sum_{i=1}^k\frac{1}{\omega_k}\cdot\mathrm{SPFH}(\boldsymbol{p}_k) FPFH(pq)=SPFH(pq)+k1i=1kωk1SPFH(pk)
      • 权重 ω k ω_k ωk 表示查询点 P q P_q Pq 和其临近点 P k P_k Pk 之间的距离
  • 下图为 FPFH 快速点特征直方图的影响区域图

    • 每个查询点(红色)仅连接到其直接的 k 邻居(由灰色圆圈包围)
    • 每个直接邻居都连接到其自己的邻居,并将所得直方图与查询点的直方图一起加权以形成 FPFH
    • 较粗的连接两次会被重复计数 2 次(比较重要的点对)
      在这里插入图片描述
  • FPFH 与 PFH 的主要区别

    • 1、FPFH 没有对全互连点的所有邻近点的计算参数进行统计,因此可能漏掉了一些重要的点对,而这些漏掉的对点可能对捕获查询点周围的几何特征有贡献
    • 2、PFH 特征模型是对查询点周围的一个精确的邻域半径内,而 FPFH 还包括半径 r 范围以外的额外点对(但不超过 2r 的范围)
    • 3、因为采用权重计算的方式,所以 FPFH 结合 SPFH 值,重新捕获邻近重要点对的几何信息
    • 4、由于 FPFH 大大地降低了 PFH 的整体复杂性,因此 FPFH 经常使用在实时应用中
    • 5、通过分解三元组,简化了合成的直方图。也就是简单生成 d 分离特征直方图,对每个特征维度来单独绘制,并把它们连接在一起
      在这里插入图片描述
  • 默认 PCL 实现的的 FPFH 使用 11 个统计区间(对每个特征值都将其参数区间分割为 11 个),分别计算特征直方图,然后合并得到了一个 33 个元素的特征向量,保存在数据类型 pcl::FPFHSignature33 中

5.4 VFH(Viewpoint Feature Histogram)视点特征直方图描述子

  • 视点特征直方图VFH概念及使用
  • 源于 FPFH 描述子,为了使构造的特征保持缩放不变性的同时,还要区分不同的位姿,因而计算时,需要加入视点信息。VFH 视点特征直方图包含两个部分
    • 视点方向的相关分量
    • 包含扩展 FPFH 的描述表面形状的分量

5.5 NARF(Normal Aligned Radial Feature)法线对齐径向特征描述子

  • 3D点云——NARF特征

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/499799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MYSQL01高级_Linux版安装、各级别字符集、字符集与比较规则、SQL大小写规范

文章目录 ①. MySQL - linux版安装②. 字符集的相关操作③. 各级别的字符集④. 字符集与比较规则(了解)⑤. SQL大小写规范⑥. sql_mode的合理设置 ①. MySQL - linux版安装 ①. 进入mysql官网,找到安装文件 ②. 将抽取出来的文件放在linux下的opt下 MySQL Community Serv…

本周大新闻|15000nit亮度Micro OLED面世;印度市场再推行VR盒子

本周XR大新闻&#xff0c;AR方面&#xff0c;eMagin公布1.5万nit亮度的新款dPd Micro OLED&#xff1b;脑机技术AR眼镜Cognixion ONE获FDA认证&#xff1b;歌尔发布智能交互手环参考设计Link&#xff1b;Meta引入更多AR广告。 VR方面&#xff0c;23年Quest Gaming Showcase定于…

3D旋转 相册

效果展示 代码逻辑 <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta name"Keywords" content""><meta name"Description" content""><title>3D旋…

Vue3(Vite) 通过 prism.js 实现代码高亮并实现Mac风格

prismjs漂亮的代码语法高亮插件 极致易用&#xff1a;引用 prism.css 和 prism.js&#xff0c;使用合适的 HTML5 标签&#xff08;code.language-xxxx&#xff09;&#xff0c;搞定&#xff01;天生伶俐&#xff1a;语言的 CSS 类是可继承的&#xff0c;所以你只需定义一次就能…

自动控制原理笔记-频率响应法-控制系统的频域稳定判据

目录 一、Nyquist稳定判据 1&#xff09;开环传递函数中没有积分环节&#xff08;不含s0的极点&#xff09; 2&#xff09;开环传递函数中含有积分环节&#xff08;含s0的开环极点&#xff09; 二、Bode 稳定判据 稳定的定义&#xff1a; 任何系统在扰动的作用下都会偏离原平衡…

炫技亮点 任务编排使用CompletableFuture优化业务流程

文章目录 背景CompletableFuture简介使用场景如何编排任务步骤场景一 多个任务串行执行场景二 多个步骤并行执行场景三 一个串行步骤后两个并行步骤场景四 一个步骤依赖两个并行步骤场景五 一个步骤依赖多个并行步骤同时完成场景六 一个任务依赖多个任务的任意一个完成结果 其他…

STL--stack queue deque

stack 一、stack介绍 stack是一种容器适配器&#xff0c;专门设计用于后进先出&#xff0c;其中元素仅从容器的一端插入和提取 二、stack接口 函数名称功能说明empty判断容器是否为空size返回容器容量大小top返回栈顶数据push从栈顶插入元素pop删除栈顶元素 三、stack模拟实…

【NLP开发】Python实现聊天机器人(若干在线聊天机器人)

文章目录 1、简介2、代码测试2.1 open.drea.cc2.2 api.ruyi.ai2.3 route.showapi.com2.4 api.binstd.com2.5 api.jisuapi.com2.6 api.fanyi.baidu.com2.7 aiml2.8 api.tianapi.com2.9 nlp.xiaoi.com2.10 api.qingyunke.com2.11 api.ownthink.com 结语 1、简介 AI 聊天机器人使…

Chrome远程调试

最近接触到Chrome远程调试相关内容&#xff0c;记录一下。 场景&#xff1a;使用Chrome远程调试Chromium。当能够控制目标主机执行命令之后&#xff0c;可以在该主机上建立全局代理&#xff0c;然后在自己这一边开启浏览器监听&#xff0c;接着在目标机器上执行 chrome.exe --…

使用CSS伪元素制作动感超酷的hover动画

css 有很多神奇的效果都是使用 CSS 伪元素利用视觉差来制作的&#xff0c;以前没怎么深入的研究过 css&#xff0c;这次复习 css 的知识点才恍然大悟&#xff0c;原来 css 这么 cool。 先上效果&#xff1a; 动画实现原理 这个组动画的实现原理很简单&#xff0c;前边是一个…

ptrace

前言 gdb 的核心技术就是使用 ptrace 系统调用。 ptrace NAMEptrace - process traceSYNOPSIS#include <sys/ptrace.h>long ptrace(enum __ptrace_request request, pid_t pid,void *addr, void *data);DESCRIPTIONThe ptrace() system call provides a means by w…

开关电源学习总结

本篇文章主要通过理论来大体的讲一下开关电源的设计的思考过程&#xff0c;希望对大家可以有所帮助。本人小白&#xff0c;如有质疑&#xff0c;可以评论区指出。 一、开关电源指标 1.输入电压与输入功率 在设计开关电源时&#xff0c;需要根据需求来设计输入电压和输入功率…

12 KVM虚拟机配置-配置虚拟设备(网络设备)

文章目录 12 KVM虚拟机配置-配置虚拟设备(网络设备)12.1 概述12.2 元素介绍12.3 配置示例 12 KVM虚拟机配置-配置虚拟设备(网络设备) 12.1 概述 XML配置文件可以配置虚拟网络设备&#xff0c;包括ethernet模式、bridge模式、vhostuser模式等&#xff0c;本节介绍虚拟网卡设备…

理解生成式AI

文章目录 1、专业术语2、生成式AI3、ChatGPT1. 理解LLMRNN循环神经网络Seq2Seq模型ChatGPT与Bert区别 4、模型的生成和部署 1、专业术语 LLM&#xff1a;大型语言模型 GAI&#xff1a;通用人工智能 NLP&#xff1a;自然语言处理 CNN&#xff1a;卷积神经网络 RNN&#xff…

Spark的安装和配置

Spark的安装和配置 推荐按照我的博客下载hadoop&#xff0c;spark&#xff0c;pyspark以及scala这样版本搭配更好。 如果觉得自己不会版本搭配可私聊博主。 先安装hadoop再安装spark scala的安装和配置&#xff1a;https://blog.csdn.net/weixin_41957626/article/details/1305…

集群session的共享问题

基于redis实现共享session登录 1.集群session共享的问题 session共享问题&#xff1a;多台Tomcat并不共享session存储空间&#xff0c;当请求切换到不同tomcat服务时导致数据丢失问题 替代方案应该满足&#xff1a; 数据共享 内存存储 key、value结构 2.基于redis实现ses…

QoS实验配置-基于类部署

目录 对路由进行优先级标记 配置端口信任DSCP优先级 配置流量监管 配置拥塞管理 配置拥塞避免 配置流量整形 出接口下应用队列模板 对配置进行检验 QoS基于类的方式实现管理&#xff08;通过调度0~7队列进行实现&#xff0c;一般6、7协议是预留给路由协议的&#xff0c…

macos和windows区别 macos怎么运行windows程序

在我们使用电脑时&#xff0c;重要的是电脑内应用&#xff0c;而系统不过是运行软件的“容器”。日常生活中&#xff0c;我们常见的操作系统是macos和windows&#xff0c;那么macos和windows区别在哪&#xff1f;这两款操作系统的区别很大。macos怎么运行windows程序&#xff1…

从I帧到B帧,H.264编码技术为您构建画面与效果完美结合的视觉盛宴

H264之帧编码 H.264&#xff0c;也称为 MPEG-4 AVC (Advanced Video Coding)&#xff0c;是一种高效的视频编码标准&#xff0c;用于压缩和存储视频。H.264 利用了预测编码和变换编码等先进的技术&#xff0c;其编码流程与普通视频编码类似&#xff0c;主要包括帧类型判定、运…

2017年下半年软件设计师下午试题

试题四 阅读下列说明和C代码&#xff0c;回答问题1至问题 2&#xff0c;将解答写在答题纸的对应栏内。 【说明】 一个无向连通图G点上的哈密尔顿&#xff08;Hamiltion&#xff09;回路是指从图G上的某个顶点出发&#xff0c;经过图上所有其他顶点一次且仅一次&#xff0c;最后…