PCL_NARF关键点提取 + 特征描述符


NARF(Normal Aligned Radial Feature)关键点是为了从深度图像中识别物体而提出的.

关键点提取并不是一个独立的部分,他往往会更进一步的应用于特征描述、识别、寻物等。

NARF(Normal Aligned Radial Feature)关键点是为了从深度图像中识别物体而提出的,对NARF关键点的提取过程有以下要求:
a) 提取的过程考虑边缘以及物体表面变化信息在内;
b)在不同视角关键点可以被重复探测;
c)关键点所在位置有足够的支持区域,可以计算描述子和进行唯一的估计法向量。

其对应的探测步骤如下:
(1) 遍历每个深度图像点,通过寻找在近邻区域有深度变化的位置进行边缘检测。
(2) 遍历每个深度图像点,根据近邻区域的表面变化决定一测度表面变化的系数,及变化的主方向。
(3) 根据step(2)找到的主方向计算兴趣点,表征该方向和其他方向的不同,以及该处表面的变化情况,即该点有多稳定。
(4) 对兴趣值进行平滑滤波。
(5) 进行无最大值压缩找到的最终关键点,即为NARF关键点。

code:

代码总流程:读取点云或创建点云-----转化为深度图-----边缘提取-----提取关键点-----可视化

/* \author Bastian Steder */

#include <iostream>
#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>
#include <pcl/console/parse.h>

typedef pcl::PointXYZ PointType;//定义别名

//参数 全局变量
float angular_resolution=0.5f;//角坐标分辨率
float support_size=0.2f;//感兴趣点的大小,(球的直径)
pcl::RangeImage::CoordinateFrame coordinate_frame=pcl::RangeImage::CAMERA_FRAME;
bool setUnseenToMaxRange=false; //是否将所有不可见的点 看作最大距离

//打印帮助
void
printUsage(const char* progName)
{
std::cout<<"\n\nUsage: "<<progName<<" [options] <scene.pcd>\n\n"
<<"Options:\n"
<<"-------------------------------------------\n"
<<"-r <float>   angular resolution in degrees (default "<<angular_resolution<<")\n"
<<"-c <int>     coordinate frame (default "<<(int)coordinate_frame<<")\n"
<<"-m           Treat all unseen points as maximum range readings\n"
<<"-s <float>   support size for the interest points (diameter of the used sphere - "
<<"default "<<support_size<<")\n"
<<"-h           this help\n"
<<"\n\n";
}

/*
void
setViewerPose(pcl::visualization::PCLVisualizer& viewer,const Eigen::Affine3f&viewer_pose)
{
Eigen::Vector3f pos_vector=viewer_pose*Eigen::Vector3f(0,0,0);
Eigen::Vector3f look_at_vector=viewer_pose.rotation()*Eigen::Vector3f(0,0,1)+pos_vector;
Eigen::Vector3f up_vector=viewer_pose.rotation()*Eigen::Vector3f(0,-1,0);
viewer.setCameraPosition(pos_vector[0], pos_vector[1], pos_vector[2],
	look_at_vector[0], look_at_vector[1], look_at_vector[2],
	up_vector[0], up_vector[1], up_vector[2]);

}
*/

// -----Main-----
int
main(int argc,char** argv)
{
//解析命令行参数
if(pcl::console::find_argument(argc,argv,"-h")>=0)
{
printUsage(argv[0]);
return 0;
}
if(pcl::console::find_argument(argc,argv,"-m")>=0)
{
setUnseenToMaxRange=true;
cout<<"Setting unseen values in range image to maximum range readings.\n";
}
int tmp_coordinate_frame;
if(pcl::console::parse(argc,argv,"-c",tmp_coordinate_frame)>=0)
{
coordinate_frame=pcl::RangeImage::CoordinateFrame(tmp_coordinate_frame);
cout<<"Using coordinate frame "<<(int)coordinate_frame<<".\n";
}
if(pcl::console::parse(argc,argv,"-s",support_size)>=0)
cout<<"Setting support size to "<<support_size<<".\n";
if(pcl::console::parse(argc,argv,"-r",angular_resolution)>=0)
cout<<"Setting angular resolution to "<<angular_resolution<<"deg.\n";
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;//上面点云的别名
pcl::PointCloud<pcl::PointWithViewpoint>far_ranges;//带视角的点构成的点云
Eigen::Affine3f scene_sensor_pose(Eigen::Affine3f::Identity());//仿射变换
std::vector<int>pcd_filename_indices=pcl::console::parse_file_extension_argument(argc,argv,"pcd");
if(!pcd_filename_indices.empty())
{
std::string filename=argv[pcd_filename_indices[0]];
if(pcl::io::loadPCDFile(filename,point_cloud)==-1)
{
cerr<<"Was not able to open file \""<<filename<<"\".\n";
printUsage(argv[0]);
return 0;
}
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_);
std::string far_ranges_filename=pcl::getFilenameWithoutExtension(filename)+"_far_ranges.pcd";
if(pcl::io::loadPCDFile(far_ranges_filename.c_str(),far_ranges)==-1)
std::cout<<"Far ranges file \""<<far_ranges_filename<<"\" does not exists.\n";
}
else//如果没有指定pcd,则生成点云
{
setUnseenToMaxRange=true;
cout<<"\nNo *.pcd file given =>Genarating example point cloud.\n\n";
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);
range_image.integrateFarRanges(far_ranges);//整合远距离点云
if(setUnseenToMaxRange)
range_image.setUnseenToMaxRange();


// 创建3D点云可视化窗口,并显示点云
pcl::visualization::PCLVisualizer 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.addCoordinateSystem (1.0f);
//pcl::visualization::PointCloudColorHandlerCustom<PointType> point_cloud_color_handler (point_cloud_ptr, 150, 150, 150);
//viewer.addPointCloud (point_cloud_ptr, point_cloud_color_handler, "original point cloud");
//viewer.initCameraParameters();
//setViewerPose(viewer,range_image.getTransformationToWorldSystem());
// 显示距离图像
pcl::visualization::RangeImageVisualizer range_image_widget("Range image");//显示深度图,(平面图,上面的3D显示)
range_image_widget.showRangeImage(range_image);


//提取NARF关键点
pcl::RangeImageBorderExtractor range_image_border_extractor;//创建深度图像的边缘提取器
pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor);//创建narf对象
narf_keypoint_detector.setRangeImage(&range_image);
narf_keypoint_detector.getParameters().support_size=support_size;
//narf_keypoint_detector.getParameters ().add_points_on_straight_edges = true;
//narf_keypoint_detector.getParameters ().distance_for_additional_points = 0.5;

pcl::PointCloud<int> keypoint_indices;//存储关键点的索引
narf_keypoint_detector.compute(keypoint_indices);//计算narf关键点
std::cout<<"Found "<<keypoint_indices.points.size()<<" key points.\n";


//在range_image_widget内显示关键点
//for (size_t i = 0; i < keypoint_indices.points.size(); ++i)
	//range_image_widget.markPoint(keypoint_indices.points[i] % range_image.width,
		                         //keypoint_indices.points[i] / range_image.width);

//在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,10);
viewer.addPointCloud<pcl::PointXYZ>(keypoints_ptr,keypoints_color_handler,"keypoints");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,7,"keypoints");

// 主循环
while(!viewer.wasStopped())
{
range_image_widget.spinOnce();// process GUI events
viewer.spinOnce();
pcl_sleep(0.01);
}
}

result:


以上进行了narf关键点的提取,之后要提取narf描述子  NarfDescriptor

 //这段直接添加到提取narf关键点的代码上(“在三维视图中显示关键点”后就行)
 // -----为特征点提取NARF描述子-----
  std::vector<int> keypoint_indices2;
  keypoint_indices2.resize (keypoint_indices.points.size ());
  for (unsigned int i=0; i<keypoint_indices.size (); ++i) 
	  //要得到正确的向量类型,这一步是必要的
	  //建立NARF关键点的索引向量,此矢量作为NARF特征计算的输入来使用
      keypoint_indices2[i]=keypoint_indices.points[i];
  pcl::NarfDescriptor narf_descriptor (&range_image, &keypoint_indices2);
  narf_descriptor.getParameters ().support_size = support_size;
  narf_descriptor.getParameters ().rotation_invariant = rotation_invariant;
  pcl::PointCloud<pcl::Narf36> narf_descriptors;
  narf_descriptor.compute (narf_descriptors);
  cout << "Extracted "<<narf_descriptors.size ()<<" descriptors for "
                      <<keypoint_indices.points.size ()<< " keypoints.\n";

结果:


参考:https://www.cnblogs.com/ironstark/p/5051533.html

扫描二维码关注公众号,回复: 11475900 查看本文章

https://blog.csdn.net/xuezhisdc/article/details/51018872

https://www.cnblogs.com/li-yao7758258/p/6476359.html

猜你喜欢

转载自blog.csdn.net/yamgyutou/article/details/105080379