自学内容网 自学内容网

PCL SHOT352描述子

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 计算法向量

2.1.2 均匀采样

2.1.3 计算SHOT描述子

2.2完整代码

三、实现效果


PCL点云算法汇总及实战案例汇总的目录地址链接:

PCL点云算法与项目实战案例汇总(长期更新)


一、概述

        SHOT(Signature of Histograms of Orientations)描述子是一种用于3D点云特征表示的局部特征描述子。通过结合法向量的几何信息和方向信息,SHOT描述子能够有效地在三维点云数据中提取具有不变性特征点。

        在这篇博客中,我们将详细介绍如何基于PCL库使用SHOT352描述子进行点云特征提取,包括法向量的计算、均匀采样关键点的提取,以及最终的描述子计算。

1.1原理

SHOT(Signature of Histograms of Orientations)描述子主要通过以下几个步骤来计算:

  1. 法向量计算:通过对点云中每个点的近邻点进行计算,获取法向量。
  2. 关键点提取:通过均匀采样的方法提取关键点,这些关键点是用于后续描述子计算的点。
  3. 描述子计算:对于每个关键点,在其邻域内计算方向的直方图,生成一个352维的特征向量。

1.2实现步骤

  1. 加载点云数据:通过pcl::PCDReader读取点云文件。
  2. 计算法向量:使用pcl::NormalEstimationOMP多线程加速计算点云中每个点的法向量。
  3. 均匀采样提取关键点:使用pcl::UniformSampling方法对点云进行均匀采样,提取出关键点。
  4. 计算SHOT描述子:使用pcl::SHOTEstimationOMP计算每个关键点的352维描述子。
  5. 可视化描述子:使用pcl::visualization::PCLPlotter进行描述子的直方图可视化。

1.3应用场景

  1. 物体识别:通过SHOT描述子可以识别不同姿态下的物体。
  2. 三维场景匹配:在三维点云数据中,SHOT描述子可以用于匹配相似特征的区域。
  3. 点云配准:在多视图点云配准中,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)!