【点云PCL入门】关键点提取

1.深度图像中提取NARF关键点

#include<iostream>
#include <pcl/range_image/range_image.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/visualization/range_image_visualizer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/keypoints/narf_keypoint.h>

// -----Parameters-----
float angular_resolution = 0.5f;
float support_size = 0.2f;
pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;

int main(int argc, char* argv[])
{
	angular_resolution = pcl::deg2rad(angular_resolution);
    // -----Read pcd file or create example point cloud if not given-----
	pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>&point_cloud = *point_cloud_ptr;
	pcl::PointCloud<pcl::PointWithViewpoint>far_ranges;//远距离点云数据
	Eigen::Affine3f scense_sensor_pose(Eigen::Affine3f::Identity());
	
	if(pcl::io::loadPCDFile("./frame_00000.pcd",point_cloud)==-1)
	{
		std::cerr << "Was not able to open file \n";
		return 0;
	}
	scense_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_);

  // -----Create RangeImage from the PointCloud-----
	float noise_level = 0.0;
	float min_range = 0.0;
	int border_size = 2;
	pcl::RangeImage::Ptr range_image_ptr(new pcl::RangeImage);
	pcl::RangeImage&range_image = *range_image_ptr;
	range_image.createFromPointCloud(point_cloud, angular_resolution, pcl::deg2rad(360.0), pcl::deg2rad(180.0), scense_sensor_pose, coordinate_frame, noise_level, min_range, border_size);
	//range_image.integrateFarRanges(far_ranges);
	range_image.setUnseenToMaxRange();//不可见区域变为最大范围读数,识别出边界

    // -----Open 3D viewer and add point cloud-----
	pcl::visualization::PCLVisualizer viewer("3D Viewer");
	viewer.setBackgroundColor(1, 1, 1); 
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange>range_image_color_handle(range_image_ptr,0,0,0);
	viewer.addPointCloud(range_image_ptr, range_image_color_handle, "range image");
	viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "range image");
	viewer.initCameraParameters();
	// -----Show range image-----
	pcl::visualization::RangeImageVisualizer range_image_widget("Range image");
	range_image_widget.showRangeImage(range_image);
	// -----Extract NARF keypoints-----
	pcl::RangeImageBorderExtractor range_image_border_extractor;
	pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor);
	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);
	std::cout << "Found " << keypoint_indices.size() << " key points.\n";

	// -----Show keypoints in 3D viewer-----
	pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>& keypoints = *keypoints_ptr;
	keypoints.resize(keypoint_indices.size());
	for (std::size_t i = 0; i < keypoint_indices.size(); ++i)
		keypoints[i].getVector3fMap() = range_image[keypoint_indices[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");

	while (!viewer.wasStopped())
	{
		range_image_widget.spinOnce();  // process GUI events
		viewer.spinOnce();
		pcl_sleep(0.01);
	}
	return 0;
}

2.SIFT关键点提取

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/keypoints/sift_keypoint.h>
#include <pcl/features/normal_3d.h>
#include<pcl/visualization/pcl_visualizer.h>

//pcl中sift特征需要返回强度信息,改为如下:
namespace pcl
{
	template<>
	struct SIFTKeypointFieldSelector<PointXYZ>
	{
		inline float operator () (const PointXYZ &p) const
		{
			return p.z;
		}
	};
}
int main(int argc, char* argv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile("./pig.pcd", *cloud_xyz);
	//stof字符串转float
	const float min_scale = 0.01;//设置尺寸空间中最小尺度的标准偏差
	const int n_octaves = 6;//高斯金字塔中组的数目
	const int n_scales_per_octave = 4;//每组计算的尺度数目
	const float min_contrast = 0.01;

	pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;//创建sift关键点检测对象
	pcl::PointCloud<pcl::PointWithScale> result;
	sift.setInputCloud(cloud_xyz);//设置输入点云
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
	sift.setSearchMethod(tree);//创建一个空的kd树对象tree,并把它传递给sift检测对象
	sift.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
	sift.setMinimumContrast(min_contrast);//设置限制关键点检测的阈值
	sift.compute(result);//执行sift关键点检测,保存结果在result


	//为了后期处理与显示的需要
	//将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_temp(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::copyPointCloud(result, *cloud_temp);

	//可视化输入点云和关键点
	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();
	}

	return 0;
}

3.Harris关键点提取

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/visualization/pcl_visualizer.h>
#include<pcl/keypoints/harris_3D.h>

int main(int argc, char* argv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile("./roorm.pcd", *input_cloud);
	pcl::PCDWriter writer;
	float r_normal=0.1;
	float r_keypoint=0.1;

	//包含强度信息
	pcl::PointCloud<pcl::PointXYZI>::Ptr Harris_keypoints(new pcl::PointCloud<pcl::PointXYZI>);
	pcl::HarrisKeypoint3D<pcl::PointXYZ,pcl::PointXYZI,pcl::Normal>* harris_detector=new  pcl::HarrisKeypoint3D<pcl::PointXYZ, pcl::PointXYZI, pcl::Normal>;
	harris_detector->setRadius(r_normal);//设置法向量估计的半径
	harris_detector->setRadiusSearch(r_keypoint);//设置关键点估计的近邻搜索半径
	harris_detector->setInputCloud(input_cloud);
	harris_detector->compute(*Harris_keypoints);

	cout << "Harris_keypoints的大小是" << Harris_keypoints->size() << endl;
	writer.write<pcl::PointXYZI>("Harris_keypoints.pcd", *Harris_keypoints, false);

	pcl::visualization::PCLVisualizer visu3("clouds");
	visu3.setBackgroundColor(255, 255, 255);
	visu3.addPointCloud(Harris_keypoints, pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZI>(Harris_keypoints, 0.0, 0.0, 255.0), "Harris_keypoints");
	visu3.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 8, "Harris_keypoints");
	visu3.addPointCloud(input_cloud, "input_cloud");
	visu3.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 0, 0, "input_cloud");
	visu3.initCameraParameters();
	visu3.spin();

}

参考

1.https://pcl.readthedocs.io/projects/tutorials/en/latest/index.html#keypoints