PCL 3D-SIFT关键点检测(曲率不变特征约束

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

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


一、概述

**3D-SIFT(Scale-Invariant Feature Transform)关键点检测是用于点云分析的一种有效方法,具有尺度不变性和旋转不变性。**在处理复杂场景和物体识别时,通过对点云的多尺度空间构建和局部特征的提取,可以提取稳定的特征点。本示例结合了曲率不变的特性,通过对点云的法向量进行计算,提取出更具几何稳定性的SIFT关键点。

1.1原理

SIFT算法的核心思想是通过尺度空间中的特征检测来找到图像中的稳定特征点。三维SIFT通过计算点云的法向量和曲率来替代二维图像的灰度值,并在不同的尺度下提取稳定的特征点。

对于3D-SIFT,最小尺度为σ0,尺度空间的特征表示为高斯函数,曲率不变特征约束的检测可以通过以下步骤来实现:

1.2实现步骤

  1. **读取点云数据:**加载3D点云文件。
  2. **法向量和曲率计算:**利用Kd-tree搜索每个点的邻域,计算法向量。
  3. **SIFT关键点检测:**结合法向量进行多尺度关键点检测,确保提取的特征点具有几何稳定性。
  4. **可视化结果:**显示原始点云和提取的SIFT关键点。

1.3应用场景

  1. **三维物体识别:**在不同的尺度下提取稳定的特征点,能够应用于物体识别和特征匹配。
  2. **点云配准:**通过关键点的匹配,能够实现点云的精确对齐和配准。
  3. **多尺度分析:**在不同的分辨率下对点云进行多尺度特征分析,适用于复杂场景的检测。

二、代码实现

2.1关键函数

2.1.1 法向量计算

cpp 复制代码
// 计算每个点的法向量和曲率
void computeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals)
{
    pcl::NormalEstimation<pcl::PointXYZ, pcl::PointNormal> ne;  // 创建法向量估计对象
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree_n(new pcl::search::KdTree<pcl::PointXYZ>());  // 初始化KD-tree用于邻域搜索
    ne.setInputCloud(cloud);  // 设置输入点云
    ne.setSearchMethod(tree_n);  // 设置搜索方法
    ne.setRadiusSearch(0.01);  // 设置搜索半径
    ne.compute(*cloud_normals);  // 计算法向量并存储结果到cloud_normals中

    // 将原始的XYZ信息与法向量结果合并
    for (std::size_t i = 0; i < cloud_normals->size(); ++i)
    {
        (*cloud_normals)[i].x = (*cloud)[i].x;
        (*cloud_normals)[i].y = (*cloud)[i].y;
        (*cloud_normals)[i].z = (*cloud)[i].z;
    }
}

2.1.2 SIFT关键点检测

cpp 复制代码
// 使用法向量进行SIFT关键点提取
void extractSIFTKeypoints(pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals, pcl::PointCloud<pcl::PointWithScale>::Ptr keypoints)
{
    const float min_scale = 0.001f;     // 设置尺度空间中最小尺度的标准偏差
    const int n_octaves = 3;            // 设置尺度空间的层数
    const int n_scales_per_octave = 4;  // 设置每个层次中的尺度数量
    const float min_contrast = 0.0001f; // 设置关键点检测的最小对比度

    pcl::SIFTKeypoint<pcl::PointNormal, pcl::PointWithScale> sift;  // 创建SIFT关键点检测对象
    pcl::search::KdTree<pcl::PointNormal>::Ptr tree(new pcl::search::KdTree<pcl::PointNormal>());  // 初始化KD-tree用于邻域搜索
    sift.setSearchMethod(tree);  // 设置搜索方法
    sift.setScales(min_scale, n_octaves, n_scales_per_octave);  // 设置尺度空间参数
    sift.setMinimumContrast(min_contrast);  // 设置最小对比度
    sift.setInputCloud(cloud_normals);  // 设置输入的带有法向量的点云
    sift.compute(*keypoints);  // 进行SIFT关键点检测,并将结果存储在keypoints中
}

2.1.3 可视化函数

cpp 复制代码
// 可视化原始点云和提取的SIFT关键点
void visualizeSIFTKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("SIFT Keypoints Viewer"));

    int v1(0), v2(0);
    viewer->createViewPort(0, 0.0, 0.5, 1.0, v1);  // 创建第一个视口用于显示原始点云
    viewer->setBackgroundColor(1.0, 1.0, 1.0, v1);  // 设置第一个视口的背景为白色
    viewer->addText("Original Point Cloud", 10, 10, "v1_text", v1);  // 添加标签

    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);  // 创建第二个视口用于显示SIFT关键点
    viewer->setBackgroundColor(0.98, 0.98, 0.98, v2);  // 设置第二个视口的背景为灰色
    viewer->addText("SIFT Keypoints", 10, 10, "v2_text", v2);  // 添加标签

    // 设置原始点云的颜色为红色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> original_color(cloud, 255, 0, 0);
    viewer->addPointCloud(cloud, original_color, "original_cloud", v1);

    // 设置关键点的颜色为绿色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color(keypoints, 0, 255, 0);
    viewer->addPointCloud(keypoints, keypoints_color, "keypoints_cloud", v2);

    // 设置关键点的大小
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "keypoints_cloud");

    // 添加坐标系
    viewer->addCoordinateSystem(1.0);

    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);  // 更新视口
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));  // 控制更新频率
    }
}

2.2完整代码

cpp 复制代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/keypoints/sift_keypoint.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>

using namespace std;

void computeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals)
{
    pcl::NormalEstimation<pcl::PointXYZ, pcl::PointNormal> ne;
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree_n(new pcl::search::KdTree<pcl::PointXYZ>());
    ne.setInputCloud(cloud);
    ne.setSearchMethod(tree_n);
    ne.setRadiusSearch(0.01);  // 设置邻域半径
    ne.compute(*cloud_normals); // 计算法向量

    // 将原始的XYZ信息合并到法向量结果中
    for (std::size_t i = 0; i < cloud_normals->size(); ++i)
    {
        (*cloud_normals)[i].x = (*cloud)[i].x;
        (*cloud_normals)[i].y = (*cloud)[i].y;
        (*cloud_normals)[i].z = (*cloud)[i].z;
    }
}

void extractSIFTKeypoints(pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals, pcl::PointCloud<pcl::PointWithScale>::Ptr keypoints)
{
    const float min_scale = 0.001f;     // 最小尺度
    const int n_octaves = 3;            // 尺度空间层数
    const int n_scales_per_octave = 4;  // 每个层次中的尺度数量
    const float min_contrast = 0.0001f; // 最小对比度

    pcl::SIFTKeypoint<pcl::PointNormal, pcl::PointWithScale> sift;
    pcl::search::KdTree<pcl::PointNormal>::Ptr tree(new pcl::search::KdTree<pcl::PointNormal>());
    sift.setSearchMethod(tree);
    sift.setScales(min_scale, n_octaves, n_scales_per_octave);
    sift.setMinimumContrast(min_contrast);
    sift.setInputCloud(cloud_normals);
    sift.compute(*keypoints);
}

void visualizeSIFTKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("SIFT Keypoints Viewer"));

    int v1(0), v2(0);
    viewer->createViewPort(0, 0.0, 0.5, 1.0, v1);
    viewer->setBackgroundColor(1.0, 1.0, 1.0, v1); // 设置白色背景
    viewer->addText("Original Point Cloud", 10, 10, "v1_text", v1);

    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
    viewer->setBackgroundColor(0.98, 0.98, 0.98, v2); // 设置灰色背景
    viewer->addText("SIFT Keypoints", 10, 10, "v2_text", v2);

    // 原始点云显示为红色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> original_color(cloud, 255, 0, 0);
    viewer->addPointCloud(cloud, original_color, "original_cloud", v1);

    // 关键点显示为绿色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color(keypoints, 0, 255, 0);
    viewer->addPointCloud(keypoints, keypoints_color, "keypoints_cloud", v2);

    // 设置点大小
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "keypoints_cloud");

    // 添加坐标系
    viewer->addCoordinateSystem(0.1);

    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }
}

int main(int argc, char** argv)
{
    string filename = "bunny.pcd";
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile(filename, *cloud_xyz);

    pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals(new pcl::PointCloud<pcl::PointNormal>);
    computeNormals(cloud_xyz, cloud_normals);

    pcl::PointCloud<pcl::PointWithScale>::Ptr sift_keypoints(new pcl::PointCloud<pcl::PointWithScale>);
    extractSIFTKeypoints(cloud_normals, sift_keypoints);

    pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_xyz(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::copyPointCloud(*sift_keypoints, *keypoints_xyz);

    visualizeSIFTKeypoints(cloud_xyz, keypoints_xyz);

    return 0;
}

三、实现效果

相关推荐
梦游钓鱼14 小时前
Logger.h和Logger.cc文件分析
开发语言·c++
低调小一14 小时前
OpenClaw 从安装到可用:把 Tools/Skills 变成“可控操控面板”,并用飞书做远程入口
java·大数据·人工智能·飞书·openclaw·clawbot·skil
穿过锁扣的风14 小时前
OpenCV 实战:花卉轮廓提取与近似 —— 从像素级轮廓到简化几何形状
人工智能·opencv·计算机视觉
八月瓜科技14 小时前
擎策·知海全球专利数据库 凭差异化优势 筑科技创新检索壁垒
大数据·数据库·人工智能·科技·深度学习·机器人
喝拿铁写前端14 小时前
AI 学习之路 01:文本不是“被看懂”的,而是先被表示成可计算对象
人工智能·机器学习
安逸sgr14 小时前
【端侧 AI 实战】BitNet 详解:1-bit LLM 推理优化从原理到部署!
人工智能·python·scrapy·fastapi·ai编程·claude
weixin_4639234214 小时前
写论文全程没用AI,被检测出“AI生成”,AIGC是否靠谱?
人工智能·毕业设计·aigc·论文笔记
mit6.82414 小时前
Agent memory发展路线
算法
喵叔哟14 小时前
06_什么样的任务最该用Skills?5类高频场景清单
人工智能·skills
tq108614 小时前
新航海时代的贸易
人工智能