PCL从理解到应用【09】 点云特征 | 关键点提取 | 方法汇总

前言

PCL中,有多种方法和函数可以用来提取点云特征,本文介绍关键点提取。

提取点云关键点,本文介绍的方法包括:SIFT、Harris、NARF、ISS和SUSAN。

Harris 提取点云关键点,效果如下图所示:

白色点是原始的点云(兔子),绿色点是Harris提取的点云关键点。

1、SIFT 提取点云关键点

基本原理:

  • SIFT算法的设计目的是在点云中,不同尺度旋转角度下稳定地检测特征点
  • 主要步骤包括:
    1. 构建尺度空间,通过高斯模糊和降采样生成不同尺度的图像。
    2. 在不同尺度图像中计算高斯差分(Difference of Gaussian, DoG),检测极值点。
    3. 对每个极值点进行精确定位,通过滤除低对比度点和边缘响应点,保留稳定的关键点。
    4. 为每个关键点分配主方向,使其具有旋转不变性。
    5. 基于关键点周围的梯度方向和幅值,生成特征描述子。

使用场景:

  • SIFT关键点适用于需要在尺度和旋转变化下保持不变的应用,例如物体识别和点云匹配。

示例代码:

#include <pcl/point_types.h>
#include <pcl/keypoints/sift_keypoint.h>
#include <pcl/io/pcd_io.h>

// 提取SIFT关键点的函数
pcl::PointCloud<pcl::PointWithScale>::Ptr extractSIFTKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    // 创建SIFT关键点检测对象
    pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;

    // 创建KdTree用于加速搜索
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    sift.setSearchMethod(tree);

    // 设置尺度参数
    // 第一个参数是初始尺度,
    // 第二个参数是尺度的数量,
    // 第三个参数是尺度之间的倍数关系
    sift.setScales(0.01f, 3, 2);

    // 设置最小对比度(用于过滤掉对比度太低的关键点)
    sift.setMinimumContrast(0.0f);

    // 设置输入点云
    sift.setInputCloud(cloud);

    // 创建一个点云对象用于存储关键点
    pcl::PointCloud<pcl::PointWithScale>::Ptr keypoints(new pcl::PointCloud<pcl::PointWithScale>);

    // 计算SIFT关键点
    sift.compute(*keypoints);

    // 返回关键点
    return keypoints;
}

2、Harris 提取点云关键点

基本原理:

  • Harris角点检测器通过计算图像中每个点云的自相关矩阵来找到角点(特征点)。
  • 主要步骤包括:
    1. 计算每个像素点的梯度信息。
    2. 根据梯度信息构建自相关矩阵。
    3. 计算响应函数R,响应函数R的高值表示可能的角点。
    4. 对响应函数进行非极大值抑制,得到角点位置。

使用场景:

  • Harris关键点适用于需要检测点云中局部几何特征显著点的应用,如点云配准和运动检测。

示例代码:

#include <pcl/point_types.h>
#include <pcl/keypoints/harris_3d.h>
#include <pcl/io/pcd_io.h>

// 提取Harris关键点的函数
pcl::PointCloud<pcl::PointXYZI>::Ptr extractHarrisKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    // 创建Harris关键点检测对象
    pcl::HarrisKeypoint3D<pcl::PointXYZ, pcl::PointXYZI> harris;

    // 设置非极大值抑制(用于去除非局部最大值点)
    harris.setNonMaxSupression(true);

    // 设置搜索半径
    harris.setRadius(0.01);

    // 设置输入点云
    harris.setInputCloud(cloud);

    // 创建一个点云对象用于存储关键点
    pcl::PointCloud<pcl::PointXYZI>::Ptr keypoints(new pcl::PointCloud<pcl::PointXYZI>);

    // 计算Harris关键点
    harris.compute(*keypoints);

    // 返回关键点
    return keypoints;
}

3、NARF 提取点云关键点

基本原理:

  • NARF关键点检测器结合点云边界特征法线方向来检测关键点。
  • 主要步骤包括:
    1. 将点云转换为深度图像(Range Image)。
    2. 提取深度图像的边界信息。
    3. 基于边界信息和法线方向,检测具有显著特征的关键点。

使用场景:

  • NARF关键点适用于环境感知和机器人导航等需要高鲁棒性的场景。

示例代码:

#include <pcl/point_types.h>
#include <pcl/range_image/range_image.h>
#include <pcl/keypoints/narf_keypoint.h>
#include <pcl/io/pcd_io.h>

// 提取NARF关键点的函数
pcl::PointCloud<int>::Ptr extractNARFKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    // 设置角度分辨率(以弧度为单位)
    float angular_resolution = pcl::deg2rad(1.0f);

    // 设置坐标系框架
    pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;

    // 设置噪声水平
    float noise_level = 0.0;

    // 设置最小范围
    float min_range = 0.0f;

    // 设置边界大小
    int border_size = 1;

    // 创建范围图像对象
    pcl::RangeImage range_image;

    // 从点云创建范围图像
    range_image.createFromPointCloud(*cloud, angular_resolution, pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), Eigen::Affine3f::Identity(), coordinate_frame, noise_level, min_range, border_size);

    // 创建边界提取器对象
    pcl::RangeImageBorderExtractor range_image_border_extractor;

    // 创建NARF关键点检测对象
    pcl::NarfKeypoint narf_keypoint_detector;

    // 设置范围图像边界提取器
    narf_keypoint_detector.setRangeImageBorderExtractor(&range_image_border_extractor);

    // 设置范围图像
    narf_keypoint_detector.setRangeImage(&range_image);

    // 设置支持大小参数
    narf_keypoint_detector.getParameters().support_size = 0.2f;

    // 创建一个点云对象用于存储关键点索引
    pcl::PointCloud<int>::Ptr keypoints_indices(new pcl::PointCloud<int>);

    // 计算NARF关键点
    narf_keypoint_detector.compute(*keypoints_indices);

    // 返回关键点索引
    return keypoints_indices;
}

4、ISS 提取点云关键点

基本原理:

  • ISS关键点检测器通过分析点的局部几何特征来确定关键点。
  • 主要步骤包括:
    1. 计算每个点的局部协方差矩阵。
    2. 通过协方差矩阵的特征值和特征向量,分析局部几何特征。
    3. 根据特征值的显著性和稳定性,选择关键点。

使用场景:

  • ISS关键点适用于点云数据噪声较少,且需要提取稳定几何特征的场景。

示例代码:

#include <pcl/point_types.h>
#include <pcl/keypoints/iss_3d.h>
#include <pcl/io/pcd_io.h>

// 提取ISS关键点的函数
pcl::PointCloud<pcl::PointXYZ>::Ptr extractISSKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    // 创建ISS关键点检测对象
    pcl::ISSKeypoint3D<pcl::PointXYZ, pcl::PointXYZ> iss_detector;

    // 设置显著半径(影响关键点的选择)
    iss_detector.setSalientRadius(0.05);

    // 设置非极大值抑制半径(用于抑制局部非最大值)
    iss_detector.setNonMaxRadius(0.05);

    // 设置两个阈值,用于控制特征值之间的比率
    iss_detector.setThreshold21(0.975); // 阈值21
    iss_detector.setThreshold32(0.975); // 阈值32

    // 设置最小邻居数(用于过滤孤立点)
    iss_detector.setMinNeighbors(5);

    // 设置输入点云
    iss_detector.setInputCloud(cloud);

    // 创建一个点云对象用于存储关键点
    pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints(new pcl::PointCloud<pcl::PointXYZ>);

    // 计算ISS关键点
    iss_detector.compute(*keypoints);

    // 返回关键点
    return keypoints;
}

5、SUSAN 提取点云关键点

基本原理:

  • SUSAN关键点检测器通过分析云点周围的强度距离一致性来检测特征点。
  • 主要步骤包括:
    1. 为每个点定义一个圆形邻域。
    2. 计算邻域内与中心点强度或距离相似的点的数量。
    3. 基于相似点的数量,判断该点是否为特征点。

使用场景:

  • SUSAN关键点适用于需要提取局部特征显著点的应用,如点云处理中的特征检测。

示例代码:

#include <pcl/point_types.h>
#include <pcl/keypoints/susan.h>
#include <pcl/io/pcd_io.h>

// 提取SUSAN关键点的函数
pcl::PointCloud<pcl::PointXYZI>::Ptr extractSUSANKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    // 创建SUSAN关键点检测对象
    pcl::SUSANKeypoint<pcl::PointXYZ, pcl::PointXYZI> susan;

    // 设置搜索半径
    susan.setRadius(0.01);

    // 设置输入点云
    susan.setInputCloud(cloud);

    // 创建一个点云对象用于存储关键点
    pcl::PointCloud<pcl::PointXYZI>::Ptr keypoints(new pcl::PointCloud<pcl::PointXYZI>);

    // 计算SUSAN关键点
    susan.compute(*keypoints);

    // 返回关键点
    return keypoints;
}

6、方法总结

提取点云关键点,本文介绍的方法包括:

  1. SIFT (Scale-Invariant Feature Transform)
  2. Harris Keypoints
  3. NARF (Normal Aligned Radial Feature)
  4. ISS (Intrinsic Shape Signatures)
  5. SUSAN (Smallest Univalue Segment Assimilating Nucleus)

对比一下5种点云关键点算法,如下表格所示:

方法简介特点时间复杂度优点缺点
SIFT基于尺度不变特征变换,检测不同尺度和旋转不变的关键点尺度不变性、旋转不变性在尺度和旋转变化下稳定,对噪声有较强的鲁棒性计算复杂度高,占用内存大
Harris基于自相关矩阵计算角点,检测局部几何特征显著点非极大值抑制检测速度快,能有效检测角点对噪声敏感,缺乏尺度不变性
NARF结合点云的边界特征和法线方向,通过深度图像提取关键点法线和边界信息结合,鲁棒性高对边界和法线特征敏感,适用于环境感知和机器人导航需要生成深度图像,计算复杂度较高
ISS通过分析点的局部几何特征,选择特征值显著且稳定的关键点几何特征分析,特征值比率能检测出稳定的几何特征点,对噪声不敏感计算复杂度较高,在密集点云上效率较低
SUSAN通过分析邻域内与中心点强度或距离相似的点,检测局部特征显著点基于强度或距离一致性计算简单,适用于实时处理对特征点的准确性依赖于参数设置,对不同数据集需要调整参数

7、实践应用——Harris 提取点云关键点

对输入的PLY文件进行Harris特征提取,并分别可视化原图和特征提取后的效果。

代码思路:

  • 包含头文件:包含PCL的点类型、IO操作、可视化和Harris关键点提取的头文件。
  • 提取Harris关键点的函数:定义extractHarrisKeypoints函数,用于从输入点云中提取Harris关键点。
  • 主函数
    • 直接在代码中指定PLY文件的路径。
    • 创建点云对象并读取PLY文件。
    • 调用extractHarrisKeypoints函数提取Harris关键点。
    • 创建PCL可视化对象viewer,设置背景颜色。
    • 添加原始点云和关键点到可视化对象中,并设置关键点的渲染属性。
    • 启动可视化循环,显示原始点云和关键点。

示例代码:

#include <pcl/point_types.h>
#include <pcl/io/ply_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/keypoints/harris_3d.h>
#include <thread> // 添加此头文件
#include <chrono> // 添加此头文件

// 提取Harris关键点的函数
pcl::PointCloud<pcl::PointXYZI>::Ptr extractHarrisKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    // 创建Harris关键点检测对象
    pcl::HarrisKeypoint3D<pcl::PointXYZ, pcl::PointXYZI> harris;
    harris.setNonMaxSupression(true); // 设置非极大值抑制
    harris.setRadius(0.01); // 设置搜索半径
    harris.setInputCloud(cloud); // 设置输入点云

    // 创建一个点云对象用于存储关键点
    pcl::PointCloud<pcl::PointXYZI>::Ptr keypoints(new pcl::PointCloud<pcl::PointXYZI>);

    // 计算Harris关键点
    harris.compute(*keypoints);

    return keypoints;
}

int main(int argc, char** argv) {
    // 指定PLY文件路径
    std::string file_path = "../../bunny/data/bun000.ply"; // 请将此路径替换为你的PLY文件路径

    // 创建点云对象
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());

    // 读取PLY文件
    if (pcl::io::loadPLYFile<pcl::PointXYZ>(file_path, *cloud) == -1) {
        std::cerr << "Couldn't read file " << file_path << std::endl;
        return -1;
    }

    // 提取Harris关键点
    pcl::PointCloud<pcl::PointXYZI>::Ptr keypoints = extractHarrisKeypoints(cloud);

    // 创建PCL可视化对象
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));

    // 设置背景颜色为黑色
    viewer->setBackgroundColor(0, 0, 0);

    // 添加原始点云
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color_handler(cloud, 255, 255, 255);
    viewer->addPointCloud(cloud, cloud_color_handler, "original cloud");

    // 添加Harris关键点
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZI> keypoints_color_handler(keypoints, 0, 255, 0);
    viewer->addPointCloud<pcl::PointXYZI>(keypoints, keypoints_color_handler, "keypoints");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "keypoints");

    // 启动可视化
    // viewer->addCoordinateSystem(1.0);
    // viewer->initCameraParameters();
    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}

可视化效果:

白色点是原始的点云(兔子),绿色点是Harris提取的点云关键点。

分享完成~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一颗小树x

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值