#include
#include
#include
#include
#include //使用OMP需要添加的头文件
#include
#include
#include
#include // 直方图的可视化
#include
#include
using namespace std;
int main()
{
//------------------加载点云数据-----------------
pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
if (pcl::io::loadPCDFile("pcd/pig_view1.pcd", *cloud) == -1)//需使用绝对路径
{
PCL_ERROR("Could not read file\n");
}
//--------------------计算法线------------------
pcl::NormalEstimationOMP n;//OMP加速
pcl::PointCloud::Ptr normals(new pcl::PointCloud);
//建立kdtree来进行近邻点集搜索
pcl::search::KdTree::Ptr tree(new pcl::search::KdTree);
n.setNumberOfThreads(8);//设置openMP的线程数
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(10);
n.compute(*normals);//开始进行法向计算
// ------------------3DSC图像计算------------------
pcl::ShapeContext3DEstimation sc;
sc.setInputCloud(cloud);
sc.setInputNormals(normals);
sc.setSearchMethod(tree);
sc.setMinimalRadius(4);
sc.setPointDensityRadius(8);
pcl::PointCloud< pcl::ShapeContext1980>::Ptr dsc_images(new pcl::PointCloud< pcl::ShapeContext1980>);
sc.setRadiusSearch(40);
sc.compute(*dsc_images);
cout << "3DSC图像计算计算完成" << endl;
// 显示和检索第一点的自旋图像描述符向量。
pcl::ShapeContext1980 first_descriptor = dsc_images->points[0];
cout << first_descriptor << endl;
pcl::PointCloud>::Ptr histograms(new pcl::PointCloud>);
// Accumulate histograms
for (int i = 0; i < dsc_images->size(); ++i) {
pcl::Histogram<1980> aggregated_histogram;
for (int j = 0; j < 1980; ++j) {
aggregated_histogram.histogram[j] = (*dsc_images)[i].descriptor[j];
}
histograms->push_back(aggregated_histogram);
}
pcl::visualization::PCLPlotter plotter;
plotter.addFeatureHistogram(*histograms,1980); //设置的横坐标长度,该值越大,则显示的越细致
plotter.setWindowName("3DSC Image");
plotter.plot();
return 0;
}
pcl::NormalEstimationOMP n;//OMP加速
pcl::PointCloud::Ptr normals(new pcl::PointCloud);
//建立kdtree来进行近邻点集搜索
pcl::search::KdTree::Ptr tree(new pcl::search::KdTree);
n.setNumberOfThreads(8);//设置openMP的线程数
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(10);
n.compute(*normals);
pcl::NormalEstimationOMP
:
pcl::NormalEstimationOMP
是一个用于估计点云法线的类,它利用了 OpenMP 进行多线程加速。
指定输入点云类型为 pcl::PointXYZ
,输出法线类型为 pcl::Normal
。pcl::PointCloud
:
pcl::search::KdTree
:
pcl::search::KdTree
指定了 KdTree 使用的点类型。n.setNumberOfThreads(8);
:
n.setInputCloud(cloud);
:
n.setSearchMethod(tree);
:
n.setKSearch(10);
:
n.compute(*normals);
:
normals
指向的点云中。参数设置及其影响:
setNumberOfThreads(int num_threads)
:通过设置并行计算线程数,可以加快法线估计的速度。但是,设置的线程数应该根据计算机的硬件配置来调整,过多的线程可能会造成资源浪费。setKSearch(int k)
:决定了估计每个点法线时考虑的最近邻点的数量。更大的值将考虑更多的邻居,这可能导致更平滑的法线估计,但也可能增加计算时间。 pcl::ShapeContext3DEstimation sc;
sc.setInputCloud(cloud);
sc.setInputNormals(normals);
sc.setSearchMethod(tree);
sc.setMinimalRadius(4);
sc.setPointDensityRadius(8);
pcl::PointCloud< pcl::ShapeContext1980>::Ptr dsc_images(new pcl::PointCloud< pcl::ShapeContext1980>);
sc.setRadiusSearch(40);
// 计算spin image图像
sc.compute(*dsc_images);
pcl::ShapeContext3DEstimation
:
pcl::ShapeContext3DEstimation
类的对象 sc
,用于计算形状上下文。pcl::PointXYZ
指定了输入点云的类型。pcl::Normal
指定了输入点云的法线类型。pcl::ShapeContext1980
指定了形状上下文的类型。sc.setInputCloud(cloud);
:
sc.setInputNormals(normals);
:
sc.setSearchMethod(tree);
:
sc.setMinimalRadius(4);
:
sc.setPointDensityRadius(8);
:
pcl::PointCloud< pcl::ShapeContext1980>::Ptr dsc_images(new pcl::PointCloud< pcl::ShapeContext1980>);
:
sc.setRadiusSearch(40);
:
sc.compute(*dsc_images);
:
dsc_images
指向的点云中。参数设置及其影响:
setMinimalRadius(double radius)
:设置形状上下文计算中的最小半径。较小的值可能导致更精细的形状描述,但也可能增加计算开销。setPointDensityRadius(double radius)
:设置用于计算形状上下文时的点密度半径。较大的值将考虑更广泛的区域,可能导致更全局的形状描述。setRadiusSearch(double radius)
:设置形状上下文计算中的搜索半径。较大的值将考虑更广泛的邻域,但可能会增加计算时间。 pcl::PointCloud>::Ptr histograms(new pcl::PointCloud>);
// Accumulate histograms
for (int i = 0; i < dsc_images->size(); ++i) {
pcl::Histogram<1980> aggregated_histogram;
for (int j = 0; j < 1980; ++j) {
aggregated_histogram.histogram[j] = (*dsc_images)[i].descriptor[j];
}
histograms->push_back(aggregated_histogram);
}
pcl::PointCloud
:
for (int i = 0; i < dsc_images->size(); ++i) {
:
pcl::Histogram<1980> aggregated_histogram;
:
for (int j = 0; j < 1980; ++j) {
:
aggregated_histogram.histogram[j] = (*dsc_images)[i].descriptor[j];
:
histograms->push_back(aggregated_histogram);
:
参数设置及其影响:
1980
表示每个形状上下文描述符的维度。这个值应与前面计算形状上下文时所使用的描述符类型中的维度相匹配。注意:运行速度很慢
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef pcl::PointCloud pointcloud;
typedef pcl::PointCloud pointnormal;
typedef pcl::PointCloud DSCFeature;
DSCFeature::Ptr compute_pfh_feature(pointcloud::Ptr input_cloud, pcl::search::KdTree::Ptr tree)
{
pointnormal::Ptr normals(new pointnormal);
pcl::NormalEstimationOMP n;
n.setInputCloud(input_cloud);
n.setNumberOfThreads(5);
n.setSearchMethod(tree);
n.setKSearch(10);
n.compute(*normals);
pcl::PointCloud::Ptr dsc_fe_dsc(new pcl::PointCloud());
pcl::ShapeContext3DEstimation sc;
sc.setInputCloud(input_cloud);
sc.setInputNormals(normals);
//kdTree加速
sc.setSearchMethod(tree);
sc.setMinimalRadius(4); // 搜索球面(Rmin)的最小半径值。
sc.setRadiusSearch(40); // 设置用于确定用于特征估计的最近邻居的球体半径。
sc.setPointDensityRadius(8);// 这个半径用于计算局部点密度=这个半径内的点数。
sc.compute(*dsc_fe_dsc);
return dsc_fe_dsc;
}
void extract_keypoint(pcl::PointCloud::Ptr& cloud, pcl::PointCloud::Ptr& keypoint)
{
pcl::ISSKeypoint3D iss;
pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
iss.setInputCloud(cloud);
iss.setSearchMethod(tree);
iss.setNumberOfThreads(8); //初始化调度器并设置要使用的线程数
iss.setSalientRadius(5); // 设置用于计算协方差矩阵的球邻域半径
iss.setNonMaxRadius(5); // 设置非极大值抑制应用算法的半径
iss.setThreshold21(0.95); // 设定第二个和第一个特征值之比的上限
iss.setThreshold32(0.95); // 设定第三个和第二个特征值之比的上限
iss.setMinNeighbors(6); // 在应用非极大值抑制算法时,设置必须找到的最小邻居数
iss.compute(*keypoint);
}
int main(int argc, char** argv)
{
pointcloud::Ptr source_cloud(new pointcloud);
pointcloud::Ptr target_cloud(new pointcloud);
pcl::io::loadPCDFile("pcd/pig_view1.pcd", *source_cloud);
pcl::io::loadPCDFile("pcd/pig_view2.pcd", *target_cloud);
pcl::PointCloud::Ptr s_k(new pcl::PointCloud);
pcl::PointCloud::Ptr t_k(new pcl::PointCloud);
extract_keypoint(source_cloud, s_k);
extract_keypoint(target_cloud, t_k);
pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
DSCFeature::Ptr source_pfh = compute_pfh_feature(s_k, tree);
DSCFeature::Ptr target_pfh = compute_pfh_feature(t_k, tree);
pcl::registration::CorrespondenceEstimation crude_cor_est;
boost::shared_ptr cru_correspondences(new pcl::Correspondences);
crude_cor_est.setInputSource(source_pfh);
crude_cor_est.setInputTarget(target_pfh);
crude_cor_est.determineCorrespondences(*cru_correspondences);
Eigen::Matrix4f Transform = Eigen::Matrix4f::Identity();
pcl::registration::TransformationEstimationSVD::Ptr trans(new pcl::registration::TransformationEstimationSVD);
trans->estimateRigidTransformation(*source_cloud, *target_cloud, *cru_correspondences, Transform);
boost::shared_ptrviewer(new pcl::visualization::PCLVisualizer("v1"));
viewer->setBackgroundColor(0, 0, 0);
pcl::visualization::PointCloudColorHandlerCustomtarget_color(target_cloud, 255, 0, 0);
viewer->addPointCloud(target_cloud, target_color, "target cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");
pcl::visualization::PointCloudColorHandlerCustominput_color(source_cloud, 0, 255, 0);
viewer->addPointCloud(source_cloud, input_color, "input cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "input cloud");
viewer->addCorrespondences(s_k, t_k, *cru_correspondences, "correspondence");
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
pcl::registration::CorrespondenceEstimation crude_cor_est;
boost::shared_ptr cru_correspondences(new pcl::Correspondences);
crude_cor_est.setInputSource(source_pfh);
crude_cor_est.setInputTarget(target_pfh);
crude_cor_est.determineCorrespondences(*cru_correspondences);
Eigen::Matrix4f Transform = Eigen::Matrix4f::Identity();
pcl::registration::TransformationEstimationSVD::Ptr trans(new pcl::registration::TransformationEstimationSVD);
trans->estimateRigidTransformation(*source_cloud, *target_cloud, *cru_correspondences, Transform);
pcl::registration::CorrespondenceEstimation
:
pcl::ShapeContext1980
。boost::shared_ptr
:
crude_cor_est.setInputSource(source_pfh);
和 crude_cor_est.setInputTarget(target_pfh);
:
source_pfh
和 target_pfh
应该是已经计算好的形状上下文描述符,参数的设置会直接影响到配准的准确度和鲁棒性。crude_cor_est.determineCorrespondences(*cru_correspondences);
:
cru_correspondences
中。Eigen::Matrix4f Transform = Eigen::Matrix4f::Identity();
:
pcl::registration::TransformationEstimationSVD
:
pcl::PointXYZ
表示点的类型,可以根据实际情况选择合适的点类型,例如 pcl::PointNormal
或者 pcl::PointXYZRGB
等,以确保变换估计的准确性。trans->estimateRigidTransformation(*source_cloud, *target_cloud, *cru_correspondences, Transform);
:
#include
#include
#include
#include
#include
#include
#include
#include // 采取固定数量的点云
#include // 采样一致性
#include // icp配准
#include
#include // 可视化
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud PointCloud;
void extract_keypoint(pcl::PointCloud::Ptr& cloud, pcl::PointCloud::Ptr& keypoint)
{
pcl::ISSKeypoint3D iss;
pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
iss.setInputCloud(cloud);
iss.setSearchMethod(tree);
iss.setNumberOfThreads(8); //初始化调度器并设置要使用的线程数
iss.setSalientRadius(7); // 设置用于计算协方差矩阵的球邻域半径
iss.setNonMaxRadius(5); // 设置非极大值抑制应用算法的半径
iss.setThreshold21(0.95); // 设定第二个和第一个特征值之比的上限
iss.setThreshold32(0.95); // 设定第三个和第二个特征值之比的上限
iss.setMinNeighbors(6); // 在应用非极大值抑制算法时,设置必须找到的最小邻居数
iss.compute(*keypoint);
}
// 点云可视化
void visualize_pcd(PointCloud::Ptr pcd_src, PointCloud::Ptr pcd_tgt)
{
//创建初始化目标
pcl::visualization::PCLVisualizer viewer("registration Viewer");
pcl::visualization::PointCloudColorHandlerCustom src_h(pcd_src, 0, 255, 0);
pcl::visualization::PointCloudColorHandlerCustom tgt_h(pcd_tgt, 255, 0, 0);
viewer.setBackgroundColor(0, 0, 0);
viewer.addPointCloud(pcd_src, src_h, "source cloud");
viewer.addPointCloud(pcd_tgt, tgt_h, "tgt cloud");
while (!viewer.wasStopped())
{
viewer.spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(1000));
}
}
// 计算特征点的3DSC描述子
void computeKeyPoints3DSC(PointCloud::Ptr& cloud_in, PointCloud::Ptr& key_cloud, pcl::PointCloud::Ptr& dsc)
{
//------------------计算法线----------------------
pcl::NormalEstimationOMP n;//OMP加速
pcl::PointCloud::Ptr normals(new pcl::PointCloud);
//建立kdtree来进行近邻点集搜索
pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
n.setNumberOfThreads(6);//设置openMP的线程数
n.setInputCloud(key_cloud);
n.setSearchSurface(cloud_in);
n.setSearchMethod(tree);
n.setKSearch(20);
//n.setRadiusSearch(0.03);//半径搜素
n.compute(*normals);
cout << "法线计算完毕!!!" << endl;
//-------------------计算3dsc-----------------------
pcl::ShapeContext3DEstimation sc;
sc.setInputCloud(key_cloud);
sc.setInputNormals(normals);
//kdTree加速
sc.setSearchMethod(tree);
sc.setMinimalRadius(4); // 搜索球面(Rmin)的最小半径值。
sc.setRadiusSearch(40); // 设置用于确定用于特征估计的最近邻居的球体半径。
sc.setPointDensityRadius(8);// 这个半径用于计算局部点密度=这个半径内的点数。
sc.compute(*dsc);
cout << "3DSC特征描述子计算完毕!!!" << endl;
}
int main(int argc, char** argv)
{
// 加载点云文件
PointCloud::Ptr source(new PointCloud); // 源点云,待配准
pcl::io::loadPCDFile("pcd/pig_view1.pcd", *source);
PointCloud::Ptr target(new PointCloud); // 目标点云
pcl::io::loadPCDFile("pcd/pig_view2.pcd", *target);
PointCloud::Ptr key_src(new PointCloud);
PointCloud::Ptr key_tgt(new PointCloud);
extract_keypoint(source, key_src);
extract_keypoint(target, key_tgt);
//计算3dsc
pcl::PointCloud::Ptr sps_src(new pcl::PointCloud());
pcl::PointCloud::Ptr sps_tgt(new pcl::PointCloud());
computeKeyPoints3DSC(source, key_src, sps_src);
computeKeyPoints3DSC(target, key_tgt, sps_tgt);
//SAC配准
pcl::SampleConsensusInitialAlignment scia;
scia.setInputSource(key_src);
scia.setInputTarget(key_tgt);
scia.setSourceFeatures(sps_src);
scia.setTargetFeatures(sps_tgt);
scia.setMinSampleDistance(7); // 设置样本之间的最小距离
scia.setNumberOfSamples(100); // 设置每次迭代计算中使用的样本数量(可省),可节省时间
scia.setCorrespondenceRandomness(6);// 在选择随机特征对应时,设置要使用的邻居的数量;
PointCloud::Ptr sac_result(new PointCloud);
scia.align(*sac_result);
std::cout << "sac has converged:" << scia.hasConverged() << " score: " << scia.getFitnessScore() << endl;
Eigen::Matrix4f sac_trans;
sac_trans = scia.getFinalTransformation();
std::cout << sac_trans << endl;
//icp配准
PointCloud::Ptr icp_result(new PointCloud);
pcl::IterativeClosestPoint icp;
icp.setInputSource(key_src);
icp.setInputTarget(key_tgt);
icp.setMaxCorrespondenceDistance(20);
icp.setMaximumIterations(35); // 最大迭代次数
icp.setTransformationEpsilon(1e-10); // 两次变化矩阵之间的差值
icp.setEuclideanFitnessEpsilon(0.01);// 均方误差
icp.align(*icp_result, sac_trans);
cout << "ICP has converged:" << icp.hasConverged() << " score: " << icp.getFitnessScore() << endl;
Eigen::Matrix4f icp_trans;
icp_trans = icp.getFinalTransformation();
cout << icp_trans << endl;
//使用创建的变换对未过滤的输入点云进行变换
pcl::transformPointCloud(*source, *icp_result, icp_trans);
//可视化
visualize_pcd(icp_result, target);
return (0);
}
我之前在iss关键点检测以及SAC-IA粗配准-CSDN博客
和Spin Image自旋图像描述符可视化以及ICP配准-CSDN博客以及本章第一部分已经解释了大部分函数,这里就不赘述了
配准结果,程序运行很慢,要等好久好久,可以适当调整参数,加快速度