admin管理员组

文章数量:1649938

目录

  • 一、概述
  • 二、代码
  • 三、结果

内容抄自CSDN点云侠:【2024最新版】PCL点云处理算法汇总(C++长期更新版)。质量无忧,永久免费,可放心复制粘贴。

一、概述

SAC-IA算法是一种基于特征匹配的初始配准方法,算法通过以下步骤完成:

特征提取:首先对输入点云进行下采样和特征提取,通常使用FPFH(Fast Point Feature Histograms)特征进行描述。
特征匹配:通过FPFH特征在目标点云与源点云之间进行匹配。
随机采样一致性:通过RANSAC方法随机采样若干个点,计算假设变换矩阵,并基于误差和内点数量选择最优变换矩阵。
输出配准结果:通过最优变换矩阵将源点云配准到目标点云。

二、代码

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/filters/voxel_grid.h>       // 体素滤波器,用于点云下采样
#include <pcl/features/normal_3d_omp.h>   // 使用多线程加速法向量估计
#include <pcl/features/fpfh_omp.h>        // FPFH加速计算
#include <pcl/registration/ia_ransac.h>   // SAC-IA初始配准算法
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>

using namespace std;

typedef pcl::PointCloud<pcl::PointXYZ> pointcloud;            // 点云类型
typedef pcl::PointCloud<pcl::Normal> pointnormal;             // 法向量类型
typedef pcl::PointCloud<pcl::FPFHSignature33> fpfhFeature;    // FPFH特征类型


// 计算FPFH特征的函数
fpfhFeature::Ptr compute_fpfh_feature(pointcloud::Ptr input_cloud, pcl::search::KdTree<pcl::PointXYZ>::Ptr tree)
{
    // 1. 估计法向量
    pointnormal::Ptr normals(new pointnormal);  // 用于存储计算得到的法向量
    pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> ne;  // 使用OMP加速法向量计算
    ne.setInputCloud(input_cloud);              // 设置输入点云
    ne.setNumberOfThreads(8);                   // 设置并行计算的线程数
    ne.setSearchMethod(tree);                   // 使用KD树加速搜索
    ne.setKSearch(10);                          // 设置K近邻点数量为10
    ne.compute(*normals);                       // 计算法向量

    // 2. 计算FPFH特征
    fpfhFeature::Ptr fpfh(new fpfhFeature);     // 创建FPFH特征存储容器
    pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh_estimator;  // FPFH特征估计器
    fpfh_estimator.setNumberOfThreads(8);       // 设置并行计算线程数
    fpfh_estimator.setInputCloud(input_cloud);  // 设置输入点云
    fpfh_estimator.setInputNormals(normals);    // 设置法向量
    fpfh_estimator.setSearchMethod(tree);       // 使用KD树加速搜索
    fpfh_estimator.setKSearch(10);              // 设置K近邻点数量为10
    fpfh_estimator.compute(*fpfh);              // 计算FPFH特征

    return fpfh;
}

// 点云下采样函数
pointcloud::Ptr downsample_cloud(pointcloud::Ptr input_cloud, float leaf_size)
{
    // 使用体素滤波器对点云进行下采样
    pcl::VoxelGrid<pcl::PointXYZ> voxel_grid;
    voxel_grid.setLeafSize(leaf_size, leaf_size, leaf_size);  // 设置体素的大小
    pointcloud::Ptr filtered_cloud(new pointcloud);           // 创建存储下采样后的点云
    voxel_grid.setInputCloud(input_cloud);                    // 设置输入点云
    voxel_grid.filter(*filtered_cloud);                       // 执行下采样

    return filtered_cloud;                                    // 返回下采样后的点云
}

// 去除点云中的NAN点的函数
void remove_nan_points(pointcloud::Ptr input_cloud)
{
    // 移除输入点云中的NAN点
    vector<int> indices;
    pcl::removeNaNFromPointCloud(*input_cloud, *input_cloud, indices);  // 去除NAN并保存有效索引
}

// 点云可视化函数
void visualizePointCloudsRegistration(pcl::PointCloud<pcl::PointXYZ>::Ptr source, pcl::PointCloud<pcl::PointXYZ>::Ptr target,
    pcl::PointCloud<pcl::PointXYZ>::Ptr icp_cloud)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Registration Result"));
    int v1 = 0, v2 = 1;
    viewer->createViewPort(0, 0, 0.5, 1, v1);  // 创建左视口
    viewer->createViewPort(0.5, 0, 1, 1, v2);  // 创建右视口
    viewer->setBackgroundColor(0, 0, 0, v1);   // 设置背景颜色
    viewer->setBackgroundColor(0.05, 0, 0, v2);

    // 设置点云的颜色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(source, 255, 0, 0);  // 源点云颜色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(target, 0, 0, 255);  // 目标点云颜色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> transe(icp_cloud, 255, 0, 0); // 配准后的点云颜色

    viewer->addPointCloud(source, src_h, "source cloud", v1);   // 添加源点云
    viewer->addPointCloud(target, tgt_h, "target cloud", v1);   // 添加目标点云
    viewer->addPointCloud(target, tgt_h, "target cloud1", v2);  // 目标点云
    viewer->addPointCloud(icp_cloud, transe, "pcs cloud", v2);  // 添加配准后的点云

    // 启动可视化窗口
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(10000));
    }
}


// 主函数
int main(int argc, char** argv)
{
    // 加载源点云数据
    pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("1.pcd", *source_cloud) < 0)
    {
        PCL_ERROR("Couldn't read file \n");
        return -1;
    }
    // 加载目标点云数据
    pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("2.pcd", *target_cloud) < 0)
    {
        PCL_ERROR("Couldn't read file \n");
        return -1;
    }

    // 去除源点云和目标点云中的NAN点
    remove_nan_points(source_cloud);
    remove_nan_points(target_cloud);

    // 对点云进行下采样
    pointcloud::Ptr source = downsample_cloud(source_cloud, 0.005f);  // 源点云下采样
    pointcloud::Ptr target = downsample_cloud(target_cloud, 0.005f);  // 目标点云下采样

    // 创建KD树用于加速搜索
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());

    // 计算源点云和目标点云的FPFH特征
    fpfhFeature::Ptr source_fpfh = compute_fpfh_feature(source, tree);
    fpfhFeature::Ptr target_fpfh = compute_fpfh_feature(target, tree);

    // 执行SAC-IA配准
   // 使用SAC-IA进行点云配准
    pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> sac_ia;
    sac_ia.setInputSource(source);                     // 设置源点云
    sac_ia.setSourceFeatures(source_fpfh);             // 设置源点云的FPFH特征
    sac_ia.setInputTarget(target);                     // 设置目标点云
    sac_ia.setTargetFeatures(target_fpfh);             // 设置目标点云的FPFH特征
    sac_ia.setMinSampleDistance(0.1);                  // 设置样本点之间的最小距离
    sac_ia.setCorrespondenceRandomness(6);             // 设置邻居数量,用于随机特征对应选择

    pointcloud::Ptr aligned_cloud(new pointcloud);     // 用于存储配准后的点云
    sac_ia.align(*aligned_cloud);                      // 执行配准

    // 输出配准结果
    cout << "配准得分: " << sac_ia.getFitnessScore() << endl;
    cout << "变换矩阵:\n" << sac_ia.getFinalTransformation() << endl;

    // 可视化源点云、目标点云和配准后的点云
    visualizePointCloudsRegistration(source_cloud, target_cloud, aligned_cloud);

    return 0;
}

三、结果

本文标签: 算法点云配准PCLSAC粗配准