1.简述
关键点也称为兴趣点,是2D图像或3D点云或曲面模型上,可以通过定义标准来获取具有稳定性、区别性的点集。它与局部特征描述子一起组成关键描述子用来加快后续识别、追踪等对数据处理速度。
2.关键点算法
NARF关键点:是为了从深度图中识别物体而提出来的。 关键点探测的重要一步是减少特征提取的搜索空间,把重点放在重要的结构上。对NARF关键点提取有以下要求:
1) 提取的过程考虑边缘以及物体表面变化信息在内;
2)在不同视角关键点可以被重复探测;
3)关键点所在位置有足够的支持区域,可以计算描述子和进行唯一的估计法向量。
其对应的探测步骤如下:
(1) 遍历每个深度图像点,通过寻找在近邻区域有深度变化的位置进行边缘检测。
(2) 遍历每个深度图像点,根据近邻区域的表面变化决定一测度表面变化的系数,及变化的主方向。
(3) 根据step(2)找到的主方向计算兴趣点,表征该方向和其他方向的不同,以及该处表面的变化情况,即该点有多稳定。
(4) 对兴趣值进行平滑滤波。
(5) 进行无最大值压缩找到的最终关键点,即为NARF关键点。
3.代码
#include <iostream>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <boost/thread/thread.hpp>
#include <pcl/range_image/range_image.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/range_image_visualizer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/keypoints/narf_keypoint.h>
using namespace std;
using namespace pcl;
//参数 全局变量
typedef pcl::PointXYZ PointType;
float angular_resolution = 0.5f; //角坐标分辨率
float support_size = 0.2f; //感兴趣点的尺寸(球面的直径)
pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME; //坐标框架:相机框架
int main( )
{
angular_resolution = pcl::deg2rad(angular_resolution);
//读取pcd文件;如果没有指定文件,就创建样本点
pcl::PointCloud<PointType>::Ptr point_cloud_ptr(new pcl::PointCloud<PointType>); //点云指针
pcl::PointCloud<PointType>& point_cloud = *point_cloud_ptr; //上面点云的别名
Eigen::Affine3f scene_sensor_pose(Eigen::Affine3f::Identity()); //仿射变换
scene_sensor_pose = Eigen::Affine3f(Eigen::Translation3f(point_cloud.sensor_origin_[0],point_cloud.sensor_origin_[1],point_cloud.sensor_origin_[2]))
*Eigen::Affine3f(point_cloud.sensor_orientation_); //设置传感器的姿势
pcl::io::loadPCDFile("D:\\pcd\\frame_00000.pcd", point_cloud); //从磁盘读取pcd文件
/* //自己设置点云文件
for (float x = -0.5f;x <= 0.5f;x += 0.01f)
{
for (float y = -0.5f;y <= 0.5f;y += 0.01f)
{
PointType point;
point.x = x;
point.y = y;
point.z = 2.0f - y;
point_cloud.points.push_back(point);
}
}
point_cloud.width = (int)point_cloud.points.size();point_cloud.height = 1; */
//从点云数据,创建深度图像
float noise_level = 0.0;
float min_range = 0.0f;
int border_size = 1;
boost::shared_ptr<pcl::RangeImage> range_image_ptr(new pcl::RangeImage); //创建RangeImage对象(指针)
pcl::RangeImage& range_image = *range_image_ptr; //引用
range_image.createFromPointCloud(point_cloud, angular_resolution, pcl::deg2rad(360.0f), pcl::deg2rad(180.0f),
scene_sensor_pose, coordinate_frame, noise_level, min_range, border_size); //从点云创建深度图像
//打开3D观察图形窗口,并添加点云
pcl::visualization::PCLVisualizer viewer("3D Viewer"); //创建3D Viewer对象
viewer.setBackgroundColor(1, 1, 1); //设置背景色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> range_image_color_handler(range_image_ptr, 0, 0, 0);
viewer.addPointCloud(range_image_ptr, range_image_color_handler, "range image"); //添加点云
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");
viewer.initCameraParameters();
//显示深度图像(平面图,上面的3D显示)
pcl::visualization::RangeImageVisualizer range_image_widget("Range image");
range_image_widget.showRangeImage(range_image);
//提取NARF关键点
pcl::RangeImageBorderExtractor range_image_border_extractor; //创建深度图像的边界提取器,用于提取NARF关键点
pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor); //创建NARF对象
narf_keypoint_detector.setRangeImage(&range_image);
narf_keypoint_detector.getParameters().support_size = support_size;
pcl::PointCloud<int> keypoint_indices; //用于存储关键点的索引
narf_keypoint_detector.compute(keypoint_indices); //计算NARF关键点
cout << "Found " << keypoint_indices.points.size() << " key points.\n";
//在3D图形窗口中显示关键点
pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr(new pcl::PointCloud<pcl::PointXYZ>); //创建关键点指针
pcl::PointCloud<pcl::PointXYZ>& keypoints = *keypoints_ptr; //引用
keypoints.points.resize(keypoint_indices.points.size()); //点云变形,无序
for (size_t i = 0; i < keypoint_indices.points.size(); ++i) {
keypoints.points[i].getVector3fMap() = range_image.points[keypoint_indices.points[i]].getVector3fMap();
}
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color_handler(keypoints_ptr, 0, 255, 0);
viewer.addPointCloud<pcl::PointXYZ>(keypoints_ptr, keypoints_color_handler, "keypoints");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "keypoints");
//Main loop
while (!viewer.wasStopped())
{
range_image_widget.spinOnce(); // 处理 GUI事件
viewer.spinOnce();
pcl_sleep(0.01);
}
}
4.显示