一、RoPs(旋转投影统计)特征原理介绍
在文章中,我们继续学习如何使用pcl:: ropsestimate类来提取点的特征。在这类中实现的特征提取方法是由Yulan Guo, Ferdous Sohel, Mohammed Bennamoun, Min Lu和Jianwei wane在他们的文章 “Rotational Projection Statistics for 3D Local Surface Description and Object Recognition”中提出的。
在噪声、网格分辨率变化、遮挡和杂波存在的情况下识别三维物体是一项非常具有挑战性的任务。Yulan Guo等人提出了一种新的旋转投影统计方法(RoPS)。它主要包括三个模块:局部参考框架(LRF)定义、RoPS特征描述和三维目标识别。这种方法通过计算局部表面上所有点的散射矩阵来定义LRF。RoPS特征描述符是通过将一个特征点的邻点旋转投影到二维平面上,并计算投影点分布的一组统计量(包括低阶中心矩和熵)来获得的。利用所提出的LRF和RoPS描述符,作者提出了一种分层的三维物体识别算法。提出的LRF、RoPS描述符和目标识别算法的性能在许多流行的和公开的数据集上进行了严格的测试并表现出了较好性能。与现有技术相比,我们提出的技术表现出更好的性能。在Bologna、UWA、Queen和Ca Foscari Venezia数据集上,基于RoPS算法的识别率分别为100、98.9、95.4和96.0。
【PS:RoPs是基于局部特征的,相较于基于深度学习Pointnet++等全局特征的方法,在点云存在噪声或网格分辨率变化较大的条件写,RoPs更为鲁棒】
算法思想:
首先,对于给定的兴趣点,裁剪局部曲面。局部表面由在给定半径内的点和三角形组成。对于给定的局部表面,计算了局部参考坐标系。LRF()仅仅是向量的三重集合,关于如何计算这些向量的全面信息可以在[本文]中找到。重要的是,使用这些向量,我们可以做到点云旋转的不变性。为此,简单地平移局部表面的点,使感兴趣的点成为原点,然后旋转局部表面,使LRF向量与Ox、Oy和Oz轴对齐。
完成以上操作之后,开始特征提取。对于每个轴Ox、Oy和Oz,执行以下步骤,我们将这些轴称为当前轴。
1.局部表面绕当前轴旋转一个给定的角度。
2.将旋转局部曲面上的点投影到XY、XZ和YZ三个平面上。
3.对于构建的每个投影分布矩阵,这个矩阵只是显示有多少点落在每个bin上。bin的数量表示矩阵维数,是算法的参数,支持半径参数内曲面上点云投影。
4.计算每个分布矩阵中心矩:M11, M12, M21, M22, E,其中E为Shannon熵。
5.然后将计算出的值连接起来形成子特征(每个轴对应一个子特征)。
多次迭代以上步骤。迭代的次数取决于给定的旋转次数。不同轴的子特性被连接起来形成最终的RoPS描述符。
二、RoPs(旋转投影统计)特征示例代码分析
在示例程序中,我们将使用Queen数据集中的模型。当然可以选择任何其他点云,但为了使代码工作,将需要使用三角化算法来获得多边形。你可以在这里找到建议的模型:
Github
点云模型: RoPs_cloud.pcd
点云索引:rops_indices.txt
三角化模型:RoPs_triangles.txt
点云模型网址:https://github.com/PointCloudLibrary/pcl/tree/master/test
接下来需要做的是在编辑器中创建一个文件rops_feature.cpp,并在其中复制以下代码。我这里测试使用的是VS2017+PCL1.8.1。
#include <pcl/features/rops_estimation.h>
#include <pcl/io/pcd_io.h>
int main (int argc, char** argv)
{
if (argc != 4)
return (-1);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ> ());
if (pcl::io::loadPCDFile (argv[1], *cloud) == -1)
return (-1);
pcl::PointIndicesPtr indices (new pcl::PointIndices);
std::ifstream indices_file;
indices_file.open (argv[2], std::ifstream::in);
for (std::string line; std::getline (indices_file, line);)
{
std::istringstream in (line);
unsigned int index = 0;
in >> index;
indices->indices.push_back (index - 1);
}
indices_file.close ();
std::vector <pcl::Vertices> triangles;
std::ifstream triangles_file;
triangles_file.open (argv[3], std::ifstream::in);
for (std::string line; std::getline (triangles_file, line);)
{
pcl::Vertices triangle;
std::istringstream in (line);
unsigned int vertex = 0;
in >> vertex;
triangle.vertices.push_back (vertex - 1);
in >> vertex;
triangle.vertices.push_back (vertex - 1);
in >> vertex;
triangle.vertices.push_back (vertex - 1);
triangles.push_back (triangle);
}
float support_radius = 0.0285f;
unsigned int number_of_partition_bins = 5;
unsigned int number_of_rotations = 3;
pcl::search::KdTree<pcl::PointXYZ>::Ptr search_method (new pcl::search::KdTree<pcl::PointXYZ>);
search_method->setInputCloud (cloud);
pcl::ROPSEstimation <pcl::PointXYZ, pcl::Histogram <135> > feature_estimator;
feature_estimator.setSearchMethod (search_method);
feature_estimator.setSearchSurface (cloud);
feature_estimator.setInputCloud (cloud);
feature_estimator.setIndices (indices);
feature_estimator.setTriangles (triangles);
feature_estimator.setRadiusSearch (support_radius);
feature_estimator.setNumberOfPartitionBins (number_of_partition_bins);
feature_estimator.setNumberOfRotations (number_of_rotations);
feature_estimator.setSupportRadius (support_radius);
pcl::PointCloud<pcl::Histogram <135> >::Ptr histograms (new pcl::PointCloud <pcl::Histogram <135> > ());
feature_estimator.compute (*histograms);
return (0);
}
我们逐段来分析以上代码做了什么,(前一部分关于点云如何读取的部分不再赘述)。
pcl::PointIndicesPtr indices (new pcl::PointIndices);
std::ifstream indices_file;
indices_file.open (argv[2], std::ifstream::in);
for (std::string line; std::getline (indices_file, line);)
{
std::istringstream in (line);
unsigned int index = 0;
in >> index;
indices->indices.push_back (index - 1);
}
indices_file.close ();
这一部分代码是加载了点云中要计算RoPS特征的点的索引。如果想为每个单独点计算特征,可以注释掉它。
std::vector <pcl::Vertices> triangles;
std::ifstream triangles_file;
triangles_file.open (argv[3], std::ifstream::in);
for (std::string line; std::getline (triangles_file, line);)
{
pcl::Vertices triangle;
std::istringstream in (line);
unsigned int vertex = 0;
in >> vertex;
triangle.vertices.push_back (vertex - 1);
in >> vertex;
triangle.vertices.push_back (vertex - 1);
in >> vertex;
triangle.vertices.push_back (vertex - 1);
triangles.push_back (triangle);
}
以上代码是载入三角化模型的功能。如果你只有点云而没有三角化模型文件,这一步可以用三角剖分的代码来替换它们。如果是无序点云,参考无序点云的快速三角剖分参考超链接。
float support_radius = 0.0285f;
unsigned int number_of_partition_bins = 5;
unsigned int number_of_rotations = 3;
以上代码定义了重要的算法参数:支持局部表面特征计算半径、用于形成分布矩阵的划分bins的数量和旋转的数量。最后一个参数影响描述符的长度。
pcl::search::KdTree<pcl::PointXYZ>::Ptr search_method (new pcl::search::KdTree<pcl::PointXYZ>);
search_method->setInputCloud (cloud);
设置该算法的点云搜索方法为kdtree。
pcl::ROPSEstimation <pcl::PointXYZ, pcl::Histogram <135> > feature_estimator;
feature_estimator.setSearchMethod (search_method);
feature_estimator.setSearchSurface (cloud);
feature_estimator.setInputCloud (cloud);
feature_estimator.setIndices (indices);
feature_estimator.setTriangles (triangles);
feature_estimator.setRadiusSearch (support_radius);
feature_estimator.setNumberOfPartitionBins (number_of_partition_bins);
feature_estimator.setNumberOfRotations (number_of_rotations);
feature_estimator.setSupportRadius (support_radius);
这里是pcl:: ropsestimate类的实例化代码。将所有参数输入到实例化对象当中。
pcl::PointCloud<pcl::Histogram <135> >::Ptr histograms (new pcl::PointCloud <pcl::Histogram <135> > ());
feature_estimator.compute (*histograms);
然后使用以上代码启动计算过程。
后续可根据需要输出直方图,与之前的点特征直方图的输出方式类似。
【博主简介】
斯坦福的兔子,男,天津大学机械工程工学硕士。毕业至今从事光学三维成像及点云处理相关工作。因工作中使用的三维处理库为公司内部库,不具有普遍适用性,遂自学开源PCL库及其相关数学知识以备使用。谨此将自学过程与君共享。
博主才疏学浅,尚不具有指导能力,如有问题还请各位在评论处留言供大家共同讨论。
若前辈们有工作机会介绍欢迎私信。
今天的文章【PCL自学:Feature8】RoPs(旋转投影统计)特征识别物体简介和使用 (持续更新)分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/83220.html