前言
什么是关键点?
关键点定义: 关键点也称为兴趣点,它是2D图像、3D点云或曲面模型上,可以通过定义检测标准来获取的具有稳定性、区别性的点集。
关键点的意义?
加快后续识别、追踪等数据的处理速度
具备该意义原因?
关键点的数量相比于原始点云或图像的数据量小很多,它与局部特征描述子结合在一起,组成关键点描述子,常用来形成原始数据的紧凑表示,而不失代表性与描述性。
SIFT关键点检测
SIFT(Scale-invaiant feature transform)尺度不变特征变换。最初用于图像处理领域的一种描述,可以在图像中检测出关键点,是一种局部特征描述子,后来引入3D点云领域用于关键点的检测。
在PCL中类 SIFTKeypoint 是将二维图像中的 SIFT 算子调整后移植到 3D 空间的 SIFT算子的实现。输入为带有 XYZ 坐标值和强度的点云 , 输出为点云中的 SIFT 关键点。
Code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/io.h>
#include <pcl/keypoints/sift_keypoint.h>//sift 关键点 检测 模块
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/time.h>
SIFT关键点提取 必须包含 sift_keypoint.h 文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*从pcd文件中读取点云*/
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz (new pcl::PointCloud<pcl::PointXYZ>);//声明读取的点云
std::string filename= "/home/jone/slam_learn/pcl/sift_keypoint_extraction/pig.pcd"; //pcd文件路径
// 读取点云
if(pcl::io::loadPCDFile(filename,*cloud_xyz)==-1)
{
//文件没有打开
std::cout << "Was not able to open file:" <<filename<<std::endl ;
return 0;
}
从pcd文件中读取点云
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//设置 sift 相关参数
const float min_scale = 0.01; //设置尺度空间中最小尺度的标准偏差
const int n_octaves = 6; //设置高斯金字塔组(octave)的数目
const int n_scales_per_octave = 4; //设置每组(octave)计算的尺度
const float min_contrast = 0.01; //设置限制关键点检测的阈值
下面会有setScales()函数 ,用到前3个参数 ,指定搜索关键点的尺度范围
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/***** 进行sift关键点检测 *****/
/* 创建sift关键点检测对象 */
pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;
pcl::PointCloud<pcl::PointWithScale> result; //声明存放结果的点云
sift.setInputCloud(cloud_xyz);//设置输入点云
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ> ());//声明一个Kd-tree
/*上面创建的一个空的kd树对象,并把它传递给sift检测对象*/
sift.setSearchMethod(tree);
/*指定搜索关键点的尺度范围*/
sift.setScales(min_scale, n_octaves, n_scales_per_octave);
/*设置限制关键点检测的阈值ֵ*/
sift.setMinimumContrast(min_contrast);
/*执行sift关键点检测,保存结果在result*/
sift.compute(result);
/*****************************/
本节重点部分:进行sift关键点检测
1、创建sift关键点检测对象
2、声明存放结果的点云
3、设置输入点云
4、声明一个Kd-tree
5、上面创建的一个空的kd树对象,并把它传递给sift检测对象
6、指定搜索关键点的尺度范围
7、设置限制关键点检测的阈值ֵ
8、执行sift关键点检测
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_temp (new pcl::PointCloud<pcl::PointXYZ>);//声明一个点云 用于存放 检测结果
/*将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据*/
copyPointCloud(result, *cloud_temp);//转换结果点的类型
将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//可视化输入点云和关键点
pcl::visualization::PCLVisualizer viewer("Sift keypoint");
viewer.setBackgroundColor( 255, 255, 255 );
viewer.addPointCloud(cloud_xyz, "cloud");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,0,0,"cloud");
viewer.addPointCloud(cloud_temp, "keypoints");
viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 9, "keypoints");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,0,255,"keypoints");
while(!viewer.wasStopped ())
{
viewer.spinOnce ();
}
可视化输入点云和关键点
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CMakeLists.txt
# 声明要求的 cmake 最低版本
cmake_minimum_required(VERSION 2.8 )
# 声明工程名称
project(sift_keypoint_extraction)
# 添加c++ 11 标准支持
set(CMAKE_CXX_FLAGS "-std=c++11")
# 寻找PCL的库
find_package(PCL REQUIRED COMPONENT common io visualization filters features keypoints)
link_directories(${PCL_LIBRARY_DIRS})
# 添加头文件
include_directories(${PCL_INCLUDE_DIRS})
add_definitions( ${PCL_DEFINITIONS} )
#添加一个可执行程序
add_executable(sift_keypoint_extraction sift_keypoint_extraction.cpp)
#链接PCL 库
target_link_libraries(sift_keypoint_extraction ${PCL_LIBRARIES})
注意:find_package() 要包含 keypoints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Result
其中蓝色的就是检测到的 SIFT关键点