NARF关键点检测及SAC-IA粗配准

一、生成对应深度图

C++

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/io.h>
#include <pcl/range_image/range_image.h>
#include <pcl/visualization/range_image_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/common_headers.h>
using namespace std;int main(int, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//要配准变化的点云pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);//目标点云(不变的)if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view1.pcd", *cloud) == -1){PCL_ERROR("加载点云失败\n");}if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view2.pcd", *cloud_target) == -1){PCL_ERROR("加载点云失败\n");}pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;Eigen::Affine3f scene_sensor_pose_src(Eigen::Affine3f::Identity());Eigen::Affine3f scene_sensor_pose_tgt(Eigen::Affine3f::Identity());scene_sensor_pose_src = Eigen::Affine3f(Eigen::Translation3f(cloud->sensor_origin_[0],cloud->sensor_origin_[1], cloud->sensor_origin_[2])) * Eigen::Affine3f(cloud->sensor_orientation_);scene_sensor_pose_tgt = Eigen::Affine3f(Eigen::Translation3f(cloud_target->sensor_origin_[0],cloud_target->sensor_origin_[1], cloud_target->sensor_origin_[2])) * Eigen::Affine3f(cloud_target->sensor_orientation_);//-------------从点云创建深度图像———————————float noise_level = 0.0;float min_range = 0.0f;int border_size = 1;pcl::RangeImage::Ptr range_image_src(new pcl::RangeImage);pcl::RangeImage::Ptr range_image_tgt(new pcl::RangeImage);range_image_src->createFromPointCloud(*cloud, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_src, coordinate_frame,noise_level, min_range, border_size);range_image_tgt->createFromPointCloud(*cloud_target, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_tgt, coordinate_frame,noise_level, min_range, border_size);boost::shared_ptr <pcl::visualization::PCLVisualizer> viewer1(new pcl::visualization::PCLVisualizer("3D Viewer1"));//创建窗口,并设置名字为3D Viewerpcl::visualization::PointCloudColorHandlerCustom < pcl::PointWithRange>range_image_color_handler1(range_image_src, 0, 0, 0);viewer1->setBackgroundColor(1, 1, 1); viewer1->addPointCloud(range_image_src, range_image_color_handler1, "range image");viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");while (!viewer1->wasStopped()){viewer1->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}boost::shared_ptr <pcl::visualization::PCLVisualizer> viewer2(new pcl::visualization::PCLVisualizer("3D Viewer2"));//创建窗口,并设置名字为3D Viewerpcl::visualization::PointCloudColorHandlerCustom < pcl::PointWithRange>range_image_color_handler2(range_image_tgt, 0, 0, 0);viewer2->setBackgroundColor(1, 1, 1);viewer2->addPointCloud(range_image_tgt, range_image_color_handler2, "range image");viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");while (!viewer2->wasStopped()){viewer2->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}boost::shared_ptr <pcl::visualization::PCLVisualizer> viewer3(new pcl::visualization::PCLVisualizer("3D Viewer3"));//创建窗口,并设置名字为3D Viewerpcl::visualization::PointCloudColorHandlerCustom < pcl::PointWithRange>range_image_color_handler3(range_image_src, 255, 0, 0);pcl::visualization::PointCloudColorHandlerCustom < pcl::PointWithRange>range_image_color_handler4(range_image_tgt, 0, 0, 0);viewer3->setBackgroundColor(1, 1, 1);viewer3->addPointCloud(range_image_src, range_image_color_handler3, "range image1");viewer3->addPointCloud(range_image_tgt, range_image_color_handler4, "range image2");viewer3->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image1");viewer3->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image2");while (!viewer3->wasStopped()){viewer3->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}return 0;
}

关键代码解析:

pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;Eigen::Affine3f scene_sensor_pose_src(Eigen::Affine3f::Identity());Eigen::Affine3f scene_sensor_pose_tgt(Eigen::Affine3f::Identity());scene_sensor_pose_src = Eigen::Affine3f(Eigen::Translation3f(cloud->sensor_origin_[0],cloud->sensor_origin_[1], cloud->sensor_origin_[2])) * Eigen::Affine3f(cloud->sensor_orientation_);scene_sensor_pose_tgt = Eigen::Affine3f(Eigen::Translation3f(cloud_target->sensor_origin_[0],cloud_target->sensor_origin_[1], cloud_target->sensor_origin_[2])) * Eigen::Affine3f(cloud_target->sensor_orientation_);//-------------从点云创建深度图像———————————float noise_level = 0.0;float min_range = 0.0f;int border_size = 1;pcl::RangeImage::Ptr range_image_src(new pcl::RangeImage);pcl::RangeImage::Ptr range_image_tgt(new pcl::RangeImage);range_image_src->createFromPointCloud(*cloud, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_src, coordinate_frame,noise_level, min_range, border_size);range_image_tgt->createFromPointCloud(*cloud_target, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_tgt, coordinate_frame,noise_level, min_range, border_size);
  1. pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;:这里定义了深度图像的坐标系,常用的坐标系包括相机坐标系 (CAMERA_FRAME) 和激光雷达坐标系 (LASER_FRAME)。

  2. Eigen::Affine3f scene_sensor_pose_src(Eigen::Affine3f::Identity());Eigen::Affine3f scene_sensor_pose_tgt(Eigen::Affine3f::Identity());:创建了两个 Affine3f 类型的对象,用于表示点云的姿态(位置和方向)。

  3. 通过以下代码计算了源点云和目标点云的姿态(位置和方向):

    scene_sensor_pose_src = Eigen::Affine3f(Eigen::Translation3f(cloud->sensor_origin_[0],cloud->sensor_origin_[1], cloud->sensor_origin_[2])) * Eigen::Affine3f(cloud->sensor_orientation_);
    scene_sensor_pose_tgt = Eigen::Affine3f(Eigen::Translation3f(cloud_target->sensor_origin_[0],cloud_target->sensor_origin_[1], cloud_target->sensor_origin_[2])) * Eigen::Affine3f(cloud_target->sensor_orientation_);
    
  4. 设置了创建深度图像所需的参数:

    • float noise_level = 0.0;:噪声水平,表示深度图像中的噪声级别。
    • float min_range = 0.0f;:最小测量范围,表示深度图像中的最小测量距离。
    • int border_size = 1;:边界大小,表示深度图像周围的边界大小。
  5. 创建了两个深度图像对象的指针:pcl::RangeImage::Ptr range_image_src(new pcl::RangeImage);pcl::RangeImage::Ptr range_image_tgt(new pcl::RangeImage);

  6. 通过以下代码,使用点云数据创建深度图像:

    range_image_src->createFromPointCloud(*cloud, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_src, coordinate_frame,noise_level, min_range, border_size);
    range_image_tgt->createFromPointCloud(*cloud_target, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_tgt, coordinate_frame,noise_level, min_range, border_size);
    

在这里,参数的设置会影响深度图像的质量和内容。例如,noise_levelmin_rangeborder_size 参数会影响深度图像的噪声水平、最小测量范围以及边界大小。而角度参数 pcl::deg2rad() 用于将角度转换为弧度。

结果:

输入点云的深度图 

输出点云的深度图  

 

 输入点云和输出点云放在一起的深度图 ,为了区别,我把输入点云深度图颜色改成红色

 

二、 NARF关键点检测

C++

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/common_headers.h>
#include <pcl/range_image/range_image.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/keypoints/narf_keypoint.h>
using namespace std;int main(int, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//要配准变化的点云pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);//目标点云(不变的)if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view1.pcd", *cloud) == -1){PCL_ERROR("加载点云失败\n");}if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view2.pcd", *cloud_target) == -1){PCL_ERROR("加载点云失败\n");}cout << "读取原点云个数: " << cloud->points.size() << endl;cout << "读取目标点云个数: " << cloud_target->points.size() << endl;pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;Eigen::Affine3f scene_sensor_pose_src(Eigen::Affine3f::Identity());Eigen::Affine3f scene_sensor_pose_tgt(Eigen::Affine3f::Identity());scene_sensor_pose_src = Eigen::Affine3f(Eigen::Translation3f(cloud->sensor_origin_[0],cloud->sensor_origin_[1], cloud->sensor_origin_[2])) * Eigen::Affine3f(cloud->sensor_orientation_);scene_sensor_pose_tgt = Eigen::Affine3f(Eigen::Translation3f(cloud_target->sensor_origin_[0],cloud_target->sensor_origin_[1], cloud_target->sensor_origin_[2])) * Eigen::Affine3f(cloud_target->sensor_orientation_);//-------------从点云创建深度图像———————————float noise_level = 0.0;float min_range = 0.0f;int border_size = 1;pcl::RangeImage::Ptr range_image_src(new pcl::RangeImage);pcl::RangeImage::Ptr range_image_tgt(new pcl::RangeImage);range_image_src->createFromPointCloud(*cloud, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_src, coordinate_frame,noise_level, min_range, border_size);range_image_tgt->createFromPointCloud(*cloud_target, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose_tgt, coordinate_frame,noise_level, min_range, border_size);//range_image->setUnseenToMaxRange();//设置不能观察到的点都为远距离点//-----------提取NARF关键点-------------pcl::RangeImage& range_image1 = *range_image_src;pcl::RangeImageBorderExtractor range_image_border_extractor1;pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints1(new pcl::PointCloud<pcl::PointXYZ>());pcl::NarfKeypoint narf_keypoint_detector1(&range_image_border_extractor1);narf_keypoint_detector1.setRangeImage(&range_image1);//指定深度图narf_keypoint_detector1.getParameters().support_size = 0.2f;//指定搜索空间球体的半径,指定计算感兴趣值时所使用的领域范围narf_keypoint_detector1.getParameters().add_points_on_straight_edges = true;//指点是否添加垂直边缘上的点narf_keypoint_detector1.getParameters().distance_for_additional_points = 0.5;pcl::PointCloud<int>keypoint_indices1;narf_keypoint_detector1.compute(keypoint_indices1);//计算索引keypoints1->points.resize(keypoint_indices1.size());keypoints1->height = keypoint_indices1.height;keypoints1->width = keypoint_indices1.width;for (std::size_t i = 0; i < keypoint_indices1.points.size(); ++i){keypoints1->points[i].getVector3fMap() = range_image_src->points[keypoint_indices1.points[i]].getVector3fMap();}cout << "NARF points 的原点云提取结果为 " << keypoints1->points.size() << endl;pcl::RangeImage& range_image2 = *range_image_tgt;pcl::RangeImageBorderExtractor range_image_border_extractor2;pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints2(new pcl::PointCloud<pcl::PointXYZ>());pcl::NarfKeypoint narf_keypoint_detector2(&range_image_border_extractor2);narf_keypoint_detector2.setRangeImage(&range_image2);//指定深度图narf_keypoint_detector2.getParameters().support_size = 0.2f;//指定搜索空间球体的半径,指定计算感兴趣值时所使用的领域范围narf_keypoint_detector2.getParameters().add_points_on_straight_edges = true;//指点是否添加垂直边缘上的点narf_keypoint_detector2.getParameters().distance_for_additional_points = 0.5;pcl::PointCloud<int>keypoint_indices2;narf_keypoint_detector2.compute(keypoint_indices2);//计算索引keypoints2->points.resize(keypoint_indices2.size());keypoints2->height = keypoint_indices2.height;keypoints2->width = keypoint_indices2.width;for (std::size_t i = 0; i < keypoint_indices2.points.size(); ++i){keypoints2->points[i].getVector3fMap() = range_image_tgt->points[keypoint_indices2.points[i]].getVector3fMap();}cout << "NARF points 的目标点云提取结果为 " << keypoints2->points.size() << endl;//关键点显示boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer1(new pcl::visualization::PCLVisualizer("V1"));viewer1->setBackgroundColor(0, 0, 0);viewer1->setWindowName("NARF Key point extraction");pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color1(cloud, 0.0, 255, 0.0);viewer1->addPointCloud<pcl::PointXYZ>(keypoints1, single_color1, "key cloud");//特征点viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");while (!viewer1->wasStopped()){viewer1->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer2(new pcl::visualization::PCLVisualizer("V2"));viewer2->setBackgroundColor(0, 0, 0);viewer2->setWindowName("NARF Key point extraction");pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color2(cloud, 0.0, 255, 0.0);viewer2->addPointCloud<pcl::PointXYZ>(keypoints2, single_color2, "key cloud");//特征点viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");while (!viewer2->wasStopped()){viewer2->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer3(new pcl::visualization::PCLVisualizer("V3"));viewer3->setBackgroundColor(0, 0, 0);viewer3->setWindowName("NARF Key point extraction");pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color3(cloud, 0.0, 255, 0.0);viewer3->addPointCloud<pcl::PointXYZ>(cloud, single_color3, "sample cloud");viewer3->addPointCloud<pcl::PointXYZ>(keypoints1, "key cloud");//特征点viewer3->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");viewer3->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "key cloud");while (!viewer3->wasStopped()){viewer3->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer4(new pcl::visualization::PCLVisualizer("V4"));viewer4->setBackgroundColor(0, 0, 0);viewer4->setWindowName("NARF Key point extraction");pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color4(cloud, 0.0, 255, 0.0);viewer4->addPointCloud<pcl::PointXYZ>(cloud_target, single_color4, "sample cloud");viewer4->addPointCloud<pcl::PointXYZ>(keypoints2, "key cloud");//特征点viewer4->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "key cloud");viewer4->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "key cloud");while (!viewer4->wasStopped()){viewer4->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}return 0;
}

关键代码解析: 

pcl::RangeImage& range_image1 = *range_image_src;pcl::RangeImageBorderExtractor range_image_border_extractor1;pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints1(new pcl::PointCloud<pcl::PointXYZ>());pcl::NarfKeypoint narf_keypoint_detector1(&range_image_border_extractor1);narf_keypoint_detector1.setRangeImage(&range_image1);//指定深度图narf_keypoint_detector1.getParameters().support_size = 0.2f;//指定搜索空间球体的半径,指定计算感兴趣值时所使用的领域范围narf_keypoint_detector1.getParameters().add_points_on_straight_edges = true;//指点是否添加垂直边缘上的点narf_keypoint_detector1.getParameters().distance_for_additional_points = 0.5;pcl::PointCloud<int>keypoint_indices1;narf_keypoint_detector1.compute(keypoint_indices1);//计算索引keypoints1->points.resize(keypoint_indices1.size());keypoints1->height = keypoint_indices1.height;keypoints1->width = keypoint_indices1.width;for (std::size_t i = 0; i < keypoint_indices1.points.size(); ++i){keypoints1->points[i].getVector3fMap() = range_image_src->points[keypoint_indices1.points[i]].getVector3fMap();}
  1. pcl::RangeImage& range_image1 = *range_image_src;:将源深度图像的引用保存到 range_image1 中,以便后续使用。

  2. pcl::RangeImageBorderExtractor range_image_border_extractor1;:创建深度图像边界提取器的实例,用于边界处理。

  3. pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints1(new pcl::PointCloud<pcl::PointXYZ>());:创建一个点云对象 keypoints1 用于存储提取的关键点。

  4. pcl::NarfKeypoint narf_keypoint_detector1(&range_image_border_extractor1);:创建 NARF 关键点检测器的实例,并将边界提取器传递给它。

  5. narf_keypoint_detector1.setRangeImage(&range_image1);:指定 NARF 关键点检测器要使用的深度图像。

  6. narf_keypoint_detector1.getParameters().support_size = 0.2f;:设置搜索空间球体的半径,该参数影响关键点的计算感兴趣值时所使用的领域范围。较小的值可能导致检测到更细小的关键点。

  7. narf_keypoint_detector1.getParameters().add_points_on_straight_edges = true;:指定是否在垂直边缘上添加点。设置为 true 可以增加关键点的数量,但可能也增加噪声。

  8. narf_keypoint_detector1.getParameters().distance_for_additional_points = 0.5;:设置额外点之间的距离。该参数用于在一些特殊情况下添加额外的关键点。

  9. pcl::PointCloud<int> keypoint_indices1;:创建一个整数类型的点云对象,用于存储关键点的索引。

  10. narf_keypoint_detector1.compute(keypoint_indices1);:计算关键点的索引。

  11. keypoints1->points.resize(keypoint_indices1.size());:调整关键点点云的大小。

  12. 使用循环将关键点的坐标从深度图像的索引中提取并存储到 keypoints1 中。

结果:

输入点云的关键点

输出点云的关键点 

 

输入点云的关键点与输入点云一起展示

 

输出点云的关键点与输出点云一起展示 

三、NARF关键点检测及SAC-IA粗配准 

C++

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/io.h>
#include <pcl/keypoints/iss_3d.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/features/fpfh_omp.h>  
#include <pcl/common/common_headers.h>
#include <pcl/registration/ia_ransac.h>
#include <pcl/range_image/range_image.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/keypoints/narf_keypoint.h>using namespace std;
void extract_keypoint(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& keypoint)
{pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;Eigen::Affine3f scene_sensor_pose(Eigen::Affine3f::Identity());scene_sensor_pose = Eigen::Affine3f(Eigen::Translation3f(cloud->sensor_origin_[0],cloud->sensor_origin_[1], cloud->sensor_origin_[2])) * Eigen::Affine3f(cloud->sensor_orientation_);//-------------从点云创建深度图像———————————float noise_level = 0.0;float min_range = 0.0f;int border_size = 1;pcl::RangeImage::Ptr range_image(new pcl::RangeImage);range_image->createFromPointCloud(*cloud, pcl::deg2rad(0.02f), pcl::deg2rad(0.02f),pcl::deg2rad(360.0f), pcl::deg2rad(180.0f), scene_sensor_pose, coordinate_frame,noise_level, min_range, border_size);//range_image->setUnseenToMaxRange();//设置不能观察到的点都为远距离点//-----------提取NARF关键点-------------pcl::RangeImage& range_image0 = *range_image;pcl::RangeImageBorderExtractor range_image_border_extractor;pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor);narf_keypoint_detector.setRangeImage(&range_image0);//指定深度图narf_keypoint_detector.getParameters().support_size = 0.2f;//指定搜索空间球体的半径,指定计算感兴趣值时所使用的领域范围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);//计算索引keypoint->points.resize(keypoint_indices.size());keypoint->height = keypoint_indices.height;keypoint->width = keypoint_indices.width;for (std::size_t i = 0; i < keypoint_indices.points.size(); ++i){keypoint->points[i].getVector3fMap() = range_image->points[keypoint_indices.points[i]].getVector3fMap();}}
pcl::PointCloud<pcl::FPFHSignature33>::Ptr compute_fpfh_feature(pcl::PointCloud<pcl::PointXYZ>::Ptr& keypoint)
{pcl::search::KdTree<pcl::PointXYZ>::Ptr tree;pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;n.setInputCloud(keypoint);n.setSearchMethod(tree);n.setKSearch(10);n.compute(*normals);pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfh(new pcl::PointCloud<pcl::FPFHSignature33>);pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> f;f.setNumberOfThreads(8);f.setInputCloud(keypoint);f.setInputNormals(normals);f.setSearchMethod(tree);f.setRadiusSearch(50);f.compute(*fpfh);return fpfh;
}
pcl::PointCloud<pcl::PointXYZ>::Ptr sac_align(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr s_k, pcl::PointCloud<pcl::PointXYZ>::Ptr t_k, pcl::PointCloud<pcl::FPFHSignature33>::Ptr sk_fpfh, pcl::PointCloud<pcl::FPFHSignature33>::Ptr tk_fpfh)
{pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> scia;scia.setInputSource(s_k);scia.setInputTarget(t_k);scia.setSourceFeatures(sk_fpfh);scia.setTargetFeatures(tk_fpfh);scia.setMinSampleDistance(7);///参数:设置采样点之间的最小距离,满足的被当做采样点scia.setNumberOfSamples(250);设置每次迭代设置采样点的个数(这个参数多可以增加配准精度)scia.setCorrespondenceRandomness(4);//设置选择随机特征对应点时要使用的邻域点个数。值越大,特征匹配的随机性就越大/*scia.setEuclideanFitnessEpsilon(0.001);scia.setTransformationEpsilon(1e-10);scia.setRANSACIterations(30);*/pcl::PointCloud<pcl::PointXYZ>::Ptr sac_result(new pcl::PointCloud<pcl::PointXYZ>);scia.align(*sac_result);pcl::transformPointCloud(*cloud, *sac_result, scia.getFinalTransformation());return sac_result;
}
int main(int, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//要配准变化的点云pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);//目标点云(不变的)if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view1.pcd", *cloud) == -1){PCL_ERROR("加载点云失败\n");}if (pcl::io::loadPCDFile<pcl::PointXYZ>("pcd/pig_view2.pcd", *cloud_target) == -1){PCL_ERROR("加载点云失败\n");}boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer1(new pcl::visualization::PCLVisualizer("v1"));viewer1->setBackgroundColor(0, 0, 0);  //设置背景颜色为黑色// 对目标点云着色可视化 (red).pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color1(cloud_target, 255, 0, 0);viewer1->addPointCloud<pcl::PointXYZ>(cloud_target, target_color1, "target cloud");viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");// 对源点云着色可视化 (green).pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color1(cloud, 0, 255, 0);viewer1->addPointCloud<pcl::PointXYZ>(cloud, input_color1, "input cloud");viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "input cloud");//while (!viewer1->wasStopped()){viewer1->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}////粗配准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(cloud, s_k);extract_keypoint(cloud_target, t_k);std::cout << "关键点数量" << s_k->size() << std::endl;std::cout << "关键点数量" << t_k->size() << std::endl;pcl::PointCloud<pcl::FPFHSignature33>::Ptr sk_fpfh = compute_fpfh_feature(s_k);pcl::PointCloud<pcl::FPFHSignature33>::Ptr tk_fpfh = compute_fpfh_feature(t_k);pcl::PointCloud<pcl::PointXYZ>::Ptr result(new pcl::PointCloud<pcl::PointXYZ>);result = sac_align(cloud, s_k, t_k, sk_fpfh, tk_fpfh);boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer2(new pcl::visualization::PCLVisualizer("显示点云"));viewer2->setBackgroundColor(0, 0, 0);  //设置背景颜色为黑色// 对目标点云着色可视化 (red).pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color2(cloud_target, 255, 0, 0);viewer2->addPointCloud<pcl::PointXYZ>(cloud_target, target_color2, "target cloud");viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");// 对源点云着色可视化 (green).pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>input_color2(result, 0, 255, 0);viewer2->addPointCloud<pcl::PointXYZ>(result, input_color2, "input cloud");viewer2->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "input cloud");//while (!viewer2->wasStopped()){viewer2->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100));}return 0;
}

关键代码解析: 

我之前在iss关键点检测以及SAC-IA粗配准-CSDN博客

已经解释了大部分函数,这篇文章就不赘述了

range_image->setUnseenToMaxRange();

 这一行是上述代码被注释掉的部分,稍微解释一下

setUnseenToMaxRange() 被调用后,范围图像中未被看到的点(通常由传感器视野限制或遮挡造成)的范围值会被设置为最大可能的范围值

scia.setEuclideanFitnessEpsilon(0.001);
scia.setTransformationEpsilon(1e-10);
scia.setRANSACIterations(30);

这三行也是上述代码被注释掉的部分,稍微解释一下

  1. scia.setEuclideanFitnessEpsilon(0.001);

    • 这一行代码设置了模型配准中的欧氏距离收敛标准(Euclidean Fitness Epsilon)。
    • 欧氏距离是指在配准的过程中,通过优化变换矩阵,使得目标点云与源点云的每个点之间的欧氏距离小于该阈值。
    • 参数值 0.001 表示当欧氏距离小于或等于 0.001 时,认为配准已经收敛。
  2. scia.setTransformationEpsilon(1e-10);

    • 这一行代码设置了模型配准中的变换矩阵收敛标准(Transformation Epsilon)。
    • 变换矩阵收敛标准是指通过优化变换矩阵的过程中,变换矩阵的变化小于该阈值时,认为配准已经收敛。
    • 参数值 1e-10 是一个非常小的数,表示当变换矩阵的变化小于或等于 1e-10 时,认为配准已经收敛。
  3. scia.setRANSACIterations(30);

    • 这一行代码设置了模型配准中的 RANSAC 迭代次数。
    • RANSAC(Random Sample Consensus)是一种迭代优化的方法,通过随机采样来估计变换矩阵。
    • 参数值 30 表示进行 30 次 RANSAC 迭代来估计最优的变换矩阵。

影响:

  • 调整 setEuclideanFitnessEpsilon 的值会影响收敛的条件,更小的值可能导致更严格的收敛,但也可能增加算法运行时间。
  • 调整 setTransformationEpsilon 的值会影响变换矩阵的收敛条件,较小的值表示更精确的匹配,但也可能增加计算开销。
  • 调整 setRANSACIterations 的值会影响 RANSAC 迭代的次数,更多的迭代次数可能带来更精确的变换矩阵,但也增加了计算时间。

结果:

输入点云与输出点云

配准后的输入点云与输出点云,实际效果并不好,运行也慢,需要好几分钟

 

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

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

相关文章

pytorch常用激活函数笔记

1. relu函数&#xff1a; 公式&#xff1a; 深层网络内部激活函数常用这个 import matplotlib.pyplot as pltdef relu_fun(x):if x>0:return xelse:return 0x np.random.randn(10) y np.arange(10)plt.plot(y,x)for i ,t in enumerate(x):x[i] relu_fun(t) plt.p…

MySQL数据库-MVCC多版本并发控制

mvcc,多版本并发控制&#xff08;Multi-Version Concurrency Control&#xff09;,是一种用于数据库管理系统中的并发控制方法. 在传统的并发控制方法中,如锁定机制,当一个事务修改数据时,会对相关的数据对象进行锁定,其他事务需要等待该锁释放才能进行操作。这种方法存在着事…

数据结构在JavaScript中的体现

一.概述 数据结构是计算机中存储、组织数据的方式。通常情况下&#xff0c;精心选择的数据结构可以带来最优效率的算法&#xff0c;其实算法并不是一个很高级的东西&#xff0c;它充斥在每一种代码组织方式中&#xff1b;而且各种语言关于数据结构方面的内容都是大同小异的&…

奔跑吧小恐龙(Java)

前言 Google浏览器内含了一个小彩蛋当没有网络连接时&#xff0c;浏览器会弹出一个小恐龙&#xff0c;当我们点击它时游戏就会开始进行&#xff0c;大家也可以玩一下试试&#xff0c;网址&#xff1a;恐龙快跑 - 霸王龙游戏. (ur1.fun) 今天我们也可以用Java来简单的实现一下这…

Python-web自动化-Playwright的学习

Python-web自动化-Playwright的学习 1. 安装playwright2. 界面等待3. 自动化代码助手4. 定位元素1. css selector定位2. xpath定位3. get_by_XXX定位 5. 操作元素1. 单选框、复选框2. select下拉框3. 网页操作4. 框架页 frame5. 窗口切换6. 截屏 1. 安装playwright pip命令 pi…

垃圾分类|城市垃圾分类管理系统|基于Springboot的城市垃圾分类管理系统设计与实现(源码+数据库+文档)

城市垃圾分类管理系统目录 目录 基于Springboot的城市垃圾分类管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、垃圾列表 2、公告信息管理 3、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 …

(06)Hive——正则表达式

Hive版本&#xff1a;hive-3.1.2 一、Hive的正则表达式概述 正则表达式是一种用于匹配和操作文本的强大工具&#xff0c;它是由一系列字符和特殊字符组成的模式&#xff0c;用于描述要匹配的文本模式。 Hive的正则表达式灵活使用解决HQL开发过程中的很多问题&#xff0c;本篇文…

代码随想录算法训练营第十七天|Leetcode110 平衡二叉树、Leetcode257 二叉树的所有路径、Leetcode404 左叶子之和

代码随想录算法训练营第十七天|Leetcode110 平衡二叉树、Leetcode257 二叉树的所有路径、Leetcode404 左叶子之和 ● Leetcode110 平衡二叉树● 解题思路● 代码实现 ● Leetcode257 二叉树的所有路径● 解题思路● 代码实现 ● Leetcode404 左叶子之和● 解题思路● 代码实现 …

esp8266-01s WIFI模块使用(一)- AT指令

时间记录&#xff1a;2024/2/15 一、注意事项 &#xff08;1&#xff09;使用英文双引号表示字符串数据 &#xff08;2&#xff09;默认波特率115200 &#xff08;3&#xff09;AT指令以“\r\n”结尾 &#xff08;4&#xff09;3.3V电源接口先连接单片机的3.3V&#xff0c;如…

7 大 Android 数据恢复软件,可轻松找回丢失的数据

每年&#xff0c;由于各种原因&#xff0c;数百万人从他们的 Android 设备中丢失数据。它可能像意外删除文件一样简单&#xff0c;也可能像系统崩溃一样复杂。在这种情况下&#xff0c;拥有高效的数据恢复工具可以证明是救命稻草。Mac 用户尤其需要找到与其系统兼容的软件。好消…

AtCoder Beginner Contest 335 (Sponsored by Mynavi) --- F - Hop Sugoroku -- 题解

目录 F - Hop Sugoroku 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; F - Hop Sugoroku 题目大意&#xff1a; 思路解析&#xff1a; 容易想到这是一个dp题&#xff0c;然后初始转移方程为&#xff1a; 如果当a[i] 较大时&#xff0c;时间复杂度为 O(N…

ElasticSearch分词器和相关性详解

目录 ES分词器详解 基本概念 分词发生时期 分词器的组成 切词器&#xff1a;Tokenizer 词项过滤器&#xff1a;Token Filter 停用词 同义词 字符过滤器&#xff1a;Character Filter HTML 标签过滤器&#xff1a;HTML Strip Character Filter 字符映射过滤器&#x…