SIFT (Scale-Invariant Feature Transform)
-
描述: SIFT 是一种图像特征提取算法,通过尺度不变性来检测关键点。尽管 SIFT 原本是用于图像处理的,但经过扩展后可以应用于点云数据。
-
优点: 具有尺度和旋转不变性,能够在不同分辨率下稳定地提取关键点。
-
使用场景: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;
}
- 上述代码在点云数据不存在强度属性时会报错。
SIFT 算法通常用于图像处理,常常是基于像素的强度值(intensity)来提取关键点。但在3D点云处理中,强度可能不是唯一的感兴趣的字段,因此我们可以选择其他字段,比如Z轴坐标。即当点云数据中没有强度属性时,可以自定义选择字段作为算法的输入来构建尺度空间和进行特征提取。
(一)示例代码
#define _CRT_SECURE_NO_WARNINGS
#include <pcl/point_types.h>
#include <pcl/keypoints/sift_keypoint.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
// 增加z坐标字段选择
namespace pcl
{
template<>
struct SIFTKeypointFieldSelector<PointXYZ>
{
inline float
operator () (const PointXYZ& p) const
{
return p.z;
}
};
}
// 提取SIFT关键点的函数
pcl::PointCloud<pcl::PointXYZ>::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);
// 将关键点转换为 pointxyz 格式
pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_xyz(new pcl::PointCloud<pcl::PointXYZ>());
pcl::copyPointCloud(*keypoints, *keypoints_xyz);
// 返回关键点
return keypoints_xyz;
}
(二)demo 结果显示
上图为示例结果,红色点为提取的关键点。
Harris 角点检测算法提取关键点
Harris角点检测算法最初是为图像处理中提取角点(特征点)而开发的,但在点云处理中也能被用于检测点云中的特征点。
(一)示例代码
#define _CRT_SECURE_NO_WARNINGS
#include <pcl/point_types.h>
#include <pcl/keypoints/harris_3d.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
// 提取Harris关键点的函数
pcl::PointCloud<pcl::PointXYZ>::Ptr extractHarrisKeypoints(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
// 创建 Harris 关键点检测器
pcl::HarrisKeypoint3D<pcl::PointXYZ, pcl::PointXYZI> harris;
harris.setInputCloud(cloud);
harris.setNonMaxSupression(true); // 非极大值抑制
harris.setRadius(0.01f); // 搜索半径
harris.setRadiusSearch(0.01f); // 搜索半径
// 保存结果
pcl::PointCloud<pcl::PointXYZI>::Ptr keypoints(new pcl::PointCloud<pcl::PointXYZI>);
harris.compute(*keypoints);
// 将关键点转换为 pointxyz 格式
pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_xyz(new pcl::PointCloud<pcl::PointXYZ>());
pcl::copyPointCloud(*keypoints, *keypoints_xyz);
// 返回关键点
return keypoints_xyz;
}
(二)demo 结果显示
可以看到,有些 Harris 关键点并非原始数据中的点,这通常是由于算法内部的插值、响应值最大化策略或数值误差导致的。所以应用时需注意。
ISS 提取点云关键点
ISS(Intrinsic Shape Signatures)通过分析点云中的几何形状来检测具有稳定局部几何特征的关键点。这些关键点通常位于曲率变化较大的区域,如边缘、角点等。
(一)示例代码
#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;
}