PCL点云的特征点提取同名点匹配并进行配准并附上代码
以下是基于PCL库实现PCL点云特征点提取、同名点匹配和配准的代码示例:
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
#include <pcl/registration/ndt.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/fpfh.h>
#include <pcl/visualization/pcl_visualizer.h>
int main(int argc, char** argv)
{
// Load point clouds
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_source(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile<pcl::PointXYZ>("source.pcd", *cloud_source);
pcl::io::loadPCDFile<pcl::PointXYZ>("target.pcd", *cloud_target);
// Compute surface normals
pcl::PointCloud<pcl::Normal>::Ptr normals_source(new pcl::PointCloud<pcl::Normal>);
pcl::PointCloud<pcl::Normal>::Ptr normals_target(new pcl::PointCloud<pcl::Normal>);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setSearchMethod(tree);
ne.setInputCloud(cloud_source);
ne.setKSearch(20);
ne.compute(*normals_source);
ne.setInputCloud(cloud_target);
ne.compute(*normals_target);
// Compute FPFH features
pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfhs_source(new pcl::PointCloud<pcl::FPFHSignature33>);
pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfhs_target(new pcl::PointCloud<pcl::FPFHSignature33>);
pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh;
fpfh.setSearchMethod(tree);
fpfh.setInputCloud(cloud_source);
fpfh.setInputNormals(normals_source);
fpfh.setRadiusSearch(0.5);
fpfh.compute(*fpfhs_source);
fpfh.setInputCloud(cloud_target);
fpfh.setInputNormals(normals_target);
fpfh.compute(*fpfhs_target);
// Find correspondences
pcl::CorrespondencesPtr correspondences(new pcl::Correspondences);
pcl::registration::CorrespondenceEstimation<pcl::FPFHSignature33, pcl::FPFHSignature33> est;
est.setInputSource(fpfhs_source);
est.setInputTarget(fpfhs_target);
est.determineCorrespondences(*correspondences);
// Reject correspondences based on distance and angle
pcl::CorrespondencesPtr correspondences_filtered(new pcl::Correspondences);
for (int i = 0; i < correspondences->size(); i++)
{
float dist = pcl::geometry::distance(cloud_source->at(correspondences->at(i).index_query),
cloud_target->at(correspondences->at(i).index_match));
float angle = pcl::geometry::acos3(cloud_source->at(correspondences->at(i).index_query).getNormalVector3fMap(),
cloud_target->at(correspondences->at(i).index_match).getNormalVector3fMap());
if (dist < 0.5 && angle < pcl::deg2rad(30))
{
correspondences_filtered->push_back(correspondences->at(i));
}
}
// Visualize correspondences
pcl::visualization::PCLVisualizer viewer("Correspondences");
viewer.addPointCloud(cloud_source, "cloud_source");
viewer.addPointCloud(cloud_target, "cloud_target");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "cloud_source");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1, 0, "cloud_target");
for (int i = 0; i < correspondences_filtered->size(); i++)
{
pcl::PointXYZ& p1 = cloud_source->at(correspondences_filtered->at(i).index_query);
pcl::PointXYZ& p2 = cloud_target->at(correspondences_filtered->at(i).index_match);
std::stringstream ss;
ss << "correspondence_" << i;
viewer.addLine(p1, p2, 1, 1, 1, ss.str());
}
viewer.spin();
// Perform ICP registration
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_source_registered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
icp.setInputSource(cloud_source);
icp.setInputTarget(cloud_target);
icp.setCorrespondenceEstimation(new pcl::registration::CorrespondenceEstimationBackProjection<pcl::PointXYZ, pcl::PointXYZ>);
icp.setCorrespondences(correspondences_filtered);
icp.setMaximumIterations(100);
icp.setTransformationEpsilon(1e-8);
icp.setEuclideanFitnessEpsilon(1e-6);
icp.align(*cloud_source_registered);
// Visualize registration result
pcl::visualization::PCLVisualizer viewer2("Registration Result");
viewer2.addPointCloud(cloud_source_registered, "cloud_source_registered");
viewer2.addPointCloud(cloud_target, "cloud_target");
viewer2.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "cloud_source_registered");
viewer2.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1, 0, "cloud_target");
viewer2.spin();
return 0;
}
以上代码实现了以下功能:
- 加载源点云和目标点云;
- 计算点云表面法向量和FPFH特征;
- 找到特征点之间的对应关系;
- 根据距离和角度过滤对应关系;
- 可视化对应关系;
- 使用ICP算法进行点云配准;
- 可视化配准结果。
需要注意的是,以上代码中的ICP算法使用了BackProjection方式的对应关系估计方法,这种方法可以提高ICP算法的收敛速度和精度。如果需要更高的精度,可以使用NDT算法代替ICP算法进行配准
原文地址: http://www.cveoy.top/t/topic/crYW 著作权归作者所有。请勿转载和采集!