解析
同时调用 setInputCorrespondences()
和 getCorrespondences()
相当于调用 getRemainingCorrespondences()
。
以下两段代码对于同一点云数据计算得到的结果是相同的。
pcl::registration::CorrespondenceRejectorSurfaceNormal rejector;
rejector.initializeDataContainer<pcl::PointNormal, pcl::PointNormal>();// 初始化点类型和普通类型的数据容器对象
rejector.setInputSource<pcl::PointNormal>(source_normals);
rejector.setInputTarget<pcl::PointNormal>(target_normals);
rejector.setInputNormals<pcl::PointNormal, pcl::PointNormal>(source_normals);
rejector.setTargetNormals<pcl::PointNormal, pcl::PointNormal>(target_normals);
float threshold = cos(M_PI * 10 / 180);//计算cos(10°)
rejector.setThreshold(threshold); // 设置法线之间的夹角阈值,输入的是夹角余弦值
boost::shared_ptr<pcl::Correspondences> correspondences_after_rejector(new pcl::Correspondences);
rejector.getRemainingCorrespondences(*all_correspondences, *correspondences_after_rejector);
pcl::registration::CorrespondenceRejectorSurfaceNormal rejector;
rejector.initializeDataContainer<pcl::PointNormal, pcl::PointNormal>();// 初始化点类型和普通类型的数据容器对象
rejector.setInputSource<pcl::PointNormal>(source_normals);
rejector.setInputTarget<pcl::PointNormal>(target_normals);
rejector.setInputNormals<pcl::PointNormal, pcl::PointNormal>(source_normals);
rejector.setTargetNormals<pcl::PointNormal, pcl::PointNormal>(target_normals);
rejector.setInputCorrespondences(all_correspondences);
float threshold = cos(M_PI * 10 / 180);//计算cos(10°)
rejector.setThreshold(threshold); // 设置法线之间的夹角阈值,输入的是夹角余弦值
pcl::CorrespondencesPtr correspondences_after_rejector(new pcl::Correspondences);
rejector.getCorrespondences(*correspondences_after_rejector);
源码
/*
* @Auther: 宇宙爆肝锦标赛冠军
* @Date: 2022-09-05 09:37:42
* @LastEditors: 宇宙爆肝锦标赛冠军
* @LastEditTime: 2022-09-05 09:40:09
* @Description: PCL 法向量夹角剔除错误匹配点对 https://blog.csdn.net/qq_36686437/article/details/115140916
*/
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/registration/correspondence_estimation_normal_shooting.h>
#include <pcl/registration/correspondence_rejection_surface_normal.h>
#include <pcl/registration/transformation_estimation_lm.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
using namespace std;
void compute_normal(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointNormal>::Ptr& normals)
{
pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::PointNormal> n;//OMP加速
//建立kdtree来进行近邻点集搜索
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
n.setNumberOfThreads(6);//设置openMP的线程数
//n.setViewPoint(0,0,0);//设置视点,默认为(0,0,0)
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(10);//点云法向计算时,需要所搜的近邻点大小
//n.setRadiusSearch(0.03);//半径搜素
n.compute(*normals);//开始进行法向计
}
int
main(int argc, char** argv)
{
// 加载目标点云
pcl::PointCloud<pcl::PointXYZ>::Ptr target(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *target) == -1)
{
PCL_ERROR("读取目标点云失败 \n");
return (-1);
}
cout << "从目标点云中读取 " << target->size() << " 个点" << endl;
// ----------------------加载源点云-----------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr source(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[2], *source) == -1)
{
PCL_ERROR("读取源标点云失败 \n");
return (-1);
}
cout << "从源点云中读取 " << source->size() << " 个点" << endl;
//-------------------------法线估计--------------------------
pcl::PointCloud<pcl::PointNormal>::Ptr source_normals(new pcl::PointCloud<pcl::PointNormal>);
compute_normal(source,source_normals);
pcl::PointCloud<pcl::PointNormal>::Ptr target_normals(new pcl::PointCloud<pcl::PointNormal>);
compute_normal(target, target_normals);
//----------------------获取匹配点对-------------------------
pcl::registration::CorrespondenceEstimationNormalShooting<pcl::PointXYZ, pcl::PointXYZ, pcl::PointNormal>core;
core.setInputSource(source);
core.setSourceNormals(source_normals);
core.setInputTarget(target);
core.setKSearch(10);
pcl::CorrespondencesPtr all_correspondences(new pcl::Correspondences);
core.determineCorrespondences(*all_correspondences, 10);//输入的是源点云上法线与目标点云上对应点之间的最大距离
//core.determineReciprocalCorrespondences(*all_correspondences); //确定输入点云与目标点云之间的交互对应关系。
//-------------------剔除错误匹配点对-----------------------
pcl::registration::CorrespondenceRejectorSurfaceNormal rejector;
rejector.initializeDataContainer<pcl::PointNormal, pcl::PointNormal>();// 初始化点类型和普通类型的数据容器对象
rejector.setInputSource<pcl::PointNormal>(source_normals);
rejector.setInputTarget<pcl::PointNormal>(target_normals);
rejector.setInputNormals<pcl::PointNormal, pcl::PointNormal>(source_normals);
rejector.setTargetNormals<pcl::PointNormal, pcl::PointNormal>(target_normals);
rejector.setInputCorrespondences(all_correspondences);
float threshold = cos(M_PI * 10 / 180);//计算cos(10°)
rejector.setThreshold(threshold); // 设置法线之间的夹角阈值,输入的是夹角余弦值
pcl::CorrespondencesPtr correspondences_after_rejector(new pcl::Correspondences);
rejector.getCorrespondences(*correspondences_after_rejector);
//cout << "Correspondences (After) : " << correspondences_after_rejector->size() << "\n";
Eigen::Matrix4f transformation = Eigen::Matrix4f::Identity();
pcl::registration::TransformationEstimationLM<pcl::PointXYZ, pcl::PointXYZ> trans_est_lm;
trans_est_lm.estimateRigidTransformation(*source, *target, *correspondences_after_rejector, transformation);
pcl::PointCloud<pcl::PointXYZ>::Ptr out(new pcl::PointCloud<pcl::PointXYZ>);
pcl::transformPointCloud(*source, *out, transformation);
pcl::io::savePCDFile("left.pcd", *out);
cout << "原始匹配点对有:" << all_correspondences->size() << "对" << endl;
cout << "剔除错误点对后有:" << correspondences_after_rejector->size() << "对" << endl;
cout <<"LM求解的变换矩阵为:\n"<< transformation << endl;
//---------------------------可视化-------------------------
boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer("显示点云"));
viewer->setBackgroundColor(0, 0, 0); //设置背景颜色为黑色
// 对源点云着色可视化 (green).
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color(source, 0, 255, 0);
viewer->addPointCloud<pcl::PointXYZ>(source, input_color, "source");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "source");
// 对目标点云着色可视化 (red).
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color(target, 255, 0, 0);
viewer->addPointCloud<pcl::PointXYZ>(target, target_color, "target");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target");
//----------------------对应关系可视化---------------------
viewer->addCorrespondences<pcl::PointXYZ>(source, target, *correspondences_after_rejector, "correspondence");
viewer->initCameraParameters();
viewer->addText("RejectorSurfaceNormal", 10, 10, "text");
viewer->spin();
return 0;
}
/*
* @Auther: 宇宙爆肝锦标赛冠军
* @Date: 2022-09-05 14:29:02
* @LastEditors: 宇宙爆肝锦标赛冠军
* @LastEditTime: 2022-09-05 14:30:20
* @Description: 调用其他函数,测试效果是否相同
*/
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/registration/correspondence_estimation_normal_shooting.h>
#include <pcl/registration/correspondence_rejection_surface_normal.h>
#include <pcl/registration/transformation_estimation_lm.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
using namespace std;
void compute_normal(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointNormal>::Ptr& normals)
{
pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::PointNormal> n;//OMP加速
//建立kdtree来进行近邻点集搜索
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
n.setNumberOfThreads(6);//设置openMP的线程数
//n.setViewPoint(0,0,0);//设置视点,默认为(0,0,0)
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(10);//点云法向计算时,需要所搜的近邻点大小
//n.setRadiusSearch(0.03);//半径搜素
n.compute(*normals);//开始进行法向计
}
int
main(int argc, char** argv)
{
// 加载目标点云
pcl::PointCloud<pcl::PointXYZ>::Ptr target(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *target) == -1)
{
PCL_ERROR("读取目标点云失败 \n");
return (-1);
}
cout << "从目标点云中读取 " << target->size() << " 个点" << endl;
// ----------------------加载源点云-----------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr source(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[2], *source) == -1)
{
PCL_ERROR("读取源标点云失败 \n");
return (-1);
}
cout << "从源点云中读取 " << source->size() << " 个点" << endl;
//-------------------------法线估计--------------------------
pcl::PointCloud<pcl::PointNormal>::Ptr source_normals(new pcl::PointCloud<pcl::PointNormal>);
compute_normal(source,source_normals);
pcl::PointCloud<pcl::PointNormal>::Ptr target_normals(new pcl::PointCloud<pcl::PointNormal>);
compute_normal(target, target_normals);
//----------------------获取匹配点对-------------------------
pcl::registration::CorrespondenceEstimationNormalShooting<pcl::PointXYZ, pcl::PointXYZ, pcl::PointNormal>core;
core.setInputSource(source);
core.setSourceNormals(source_normals);
core.setInputTarget(target);
core.setKSearch(10);
boost::shared_ptr<pcl::Correspondences> all_correspondences(new pcl::Correspondences);
core.determineCorrespondences(*all_correspondences, 10);//输入的是源点云上法线与目标点云上对应点之间的最大距离
//core.determineReciprocalCorrespondences(*all_correspondences); //确定输入点云与目标点云之间的交互对应关系。
//-------------------剔除错误匹配点对-----------------------
pcl::registration::CorrespondenceRejectorSurfaceNormal rejector;
rejector.initializeDataContainer<pcl::PointNormal, pcl::PointNormal>();// 初始化点类型和普通类型的数据容器对象
rejector.setInputSource<pcl::PointNormal>(source_normals);
rejector.setInputTarget<pcl::PointNormal>(target_normals);
rejector.setInputNormals<pcl::PointNormal, pcl::PointNormal>(source_normals);
rejector.setTargetNormals<pcl::PointNormal, pcl::PointNormal>(target_normals);
// rejector.setInputCorrespondences(all_correspondences);
float threshold = cos(M_PI * 10 / 180);//计算cos(10°)
rejector.setThreshold(threshold); // 设置法线之间的夹角阈值,输入的是夹角余弦值
boost::shared_ptr<pcl::Correspondences> correspondences_after_rejector(new pcl::Correspondences);
// rejector.getCorrespondences(*correspondences_after_rejector);
rejector.getRemainingCorrespondences(*all_correspondences, *correspondences_after_rejector);
//cout << "Correspondences (After) : " << correspondences_after_rejector->size() << "\n";
Eigen::Matrix4f transformation = Eigen::Matrix4f::Identity();
pcl::registration::TransformationEstimationLM<pcl::PointXYZ, pcl::PointXYZ> trans_est_lm;
trans_est_lm.estimateRigidTransformation(*source, *target, *correspondences_after_rejector, transformation);
pcl::PointCloud<pcl::PointXYZ>::Ptr out(new pcl::PointCloud<pcl::PointXYZ>);
pcl::transformPointCloud(*source, *out, transformation);
pcl::io::savePCDFile("left.pcd", *out);
cout << "原始匹配点对有:" << all_correspondences->size() << "对" << endl;
cout << "剔除错误点对后有:" << correspondences_after_rejector->size() << "对" << endl;
cout <<"LM求解的变换矩阵为:\n"<< transformation << endl;
//---------------------------可视化-------------------------
boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer("显示点云"));
viewer->setBackgroundColor(0, 0, 0); //设置背景颜色为黑色
// 对源点云着色可视化 (green).
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color(source, 0, 255, 0);
viewer->addPointCloud<pcl::PointXYZ>(source, input_color, "source");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "source");
// 对目标点云着色可视化 (red).
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color(target, 255, 0, 0);
viewer->addPointCloud<pcl::PointXYZ>(target, target_color, "target");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target");
//----------------------对应关系可视化---------------------
viewer->addCorrespondences<pcl::PointXYZ>(source, target, *correspondences_after_rejector, "correspondence");
viewer->initCameraParameters();
viewer->addText("RejectorSurfaceNormal", 10, 10, "text");
viewer->spin();
return 0;
}