pcl--第六节 3D特征描述子

news2024/12/27 18:33:09

特征描述子 Feature Descriptor

  • 是每个特征点独特的身份认证
  • 同一空间点在不同视角的特征点具有高度相似的描述子
  • 不同特征点的描述子差异性尽量大
  • 通常描述子是一个具有固定长度的向量

描述子可以分为以下几种类型:基于不变性的描述子、基于直方图的描述子、二进制描述子

PCL主要实现了:

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

PFH点特征直方图描述子¶

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

我们可以通过点特征直方图(Point Feature Histograms, PFH)来采集全局的特征信息。

理论基础

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

img

在VR的应用中也分为3DoF和6DoF:

image-20200516201810352

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

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

以下是两个点的PFH直方图演示:

image-20200516205729207

默认PFH的实现,对每个特征都使用5个子区间进行分类,这里不包括距离d�。这样就组成了一个125个浮点数元素的特征向量(5353),保存在数据类型pcl::PFHSignature125中。

以下是根据3D点与法线的空间邻域估计单个点的三个角特征的PFH(点特征直方图)。

/** \brief Estimate the PFH (Point Feature Histograms) individual signatures of the three angular (f1, f2, f3)
* features for a given point based on its spatial neighborhood of 3D points with normals
* \param[in] cloud the dataset containing the XYZ Cartesian coordinates of the two points
* \param[in] normals the dataset containing the surface normals at each point in \a cloud
* \param[in] indices the k-neighborhood point indices in the dataset
* \param[in] nr_split the number of subdivisions for each angular feature interval
* \param[out] pfh_histogram the resultant (combinatorial) PFH histogram representing the feature at the query point
*/
void 
computePointPFHSignature (const pcl::PointCloud<PointInT> &cloud,
                          const pcl::PointCloud<PointNT> &normals, 
                          const std::vector<int> &indices, int nr_split,
                          Eigen::VectorXf &pfh_histogram);

参数说明:

  1. cloud:包含xyz坐标点信息的数据集

  2. normals:数据集中点的法向量信息

  3. indices:指定查询点,数据集中k邻域点的索引

  4. nr_split:每个角特征的区间数

  5. pfh_histogram(输出):结果PFH直方图,表示查询点处的特征

更多相关信息和数学推导,包括不同几何体表面点云的 PFH 特征分析,详见论文链接RusuDissertation

代码实现参见:https://pcl-tutorials.readthedocs.io/en/master/pfh_estimation.html#

pfh_estimation.cpp

//
// Created by ty on 20-5-28.
//

#include <pcl/point_types.h>
#include <pcl/features/pfh.h>

#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/cloud_viewer.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);
    pcl::io::loadPCDFile("./data/bunny.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);

    // Create the PFH estimation class, and pass the input dataset+normals to it ------计算PFH直方图
    pcl::PFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::PFHSignature125> pfh;
    pfh.setInputCloud(cloud);
    pfh.setInputNormals(normals);
    // alternatively, if cloud is of tpe PointNormal, do pfh.setInputNormals (cloud);

    // Create an empty kdtree representation, and pass it to the PFH estimation object.
    // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    //pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ> ()); -- older call for PCL 1.5-
    pfh.setSearchMethod(tree);

    // Output datasets
    pcl::PointCloud<pcl::PFHSignature125>::Ptr pfhs(new pcl::PointCloud<pcl::PFHSignature125>());

    // Use all neighbors in a sphere of radius 5cm
    // 使用一个半径为5厘米的球体,作为搜索邻域
    // IMPORTANT: the radius used here has to be larger than the radius used to estimate the surface normals!!!
    // 重点: 半径必须要比用于估算法向量的邻域半径要大
    pfh.setRadiusSearch(0.08);

    // Compute the features
    pfh.compute(*pfhs);

    unsigned long size = pfhs->points.size();
    for (int j = 0; j < size; ++j) {
        pcl::PFHSignature125 &signature125 = pfhs->points[j];
        float* h = signature125.histogram;

        printf("%d: %f,%f,%f \n", j, h[1], h[2], h[3]);
    }

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

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

FPFH快速点特征直方图描述子¶

image-20200516234137600

FPFH快点特征直方图的影响区域图。 每个查询点(红色)仅连接到其直接的k邻居(由灰色圆圈包围)。 每个直接邻居都连接到其自己的邻居,并将所得直方图与查询点的直方图一起加权以形成FPFH。 较粗的连接两次会被重复计数2次(比较重要的点对)。

FPFH与PFH的主要区别

  1. FPFH没有对全互连点的所有邻近点的计算参数进行统计,因此可能漏掉了一些重要的点对,而这些漏掉的对点可能对捕获查询点周围的几何特征有贡献;

  2. PFH特征模型是对查询点周围的一个精确的邻域半径内,而FPFH还包括半径r范围以外的额外点对(但不超过2r的范围);

  3. 因为采用权重计算的方式,所以FPFH结合SPFH值,重新捕获邻近重要点对的几何信息;
  4. 由于FPFH大大地降低了PFH的整体复杂性,因此FPFH经常使用在实时应用中;
  5. 通过分解三元组,简化了合成的直方图。也就是简单生成d分离特征直方图,对每个特征维度来单独绘制,并把它们连接在一起。

image-20200516235329781

默认pcl实现的的FPFH使用11个统计区间(对每个特征值都将其参数区间分割为11个),分别计算特征直方图,然后合并得到了一个33个元素的特征向量,保存在数据类型pcl::FPFHSignature33中。

代码实现参见:https://pcl-tutorials.readthedocs.io/en/master/fpfh_estimation.html#fpfh-estimation

利用OpenMP提高FPFH的计算速度

对于计算速度要求苛刻的用户,PCL提供了一个FPFH估计的另一实现,它使用多核/多线程规范,利用OpenMP开发模式来提高计算速度。这个类的名称是pcl::FPFHEstimationOMP,并且它的应用程序接口(API)100%兼容单线程pcl::FPFHEstimation,这使它适合作为一个替换元件。在8核系统中,OpenMP的实现可以在6-8倍更快的计算时间内完全同样单核系统上的计算。

VFH视点特征直方图描述子¶

源于FPFH描述子,为了使构造的特征保持缩放不变性的同时,还要区分不同的位姿,因而计算时,需要加入视点信息。VFH时点特征直方图包含两个部分:

  1. 视点方向的相关分量
  2. 包含扩展FPFH的描述表面形状的分量

NARF特征点描述子¶

NARF (Normal Aligned Radial Feature)法线对齐径向特征,是一种3D特征检测和描述的算法。参见:

《Point Feature Extraction on 3D Range ScansTaking into Account Object Boundaries》

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

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

相关文章

上万条童话故事儿童故事ACCESS\EXCEL数据库

虽然已经有《7千多儿童故事网ACCESS\EXCEL数据库》这种记录数的童话故事类数据&#xff0c;但是遇到了好采集的就总想采集下来&#xff0c;后续有时间或有需求可以再做合并等操作。 分类情况统计为&#xff1a; 儿童故事&#xff1a;儿童小故事&#xff08;1895&#xff09;、…

Cobra眼睛蛇-强大的Golang CLI框架,快速上手的脚手架搭建项目工具,详细安装和使用

Cobra眼睛蛇-强大的Golang CLI框架&#xff0c;快速上手的脚手架搭建项目工具&#xff0c;详细安装和使用。 阅读过k8s源码的同学&#xff0c;应该都知道k8s Scheduler、kubeadm、kubelet等核心组件的命令行交互全都是通过spf13写的Cobra库来实现。本文就来介绍下Cobra的相关概…

成都爱尔李晓峰医生解析“秋季干眼症”!该如何远离

秋高气爽?相较于夏天不然湿热难忍&#xff0c;气候逐渐干燥似乎“好过”了些。但干燥不见得都是好事&#xff0c;环境空气的干同时让人体呈现“燥”&#xff0c;如皮肤干燥、喉痒、口干、干咳、便秘等不适&#xff0c;就连眼睛也不能幸免。 由于眼部水分较其他季节蒸发快&…

时序预测 | MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测

时序预测 | MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测 目录 时序预测 | MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测&#…

STM32F407 串口使用DMA方式通信

DMA的原理&#xff0c;就是利用寄存器方式进行读写&#xff0c;这样的好处就是相对于中断触发&#xff08;往往一个字节字节的就中断一次&#xff09;&#xff0c;CPU中断次数大大降少&#xff0c;提高了效率&#xff0c;但也影响了实时性。总体来说&#xff0c;对于一般的应用…

系统安装(一)CentOS 7 本地安装

CentOS与Ubuntu并称为Linux最著名的两个发行版&#xff0c;但由于笔者主要从事深度学习图像算法工作&#xff0c;Ubuntu作为谷歌和多数依赖库的亲儿子占据着最高生态位。但最近接手的一个项目里&#xff0c;甲方指定需要在CentOS7上运行项目代码&#xff0c;笔者被迫小小cos了一…

VS Code时间轴插件:MarkWhen

文章目录 简介时间格式事件格式 简介 MarkWhen是一款文本转时间轴的工具&#xff0c;非常好用&#xff0c;也十分炫酷。可在VS Code中搜索插件MarkWhen&#xff0c;点击安装&#xff0c;然后新建一个.mw后缀的文件&#xff0c;就可以使用了&#xff0c;下面举一个简单的例子 …

嵌入式笔试面试刷题(day15)

文章目录 前言一、Linux中的主设备号和次设备号1.查看方法2.主设备号和次设备号的作用 二、软件IIC和硬件IIC的区别三、变量的声明和定义区别四、static在C和C中的区别五、串口总线空闲时候的电平状态总结 前言 本篇文章继续讲解嵌入式笔试面试刷题&#xff0c;希望大家坚持跟…

PyTorch深度学习实战(17)——多任务学习

PyTorch深度学习实战&#xff08;17&#xff09;——多任务学习 0. 前言1. 多任务学习1.1 多任务学习基本概念1.2 多任务学习优势 2. 模型与数据集分析2.1 模型分析2.2 数据集介绍 3. 实现年龄估计和性别分类小结系列链接 0. 前言 多任务学习( Multi-Task Learning, MTL )是一…

SpringCloud Alibaba 整合Sentinel的基本使用

文章目录 一、什么是Sentinel二、Sentinel 的主要特性1. 流量控制&#xff1a;2. 熔断降级&#xff1a;3. 实时监控&#xff1a;4. 规则配置&#xff1a;5. 集成方便&#xff1a; 三、Sentinel 分为哪几部分:1. 核心库&#xff08;Java 客户端&#xff09;2. 控制台&#xff08…

Matlab图像处理-区域描述

一旦一幅图像的目标区域被确定&#xff0c;我们往往用一套描述子来表示其特性。选择区域描述子的动机不单纯为了减少在区域中原始数据的数量&#xff0c;而且也应有利于区别带有不同特性的区域。因此&#xff0c;当目标区域有大小、旋转、平移等方面的变化时&#xff0c;针对这…

ThreeJS-3D教学一基础场景创建

Three.js 是一个开源的 JS 3D 图形库&#xff0c;用于创建和展示高性能、交互式的 3D 图形场景。它建立在 WebGL 技术之上&#xff0c;并提供了丰富的功能和工具&#xff0c;使开发者可以轻松地构建令人惊叹的 3D 可视化效果。 Three.js 提供了一套完整的工具和 API&#xff0…

【深度学习】实验13 使用Dropout抑制过拟合

文章目录 使用Dropout抑制过拟合1. 环境准备2. 导入数据集3. 对所有数据的预测3.1 数据集3.2 构建神经网络 3.3 训练模型3.4 分析模型 4. 对未见过数据的预测4.1 划分数据集4.2 构建神经网络4.3 训练模型4.4 分析模型 5. 使用Dropout抑制过拟合5.1 构建神经网络5.2 训练模型5.3…

基于Qt4的拉格朗日插值实现及使用

目录 1 拉格朗日插值算法 2 实现思路 3 子程序编写 1 框架搭建 2 加载节点值 3 加载插值点 4 位置查找 5 二点线性插值 3 子程序使用 1 拉格朗日插值算法 拉格朗日插值是一种常用的散点插值算法,是是以法国十八世纪数学家约瑟夫拉格朗日命名的一种多项式插值方法。是…

python爬虫——爬取豆瓣top250电影数据(适合初学者)

前言&#xff1a; 爬取豆瓣top250其实是初学者用于练习和熟悉爬虫技能知识的简单实战项目&#xff0c;通过这个项目&#xff0c;可以让小白对爬虫有一个初步认识&#xff0c;因此&#xff0c;如果你已经接触过爬虫有些时间了&#xff0c;可以跳过该项目&#xff0c;选择更有挑…

Linux Shell 实现一键部署podman

podman 介绍 使用 Podman 管理容器、Pod 和映像。从本地环境中无缝使用容器和 Kubernetes&#xff0c;Podman 提供与 Docker 非常相似的功能&#xff0c;它不需要在你的系统上运行任何守护进程&#xff0c;并且它也可以在没有 root 权限的情况下运行。 Podman 可以管理和运行…

JavaWeb后端开发登录操作 登录功能 通用模板/SpringBoot整合

登录功能的思路 前端会传入两个参数:用户名和密码 在用户表中查询用户名,并校对相应的密码(涉及查询操作) SQL语句 select * from emp where username jingyong and password 123456; 如果有则成功,没有则登录失败.不可能为多个,因为添加了unique唯一约束,最终只会有一条 …

如何将转换器应用于时序模型

一、说明 在机器学习的广阔环境中&#xff0c;变压器作为建筑奇迹屹立不倒&#xff0c;以其复杂的设计和捕获复杂关系的能力重塑了我们处理和理解大量数据的方式。 自 2017 年创建第一台变压器以来&#xff0c;变压器类型呈爆炸式增长&#xff0c;包括强大的生成 AI 模型&#…

Kubernetes部署dolphindcheduler-3.1.8问题记录

温故知新 ⁉️问题记录❓问题一&#xff1a;Unschedulable 0/3 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..❗解决方式&#xff1a;创建PV供应&#x1f…

ARM Soc内部总线

由于soc架构&#xff0c;把常用外设&#xff08;控制器&#xff09;集成到芯片内部&#xff0c;所以需要一种总线协调ARMcore与这些内部外设的通信&#xff0c;于是有了APB and AHB以及AXi这种片上总线。 同时要注意与常说的PC时代总线区分开&#xff1a; CPU总线&#xff08;…