PCL SHOT352描述子
目录
PCL点云算法汇总及实战案例汇总的目录地址链接:
一、概述
SHOT(Signature of Histograms of Orientations)描述子是一种用于3D点云特征表示的局部特征描述子。通过结合法向量的几何信息和方向信息,SHOT描述子能够有效地在三维点云数据中提取具有不变性特征点。
在这篇博客中,我们将详细介绍如何基于PCL库使用SHOT352描述子进行点云特征提取,包括法向量的计算、均匀采样关键点的提取,以及最终的描述子计算。
1.1原理
SHOT(Signature of Histograms of Orientations)描述子主要通过以下几个步骤来计算:
- 法向量计算:通过对点云中每个点的近邻点进行计算,获取法向量。
- 关键点提取:通过均匀采样的方法提取关键点,这些关键点是用于后续描述子计算的点。
- 描述子计算:对于每个关键点,在其邻域内计算方向的直方图,生成一个352维的特征向量。
1.2实现步骤
- 加载点云数据:通过pcl::PCDReader读取点云文件。
- 计算法向量:使用pcl::NormalEstimationOMP多线程加速计算点云中每个点的法向量。
- 均匀采样提取关键点:使用pcl::UniformSampling方法对点云进行均匀采样,提取出关键点。
- 计算SHOT描述子:使用pcl::SHOTEstimationOMP计算每个关键点的352维描述子。
- 可视化描述子:使用pcl::visualization::PCLPlotter进行描述子的直方图可视化。
1.3应用场景
- 物体识别:通过SHOT描述子可以识别不同姿态下的物体。
- 三维场景匹配:在三维点云数据中,SHOT描述子可以用于匹配相似特征的区域。
- 点云配准:在多视图点云配准中,SHOT描述子可以帮助提高配准精度。
二、代码实现
2.1关键函数
2.1.1 计算法向量
该函数使用pcl::NormalEstimationOMP类来计算点云中每个点的法向量。
void computeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::Normal>::Ptr normals)
{
pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> ne;
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setNumberOfThreads(4); // 使用4线程并行计算
ne.setInputCloud(cloud); // 设置输入点云
ne.setSearchMethod(tree); // 设置搜索方法
ne.setKSearch(10); // 设置近邻点数
ne.compute(*normals); // 计算法向量
}
2.1.2 均匀采样
使用pcl::UniformSampling方法进行均匀采样,以确保关键点分布均匀。
void uniformSampling(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered)
{
pcl::UniformSampling<pcl::PointXYZ> us;
us.setInputCloud(cloud); // 设置输入点云
us.setRadiusSearch(0.01f); // 设置搜索半径
us.filter(*cloud_filtered); // 提取关键点
}
2.1.3 计算SHOT描述子
pcl::SHOTEstimationOMP类用于并行计算每个关键点的SHOT描述子。
void computeSHOTDescriptors(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered, pcl::PointCloud<pcl::Normal>::Ptr normals, pcl::PointCloud<pcl::SHOT352>::Ptr model_descriptors, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
pcl::SHOTEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::SHOT352> shot352;
shot352.setRadiusSearch(0.01); // 设置搜索半径
shot352.setInputCloud(cloud_filtered); // 输入关键点
shot352.setInputNormals(normals); // 输入法线
shot352.setSearchSurface(cloud); // 输入点云
shot352.compute(*model_descriptors); // 计算描述子
}
2.2完整代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h> // 点云类型头文件
#include <pcl/features/normal_3d_omp.h> // 多线程计算法线
#include <pcl/features/shot_omp.h> // SHOT 描述子
#include <pcl/keypoints/uniform_sampling.h> // 均匀采样
#include <pcl/visualization/pcl_plotter.h> // 直方图的可视化
using namespace std;
// 计算法向量
void computeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::Normal>::Ptr normals)
{
pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> ne;
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setNumberOfThreads(4); // 使用4线程并行计算
ne.setInputCloud(cloud); // 设置输入点云
ne.setSearchMethod(tree); // 设置搜索方法
ne.setKSearch(10); // 设置近邻点数
ne.compute(*normals); // 计算法向量
}
// 均匀采样
void uniformSampling(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered)
{
pcl::UniformSampling<pcl::PointXYZ> us;
us.setInputCloud(cloud); // 设置输入点云
us.setRadiusSearch(0.01f); // 设置搜索半径
us.filter(*cloud_filtered); // 提取关键点
}
// 计算 SHOT 描述子
void computeSHOTDescriptors(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered, pcl::PointCloud<pcl::Normal>::Ptr normals, pcl::PointCloud<pcl::SHOT352>::Ptr model_descriptors, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
pcl::SHOTEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::SHOT352> shot352;
shot352.setRadiusSearch(0.01); // 设置搜索半径
shot352.setInputCloud(cloud_filtered); // 输入关键点
shot352.setInputNormals(normals); // 输入法线
shot352.setSearchSurface(cloud); // 输入点云
shot352.compute(*model_descriptors); // 计算描述子
}
void printSHOTDescriptorInfo(pcl::PointCloud<pcl::SHOT352>::Ptr model_descriptors)
{
// 输出描述子信息
cout << "SHOT描述子的个数: " << model_descriptors->size() << endl;
cout << "每个描述子的维度: 352" << endl;
// 输出每个关键点的描述子信息(这里只输出前5个关键点作为示例)
for (size_t i = 0; i < model_descriptors->size() && i < 5; ++i)
{
cout << "关键点 " << i + 1 << " 的描述子: " << endl;
for (int j = 0; j < 352; ++j)
{
cout << model_descriptors->points[i].descriptor[j] << " ";
}
cout << endl;
}
}
int main()
{
// 1. 加载点云数据
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
if (pcl::io::loadPCDFile<pcl::PointXYZ>("C:\\Users\\twothree\\Desktop\\PCL_Blog\\PCL_Blog\\cloud_data\\pcd_data\\bunny.pcd", *cloud) == -1)
{
PCL_ERROR("Could not read file\n");
return -1;
}
// 2. 计算法向量
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
computeNormals(cloud, normals);
// 3. 均匀采样提取关键点
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>());
uniformSampling(cloud, cloud_filtered);
// 4. 计算 SHOT 描述子
pcl::PointCloud<pcl::SHOT352>::Ptr model_descriptors(new pcl::PointCloud<pcl::SHOT352>());
computeSHOTDescriptors(cloud_filtered, normals, model_descriptors, cloud);
// 5. 输出描述子信息
printSHOTDescriptorInfo(model_descriptors);
return 0;
}
三、实现效果
SHOT352描述子在PCL中无法直接用plot进行可视化
原文地址:https://blog.csdn.net/qq_47947920/article/details/142783207
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!