PCL 3D-SIFT关键点检测(Z方向梯度约束

news2024/11/19 20:19:25

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 SIFT关键点检测

2.1.2 可视化函数

2.2完整代码

三、实现效果


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

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


一、概述

        3D-SIFT关键点检测是SIFT算法在三维点云中的扩展应用。与二维图像的SIFT类似,它通过尺度空间的构建和局部特征检测来提取点云的关键点。在三维点云中,SIFT可以通过计算每个点在Z方向的梯度,找到具有几何显著特征的关键点,适用于物体识别、特征匹配、点云配准等应用场景。

1.1原理

        SIFT(Scale-Invariant Feature Transform)算法通过建立图像的尺度空间来提取关键点。在三维点云中,我们可以通过分析Z轴方向的变化(梯度)来检测点云的关键点。其核心步骤包括:

  1. 尺度空间构建:通过不同尺度的高斯核卷积,构造尺度空间,使得算法能够在不同的尺度下检测关键点。最小尺度通过参数 min_scale 设置,尺度空间的层数和每个层次的尺度数量由 n_octaves n_scales_per_octave 控制。
  2. 关键点检测:通过对尺度空间的极值点检测来提取关键点,极值点通过比较邻域点在不同尺度下的响应得到。为了减少检测到的无效点,需要设置最小对比度 min_contrast,以过滤掉噪声。
  3. 梯度估计:利用Z方向的变化,估计点云中每个点的局部梯度,作为响应值。Z轴梯度用于构建响应函数,并检测局部极值。

参数解释

  • min_scale:最小尺度,控制高斯核的最小标准差。
  • n_octaves:尺度空间的层数。
  • n_scales_per_octave:每个层次的尺度数量。
  • min_contrast:最小对比度,用于过滤掉低响应值的点。

1.2实现步骤

  1. 加载点云数据。
  2. 初始化SIFT关键点提取器,设置所需的参数(如尺度、对比度等)。
  3. 通过SIFT算法提取点云中的关键点,并将结果转换为标准的XYZ点云格式。
  4. 可视化原始点云和提取的SIFT关键点。

1.3应用场景

  1. 三维物体识别:通过SIFT提取点云的关键点进行特征匹配和物体识别。
  2. 点云配准:利用关键点信息对不同视角的点云进行精确对齐。
  3. 特征提取:用于三维重建、机器人导航等领域中的特征提取和环境感知。

二、代码实现

2.1关键函数

2.1.1 SIFT关键点检测

void extractSIFTKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointWithScale>::Ptr keypoints)
{
    // 设置SIFT算法参数
    const float min_scale = 0.001f;           // 设置尺度空间中最小尺度的标准偏差          
    const int n_octaves = 3;                  // 设置尺度空间层数,越小则特征点越多           
    const int n_scales_per_octave = 15;       // 设置尺度空间中计算的尺度个数
    const float min_contrast = 0.0001f;       // 设置限制关键点检测的阈值   

    // 创建SIFT关键点检测对象
    pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;
    sift.setInputCloud(cloud);                // 设置输入点云
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ> ());
    sift.setSearchMethod(tree);               // 设置KdTree搜索
    sift.setScales(min_scale, n_octaves, n_scales_per_octave); // 设置尺度范围
    sift.setMinimumContrast(min_contrast);    // 设置最小对比度

    // 执行SIFT关键点检测
    sift.compute(*keypoints);
}

2.1.2 可视化函数

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, 0, 255, 0);
    viewer->addPointCloud(cloud, original_color, "original_cloud", v1);

    // 关键点显示为红色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color(keypoints, 255, 0, 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完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/keypoints/sift_keypoint.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/common/time.h>
#include <boost/thread/thread.hpp>

// 基于Z梯度估计3D点云的SIFT关键点
namespace pcl
{
    template<>
    struct SIFTKeypointFieldSelector<PointXYZ>
    {
        inline float
            operator () (const PointXYZ& p) const
        {
            return p.z;
        }
    };
}

// 提取SIFT关键点
void extractSIFTKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointWithScale>::Ptr keypoints)
{
    const float min_scale = 0.001f;           // 设置尺度空间中最小尺度的标准偏差          
    const int n_octaves = 3;                  // 设置尺度空间层数,越小则特征点越多           
    const int n_scales_per_octave = 15;       // 设置尺度空间中计算的尺度个数
    const float min_contrast = 0.0001f;       // 设置限制关键点检测的阈值   

    // 创建SIFT关键点检测对象
    pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;
    sift.setInputCloud(cloud);                // 设置输入点云
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    sift.setSearchMethod(tree);               // 设置KdTree搜索
    sift.setScales(min_scale, n_octaves, n_scales_per_octave); // 设置尺度范围
    sift.setMinimumContrast(min_contrast);    // 设置最小对比度

    // 执行SIFT关键点检测
    sift.compute(*keypoints);
}

// 可视化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);
    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, 0, 255, 0);
    viewer->addPointCloud(cloud, original_color, "original_cloud", v1);

    // 关键点显示为红色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color(keypoints, 255, 0, 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[])
{
    pcl::StopWatch watch; // 计时器
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("bunny.pcd", *cloud_xyz);

    // 提取SIFT关键点
    pcl::PointCloud<pcl::PointWithScale>::Ptr sift_keypoints(new pcl::PointCloud<pcl::PointWithScale>);
    extractSIFTKeypoints(cloud_xyz, sift_keypoints);

    // 将SIFT关键点转换为标准XYZ格式
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_temp(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::copyPointCloud(*sift_keypoints, *cloud_temp);

    std::cout << "Extracted " << sift_keypoints->size() << " keypoints" << std::endl;
    std::cout << "SIFT关键点提取用时: " << watch.getTimeSeconds() << "秒" << std::endl;

    // 可视化输入点云和SIFT关键点
    visualizeSIFTKeypoints(cloud_xyz, cloud_temp);

    return 0;
}

三、实现效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2199961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

调用CString::Format接口格式化字符串时产生异常,可能是将当前的CString对象作为参数传给CString::Format接口导致的

最近有人在技术群里问一个关于使用MFC库中的CString类格式化字符串时遇到的问题&#xff0c;有时格式化出来的字符串有问题&#xff08;不是预期的&#xff09;&#xff0c;有时会产生异常崩溃&#xff0c;让我们帮忙分析一下&#xff0c;看看是什么原因导致的。 后来到MSDN上查…

JAVA基础: synchronized 和 lock的区别、synchronized锁机制与升级

1 synchronized 和 lock的区别 synchronized是一个关键字&#xff0c; lock是一个接口&#xff0c;实际使用的是实现类 synchronized通过触发的是系统级别的锁机制&#xff0c; lock是API级别的锁机制 synchronized自动获得锁&#xff0c;自动释放锁。 lock需要通过方法获得锁…

基于SSM的校园教务系统的设计与实现(论文+源码)_kaic

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对校园教务信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

【含开题报告+文档+PPT+源码】基于SSM框架的民宿酒店预定系统的设计与实现

开题报告 随着人们旅游需求的增加&#xff0c;民宿行业呈现出快速发展的趋势。传统的住宿方式逐渐无法满足人们对个性化、舒适、便捷的需求&#xff0c;而民宿作为一种新型的住宿选择&#xff0c;逐渐受到人们的青睐。民宿的特点是具有独特的风格、便捷的地理位置、相对亲近的…

基于yolov8的版面分析AI能力生产全流程

目录 1.coco数据集 1.1 基本定义 1.2应用场景 1.3 数据结构 2.labelme标注工具 2.1 基本定义 2.2 应用场景 2.3 安装步骤 3. 模型训练 3.1 数据标注 3.2 环境准备 3.3 数据预处理 3.4 模型训练 3.5 模型推理 4.参考链接 1.coco数据集 1.1 基本定…

数据库的相关知识

数据库的相关知识 1.数据库能够做什么&#xff1f; 存储大量数据&#xff0c;方便检索和访问保持数据信息的一致、完整共享和安全通过组合分析&#xff0c;产生新的有用信息 2.数据库作用&#xff1f; 存储数据、检索数据、生成新的数据 3.数据库要求&#xff1f; 统一、…

51单片机的自动洗手器【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机红外传感器继电器LED等模块构成。适用于红外感应洗手器、自动出水等相似项目。 可实现功能: 1、红外传感器实时采集人体信息&#xff0c;如果有人靠近&#xff0c;则闭合水泵继电器开始出水&#xff0c;人离开5s后&#xff0c;继电…

微信5大隐藏技巧,让你成为聊天高手

微信&#xff0c;这个几乎人人都在使用的应用&#xff0c;它的一些隐藏功能却鲜为人知。 今天&#xff0c;就让我们一起来探索这些实用的小技巧&#xff0c;让你的微信使用体验更上一层楼。 一键长截图&#xff0c;保存完整信息 在微信里&#xff0c;当你需要截取某个网页或公…

JAVA八股文1

1.Java 基础 1.1 语法基础 封装 利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部&#xff0c;尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与外部发生联系。用户无需知道对象内…

【算法】链表:2.两数相加(medium)+模拟

系列专栏 《分治》 《模拟》 《Linux》 目录 1、题目链接 2、题目介绍 3、解法 (模拟) 4、代码 1、题目链接 2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 2、题目介绍 3、解法 (模拟) 理解题目要求&#xff1a; 我们有两个链表&#xff0c;每个链表代表一个…

完成Sentinel-Dashboard控制台数据的持久化-同步到Nacos

本次案例采用的是Sentinel1.8.8版本 一、Sentinel源码环境搭建 1、下载Sentinel源码工程 git clone https://github.com/alibaba/Sentinel.git 2、导入到idea 这里可以先运行DashboardApplication.java试一下是否运行成功&#xff0c;若成功&#xff0c;源码环境搭建完毕&a…

华为OD机试 - 最长广播响应 - 广度优先搜索(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

计算机视觉学习笔记--高斯金字塔,DoG金字塔和拉普拉斯金字塔附带代码

尺度空间和图像金字塔 尺度并非指图像的大小&#xff0c;而是指图像的模糊程度&#xff0c;从近距离到远距离图像越来越模糊的过程&#xff0c;也是图像的尺度越来越大的过程。尺度空间是图像在不同尺度下的连续表示。其中最常见的是使用高斯核对图像进行卷积。随着高斯滤波核…

网格剖分-耳切法效果展示

1.前言 将简单多边形转换成一组由同样顶点组成的三角形集合是计算机图形学中的一个经典问题。问题中&#xff0c;简单多边形是指由一组有序顶点组成的&#xff0c;点V0~点Vn-1。相邻的顶点之间通过边(Vi,Vi-1)连接&#xff0c;并且边&#xff08;Vn-1,V0&#xff09;连接起始点…

换毛季来临,铲屎官如何应对猫咪掉毛?宠物空气净化器该怎么选?

养猫前&#xff0c;我是潇洒自如的单身汉&#xff1b;养猫后&#xff0c;我就是勤恳辛劳的保姆&#xff01;每天下班还要“伺候”猫孩子&#xff0c;收拾它一天在家掉落的猫毛。虽说我没有洁癖&#xff0c;但换毛季可不是开玩笑的&#xff0c;稍微偷懒几天没有清理&#xff0c;…

C++竞赛初阶—— 石头剪子布

题目内容 石头剪子布&#xff0c;是一种猜拳游戏。起源于中国&#xff0c;然后传到日本、朝鲜等地&#xff0c;随着亚欧贸易的不断发展它传到了欧洲&#xff0c;到了近现代逐渐风靡世界。简单明了的规则&#xff0c;使得石头剪子布没有任何规则漏洞可钻&#xff0c;单次玩法比…

苹果开发者网站iOS应用创建全流程详解

引言 在当今的移动开发领域&#xff0c;uni-app 和 Flutter 等跨平台开发工具为开发者提供了便利&#xff0c;可以一次编写代码并部署到多个平台。然而&#xff0c;尽管这些工具简化了应用的开发过程&#xff0c;但它们在iOS应用的构建和发布环节往往并不涉及太多。对于希望在…

上传本地项目到GitHub远程仓库(极简洁操作版)

第一步&#xff1a;在GitHub创建一个空的仓库 第二步&#xff1a;将仓库克隆&#xff08;下载&#xff09;到本地 第三步&#xff1a;将你要上传的所有文件放到这个克隆的仓库文件夹中 第四步&#xff1a;通过git add .将待上传文件添加到暂存区 此时&#xff0c;可以通过git …

网际报文协议ICMP及ICMP重定向实例详解5

之前在一个项目中遇到了与ICMP重定向相关的问题&#xff0c;因为缺乏对ICMP相关内容的了解&#xff0c;排查了很长一段时间才查出来。本文给大家简要地介绍一下ICMP及ICMP重定向相关的内容。 1、ICMP的概念 ICMP&#xff08;Internet Control Message Protocol&#xff09;网际…

156-反溯源隐藏C2项目域前置云函数数据中转DNS转发

演示案例&#xff1a; CS-隐藏防朔源-域前置-C2&CDN CS-隐藏防朔源-云函数-C2&API 触发 CS-隐藏防朔源-DNS 解析-C2&流量伪装 CS-隐藏防朔源-数据转发-C2&Iptables&中间件 接上节课的知识点&#xff0c;上节课只讲了利用CDN进行隐藏的方式 #域前置-CDN 配合…