3DSC特征描述符、对应关系可视化以及ICP配准

一、3DSC特征描述符可视化

C++

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/search/kdtree.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d_omp.h>//使用OMP需要添加的头文件
#include <pcl/features/spin_image.h>
#include <boost/thread/thread.hpp>
#include <pcl/features/3dsc.h>
#include <pcl/visualization/pcl_plotter.h>// 直方图的可视化 
#include <pcl/visualization/histogram_visualizer.h>
#include <pcl/kdtree/kdtree_flann.h>
using namespace std;
int main()
{//------------------加载点云数据-----------------pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view1.pcd", *cloud) == -1)//需使用绝对路径{PCL_ERROR("Could not read file\n");}//--------------------计算法线------------------pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;//OMP加速pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//建立kdtree来进行近邻点集搜索pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);n.setNumberOfThreads(8);//设置openMP的线程数n.setInputCloud(cloud);n.setSearchMethod(tree);n.setKSearch(10);n.compute(*normals);//开始进行法向计算// ------------------3DSC图像计算------------------pcl::ShapeContext3DEstimation<pcl::PointXYZ, pcl::Normal, pcl::ShapeContext1980> 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<pcl::Histogram<1980>>::Ptr histograms(new pcl::PointCloud<pcl::Histogram<1980>>);// Accumulate histogramsfor (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<pcl::PointXYZ, pcl::Normal> n;//OMP加速pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//建立kdtree来进行近邻点集搜索pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);n.setNumberOfThreads(8);//设置openMP的线程数n.setInputCloud(cloud);n.setSearchMethod(tree);n.setKSearch(10);n.compute(*normals);
  1. pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;

    • pcl::NormalEstimationOMP 是一个用于估计点云法线的类,它利用了 OpenMP 进行多线程加速。
    • <pcl::PointXYZ, pcl::Normal> 指定输入点云类型为 pcl::PointXYZ,输出法线类型为 pcl::Normal
  2. pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

    • 创建了一个指向存储法线的点云的指针。
  3. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);

    • 创建了一个 KdTree 对象,用于近邻搜索。
    • pcl::search::KdTree<pcl::PointXYZ> 指定了 KdTree 使用的点类型。
  4. n.setNumberOfThreads(8);

    • 设置 OpenMP 的线程数为 8。这指定了在计算法线时要使用的并行线程数量。通常,设置为计算机的可用核心数或稍少一些是合理的。
  5. n.setInputCloud(cloud);

    • 设置输入点云,即需要估计法线的点云。
  6. n.setSearchMethod(tree);

    • 设置法线估计中使用的搜索方法,这里使用了建立好的 KdTree。
  7. n.setKSearch(10);

    • 设置用于估计每个点法线的最近邻点的数量。这里设置为 10,表示每个点的法线估计将使用其最近的 10 个邻居。
  8. n.compute(*normals);

    • 执行法线估计。
    • 估计的法线将存储在 normals 指向的点云中。

参数设置及其影响:

  • setNumberOfThreads(int num_threads):通过设置并行计算线程数,可以加快法线估计的速度。但是,设置的线程数应该根据计算机的硬件配置来调整,过多的线程可能会造成资源浪费。
  • setKSearch(int k):决定了估计每个点法线时考虑的最近邻点的数量。更大的值将考虑更多的邻居,这可能导致更平滑的法线估计,但也可能增加计算时间。
	pcl::ShapeContext3DEstimation<pcl::PointXYZ, pcl::Normal, pcl::ShapeContext1980> 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);
  1. pcl::ShapeContext3DEstimation<pcl::PointXYZ, pcl::Normal, pcl::ShapeContext1980> sc;

    • 创建了一个 pcl::ShapeContext3DEstimation 类的对象 sc,用于计算形状上下文。
    • pcl::PointXYZ 指定了输入点云的类型。
    • pcl::Normal 指定了输入点云的法线类型。
    • pcl::ShapeContext1980 指定了形状上下文的类型。
  2. sc.setInputCloud(cloud);

    • 设置输入点云,即待计算形状上下文的点云。
  3. sc.setInputNormals(normals);

    • 设置输入点云的法线。
  4. sc.setSearchMethod(tree);

    • 设置用于形状上下文估计的搜索方法,这里使用了之前建立的 KdTree。
  5. sc.setMinimalRadius(4);

    • 设置形状上下文估计中的最小半径。这个参数决定了形状上下文描述符的大小。较小的值可能导致更精细的形状描述,但也可能增加计算开销。
  6. sc.setPointDensityRadius(8);

    • 设置用于计算点云形状上下文时的点密度半径。这个参数控制着在形状上下文计算中用于描述点云局部形状的密度。较大的值将考虑更广泛的区域,可能导致更全局的形状描述。
  7. pcl::PointCloud< pcl::ShapeContext1980>::Ptr dsc_images(new pcl::PointCloud< pcl::ShapeContext1980>);

    • 创建了一个指向存储形状上下文描述符的点云的指针。
  8. sc.setRadiusSearch(40);

    • 设置用于形状上下文计算的搜索半径。这个参数决定了在形状上下文计算中考虑的邻居点的数量。较大的值将考虑更广泛的邻域,但可能会增加计算时间。
  9. sc.compute(*dsc_images);

    • 执行形状上下文计算。
    • 计算得到的形状上下文描述符将存储在 dsc_images 指向的点云中。

参数设置及其影响:

  • setMinimalRadius(double radius):设置形状上下文计算中的最小半径。较小的值可能导致更精细的形状描述,但也可能增加计算开销。
  • setPointDensityRadius(double radius):设置用于计算形状上下文时的点密度半径。较大的值将考虑更广泛的区域,可能导致更全局的形状描述。
  • setRadiusSearch(double radius):设置形状上下文计算中的搜索半径。较大的值将考虑更广泛的邻域,但可能会增加计算时间。
	pcl::PointCloud<pcl::Histogram<1980>>::Ptr histograms(new pcl::PointCloud<pcl::Histogram<1980>>);// Accumulate histogramsfor (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);}
  1. pcl::PointCloud<pcl::Histogram<1980>>::Ptr histograms(new pcl::PointCloud<pcl::Histogram<1980>>);

    • 创建了一个指向存储直方图的点云的指针。
  2. for (int i = 0; i < dsc_images->size(); ++i) {

    • 循环遍历形状上下文描述符点云中的每个点。
  3. pcl::Histogram<1980> aggregated_histogram;

    • 创建了一个用于存储聚合直方图的对象。
  4. for (int j = 0; j < 1980; ++j) {

    • 循环遍历每个形状上下文描述符的维度。
  5. aggregated_histogram.histogram[j] = (*dsc_images)[i].descriptor[j];

    • 将形状上下文描述符的每个维度的值赋给聚合直方图中对应维度的值。
  6. histograms->push_back(aggregated_histogram);

    • 将聚合后的直方图添加到直方图点云中。

参数设置及其影响:

  • 这段代码中没有涉及显式的参数设置,但是需要注意的是:
    • 1980 表示每个形状上下文描述符的维度。这个值应与前面计算形状上下文时所使用的描述符类型中的维度相匹配。

结果:

注意:运行速度很慢

a0bb3803054a4a2583915abdc3d49a76.png

二、3DSC对应关系可视化

C++

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/registration/correspondence_estimation.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/registration/transformation_estimation_svd.h> 
#include <pcl/features/3dsc.h>
#include <pcl/keypoints/iss_3d.h>
using namespace std;typedef pcl::PointCloud<pcl::PointXYZ> pointcloud;
typedef pcl::PointCloud<pcl::Normal> pointnormal;
typedef pcl::PointCloud<pcl::ShapeContext1980> DSCFeature;DSCFeature::Ptr compute_pfh_feature(pointcloud::Ptr input_cloud, pcl::search::KdTree<pcl::PointXYZ>::Ptr tree)
{pointnormal::Ptr normals(new pointnormal);pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;n.setInputCloud(input_cloud);n.setNumberOfThreads(5);n.setSearchMethod(tree);n.setKSearch(10);n.compute(*normals);pcl::PointCloud<pcl::ShapeContext1980>::Ptr dsc_fe_dsc(new pcl::PointCloud<pcl::ShapeContext1980>());pcl::ShapeContext3DEstimation<pcl::PointXYZ, pcl::Normal, pcl::ShapeContext1980> 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<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& keypoint)
{pcl::ISSKeypoint3D<pcl::PointXYZ, pcl::PointXYZ> iss;pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());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<pcl::PointXYZ>("pcd/pig_view1.pcd", *source_cloud);pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view2.pcd", *target_cloud);pcl::PointCloud<pcl::PointXYZ>::Ptr s_k(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>::Ptr t_k(new pcl::PointCloud<pcl::PointXYZ>);extract_keypoint(source_cloud, s_k);extract_keypoint(target_cloud, t_k);pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());DSCFeature::Ptr source_pfh = compute_pfh_feature(s_k, tree);DSCFeature::Ptr target_pfh = compute_pfh_feature(t_k, tree);pcl::registration::CorrespondenceEstimation<pcl::ShapeContext1980, pcl::ShapeContext1980> crude_cor_est;boost::shared_ptr<pcl::Correspondences> 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<pcl::PointXYZ, pcl::PointXYZ, float>::Ptr trans(new pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ, float>);trans->estimateRigidTransformation(*source_cloud, *target_cloud, *cru_correspondences, Transform);boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer("v1"));viewer->setBackgroundColor(0, 0, 0);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color(target_cloud, 255, 0, 0);viewer->addPointCloud<pcl::PointXYZ>(target_cloud, target_color, "target cloud");viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color(source_cloud, 0, 255, 0);viewer->addPointCloud<pcl::PointXYZ>(source_cloud, input_color, "input cloud");viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "input cloud");viewer->addCorrespondences<pcl::PointXYZ>(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<pcl::ShapeContext1980, pcl::ShapeContext1980> crude_cor_est;boost::shared_ptr<pcl::Correspondences> 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<pcl::PointXYZ, pcl::PointXYZ, float>::Ptr trans(new pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ, float>);trans->estimateRigidTransformation(*source_cloud, *target_cloud, *cru_correspondences, Transform);
  1. pcl::registration::CorrespondenceEstimation<pcl::ShapeContext1980, pcl::ShapeContext1980> crude_cor_est;

    • 创建了一个形状上下文描述符之间的对应估计对象。这里使用的是形状上下文描述符类型 pcl::ShapeContext1980
    • 参数设置影响:这里没有显式地设置参数,但是你可以根据需要调整匹配算法的参数,如距离阈值、特征匹配方式等,以获得更好的配准效果。
  2. boost::shared_ptr<pcl::Correspondences> cru_correspondences(new pcl::Correspondences);

    • 创建了一个存储对应关系的指针,用于存储形状上下文描述符之间的对应关系。
  3. crude_cor_est.setInputSource(source_pfh);crude_cor_est.setInputTarget(target_pfh);

    • 设置了待配准的源点云和目标点云的形状上下文描述符。
    • 参数设置影响:这里的 source_pfh 和 target_pfh 应该是已经计算好的形状上下文描述符,参数的设置会直接影响到配准的准确度和鲁棒性。
  4. crude_cor_est.determineCorrespondences(*cru_correspondences);

    • 执行对应关系的估计,将对应关系存储到 cru_correspondences 中。
    • 参数设置影响:在这一步中,配准的结果受到匹配算法的影响,包括特征匹配的算法、距离阈值等参数设置。
  5. Eigen::Matrix4f Transform = Eigen::Matrix4f::Identity();

    • 创建了一个单位矩阵,用于存储计算得到的变换矩阵。
  6. pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ, float>::Ptr trans(new pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ, float>);

    • 创建了一个利用奇异值分解(SVD)方法估计变换的对象。
    • 参数设置影响:这里的 pcl::PointXYZ 表示点的类型,可以根据实际情况选择合适的点类型,例如 pcl::PointNormal 或者 pcl::PointXYZRGB 等,以确保变换估计的准确性。
  7. trans->estimateRigidTransformation(*source_cloud, *target_cloud, *cru_correspondences, Transform);

    • 使用估计的对应关系和变换方法计算源点云到目标点云的刚性变换。
    • 参数设置影响:这里的参数包括源点云、目标点云、对应关系以及变换矩阵。调整这些参数可以影响配准的结果,如不同的匹配算法、不同的点云特征类型等。

 

结果:

b76e669f624b466698296abd94675bca.png

三、3DSC结合ICP配准

 

C++

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/keypoints/iss_3d.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/features/3dsc.h>
#include <pcl/search/kdtree.h>
#include <pcl/filters/random_sample.h> // 采取固定数量的点云
#include <pcl/registration/ia_ransac.h>// 采样一致性
#include <pcl/registration/icp.h>      // icp配准
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h> // 可视化typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloud;
void extract_keypoint(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& keypoint)
{pcl::ISSKeypoint3D<pcl::PointXYZ, pcl::PointXYZ> iss;pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());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<PointT> src_h(pcd_src, 0, 255, 0);pcl::visualization::PointCloudColorHandlerCustom<PointT> 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<pcl::ShapeContext1980>::Ptr& dsc)
{//------------------计算法线----------------------pcl::NormalEstimationOMP<PointT, pcl::Normal> n;//OMP加速pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//建立kdtree来进行近邻点集搜索pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());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<PointT, pcl::Normal, pcl::ShapeContext1980> 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);//计算3dscpcl::PointCloud<pcl::ShapeContext1980>::Ptr sps_src(new pcl::PointCloud<pcl::ShapeContext1980>());pcl::PointCloud<pcl::ShapeContext1980>::Ptr sps_tgt(new pcl::PointCloud<pcl::ShapeContext1980>());computeKeyPoints3DSC(source, key_src, sps_src);computeKeyPoints3DSC(target, key_tgt, sps_tgt);//SAC配准pcl::SampleConsensusInitialAlignment<PointT, PointT, pcl::ShapeContext1980> 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<PointT, PointT> 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博客以及本章第一部分已经解释了大部分函数,这里就不赘述了

结果:

配准结果,程序运行很慢,要等好久好久,可以适当调整参数,加快速度

2466ce8a268846268cf56df3af6ec61f.png

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/261661.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA领域顶级学术会议

FPGA领域顶级学术会议主要有FPGA,FCCM,FPL和FPT。 1 FPGA 会议全名是: ACM/SIGDA International Symposium on Field-Programmable Gate Arrays 网站是:https://dl.acm.org/conference/fpga FPGA常年在美国举办,每年2月,偏FPGA基础研究; 该会议的论文免费下载。这个比…

(十三)【Jmeter】线程(Threads(Users))之tearDown 线程组

简述 操作路径如下: 作用:在正式测试结束后执行清理操作,如关闭连接、释放资源等。配置:设置清理操作的采样器、执行顺序等参数。使用场景:确保在测试结束后应用程序恢复到正常状态,避免资源泄漏或对其他测试的影响。优点:提供清理操作,确保测试环境的整洁和可重复性…

jvm、jre、jdk的关系

jvm Java 虚拟机&#xff08;JVM&#xff09;是运行 Java 字节码的虚拟机。 jre JRE&#xff08;Java Runtime Environment&#xff09; 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合&#xff0c;主要包括 Java 虚拟机&#xff08;JVM&#xff09;、J…

C++笔记:OOP三大特性之继承

文章目录 一、继承的概念和定义1.1 概念1.2 定义格式1.3 继承关系和访问限定符 二、基类和派生类对象赋值兼容转换2.1 类型转换存在临时对象的意义2.2 赋值兼容转换不会产生临时变量 三、继承中的作用域四、派生类中的默认成员函数4.1 构造4.2 拷贝构造4.3 赋值重载4.4 析构 五…

【Java多线程】分析线程加锁导致的死锁问题以及解决方案

目录 1、线程加锁 2、死锁问题的三种经典场景 2.1、一个线程一把锁 2.2、两个线程两把锁 2.3、N个线程M把锁&#xff08;哲学家就餐问题&#xff09; 3、解决死锁问题 1、线程加锁 其中 locker 可以是任意对象&#xff0c;进入 synchronized 修饰的代码块, 相当于加锁&…

OpenWRT部署web站点并结合内网穿透实现无公网ip远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

尝试一下最新的联合办公利器ONLYOffice

下载下来一起试试吧 桌面安装版下载地址&#xff1a;https://www.onlyoffice.com/zh/download-desktop.aspx) 官网地址&#xff1a;https://www.onlyoffice.com 普通Office对联合办公的局限性 普通Office软件&#xff08;如Microsoft Office、Google Docs等&#xff09;在面对…

Socket通信---Python发送数据给C++程序

0. Problems 很多时候实现某种功能&#xff0c;需要在不同进程间发送数据&#xff0c;目前有几种主流的方法&#xff0c;如 让python和C/C程序互相发送数据&#xff0c;其实有几种方法&#xff1a; 共享内存共享文件Socket通信 在这里只提供Socket通信的例程&#xff0c;共享…

MySQL学习笔记3: MySQL数据库基础

目录 前言目标数据库操作&#xff08;针对database 的操作&#xff09;1. 创建数据库 create database 数据库名;2. 查看数据库 show databases;3. 选中数据库 use 数据库名;4. 删除数据库 drop database 数据库名; mysql中支持的数据类型1. 数值类型: NUMERIC(M,D)2. 字符串类…

如何在OpenWRT安装内网穿透工具实现远程访问本地搭建的web网站界面

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

【Vue】本地使用 axios 调用第三方接口并处理跨域

前端处理跨域 一. 开发准备 开发工具&#xff1a;VScode框架&#xff1a;Vue2项目结构&#xff1a;vue脚手架生成的标准项目&#xff08;以下仅显示主要部分&#xff09; 本地已搭建好的端口&#xff1a;8080要请求的第三方接口&#xff1a;http://1.11.1.111:端口号/xxx-api…

大型语言模型的语义搜索(一):关键词搜索

关键词搜索(Keyword Search)是文本搜索种一种常用的技术&#xff0c;很多知名的应用app比如Spotify、YouTube 或 Google map等都会使用关键词搜索的算法来实现用户的搜索任务&#xff0c;关键词搜索是构建搜索系统最常用的方法&#xff0c;最常用的搜索算法是Okapi BM25&#x…

Unity基于AssetBundle资源管理流程详解

在Unity游戏开发中&#xff0c;资源管理是一个非常重要的环节。随着游戏的发展&#xff0c;资源会变得越来越庞大&#xff0c;因此需要一种高效的资源管理方式来减少内存占用和加快加载速度。AssetBundle是Unity提供的一种资源打包和加载方式&#xff0c;可以将资源打包成一个独…

JS前端高频面试

JS数据类型有哪些&#xff0c;区别是什么 js数据类型分为原始数据类型和引用数据类型。 原始数据类型包括&#xff1a;number&#xff0c;string&#xff0c;boolean&#xff0c;null&#xff0c;undefined&#xff0c;和es6新增的两种类型&#xff1a;bigint 和 symbol。&am…

使用 Coze 搭建 TiDB 助手

导读 本文介绍了使用 Coze 平台搭建 TiDB 文档助手的过程。通过比较不同 AI Bot 平台&#xff0c;突出了 Coze 在插件能力和易用性方面的优势。文章深入讨论了实现原理&#xff0c;包括知识库、function call、embedding 模型等关键概念&#xff0c;最后成功演示了如何在 Coze…

【EasyV】QGIS转换至EasyV

QGIS转换至EasyV 第一步&#xff1a;导入QGIS第二步 坐标系转换第三步 集合修正第四步 重命名字段第五步 导出WGS geojson坐标第六步 导入EasyV 第一步&#xff1a;导入QGIS 第二步 坐标系转换 第三步 集合修正 第四步 重命名字段 第五步 导出WGS geojson坐标 第六步 导入EasyV…

【Git】:初识git

初识git 一.创建git仓库二.管理文件三.认识.git内部结构 一.创建git仓库 1.安装git 使用yum install git -y即可安装git。 2.创建仓库 首先创建一个git目录。 3.初始化仓库 这里面有很多内容&#xff0c;后面会将&#xff0c;主要是用来进行追踪的。 4.配置name和email 当然也…

ClickHouse快速上手

简介 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS) 官网(https://clickhouse.com/docs/zh)给出的定义&#xff0c;其实没看懂 特性 ClickHouse支持一种基于SQL的声明式查询语言&#xff0c;它在许多情况下与ANSI SQL标准相同。使用时和MySQL有点相似&#…

Python输出函数有知道的吗?

print()函数主要用于在终端中输出程序结果。它接受可变参数&#xff0c;可输出多个数据&#xff0c;数据之间默认用空格隔开&#xff0c;输出完毕后默认以换行结尾。print()函数还接受sep和end参数来指定数据间隔和结尾符号&#xff0c;以及file参数来指定输出流。 1.print() 函…

一分钟学会MobaXterm当Linux客户端使用

一、介绍 MobaXterm是一款功能强大的远程计算机管理工具&#xff0c;它集成了各种网络工具和远程连接协议&#xff0c;可以帮助用户在Windows系统上轻松管理远程计算机。MobaXterm支持SSH、Telnet、RDP、VNC等多种远程连接协议&#xff0c;同时还集成了X11服务器&#xff0c;可…