【PCL】SAC-IA粗匹配

1. 相关说明

2. CMakeLists.txt

# 指定最低的CMAKE版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.22 FATAL_ERROR)

# 创建项目
PROJECT(PCLSamples LANGUAGES CXX)

# 指定CPLUSPLUS标准
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_STANDARD 14)
SET(CMAKE_C_STANDARD 14)
SET(CMAKE_C_STANDARD_REQUIRED ON)

# 查找第三方依赖库
FIND_PACKAGE(PCL 1.11 REQUIRED)

# 添加可执行文件
ADD_EXECUTABLE(PCLSample src/main.cpp)

# 添加头文件目录
TARGET_INCLUDE_DIRECTORIES(PCLSample PRIVATE ${PCL_INCLUDE_DIRS})

# 添加库目录
TARGET_LINK_DIRECTORIES(PCLSample PRIVATE ${PCL_LIBRARY_DIRS})

# 添加编译器定义
TARGET_COMPILE_DEFINITIONS(PCLSample PRIVATE ${PCL_DEFINITIONS})
# 取消已有的编译器定义
#SET_TARGET_PROPERTIES(PCLSample PROPERTIES COMPILE_FLAGS "/UBOOST_ALL_NO_LIB-DBOOST_ALL_NO_LIB")

# 添加依赖库文件
target_link_libraries(PCLSample PRIVATE ${PCL_LIBRARIES})

3. main.cpp

#include <limits>
#include <fstream>
#include <vector>
#include <Eigen/Core>
#include <pcl/memory.h>
#include <pcl/pcl_macros.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/fpfh.h>
#include <pcl/registration/ia_ransac.h>

void calculateTemplate(_In_ const pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPtr,
    _In_ const float normalRadius,
    _In_ const float featureRadius,
    _Out_ pcl::PointCloud<pcl::FPFHSignature33>::Ptr& featurePtr)
{
    // 输出初始化
    pcl::PointCloud<pcl::Normal>::Ptr normalPtr(new pcl::PointCloud<pcl::Normal>);
    featurePtr = pcl::PointCloud<pcl::FPFHSignature33>::Ptr(new pcl::PointCloud<pcl::FPFHSignature33>);

    // 搜索方法
    pcl::search::KdTree<pcl::PointXYZ>::Ptr searchMothodPtr(new pcl::search::KdTree<pcl::PointXYZ>);

    // 计算法线
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
    normalEstimation.setInputCloud(cloudPtr);
    normalEstimation.setSearchMethod(searchMothodPtr);
    normalEstimation.setRadiusSearch(normalRadius);
    normalEstimation.compute(*normalPtr);

    // FPFH特征计算
    pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> featureEstimation;
    featureEstimation.setInputCloud(cloudPtr);
    featureEstimation.setInputNormals(normalPtr);
    featureEstimation.setSearchMethod(searchMothodPtr);
    featureEstimation.setRadiusSearch(featureRadius);
    featureEstimation.compute(*featurePtr);
}

/***********************************************************************************************************************
 * 主函数调用
 **********************************************************************************************************************/
int main(int argc, char** argv)
{
    /*******************************************************************************************************************
     * 加载模板点云与创建模板
     ******************************************************************************************************************/
    std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clouds;
    std::vector<pcl::PointCloud<pcl::FPFHSignature33>::Ptr> features;
    std::ifstream input_stream("./data/object_templates.txt");
    while (input_stream.good())
    {
        std::string pcd_filename;
        std::getline(input_stream, pcd_filename);
        if (pcd_filename.empty() || pcd_filename.at(0) == '#')
            continue;

        pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPtr(new pcl::PointCloud<pcl::PointXYZ>);
        pcl::io::loadPCDFile(pcd_filename, *cloudPtr);

        pcl::PointCloud<pcl::FPFHSignature33>::Ptr featurePtr;
        calculateTemplate(cloudPtr, 0.02f, 0.02f, featurePtr);

        std::cout << "计算路径为 " << pcd_filename << " 的点云特征完成" << std::endl;

        clouds.push_back(cloudPtr);
        features.push_back(featurePtr);
    }
    input_stream.close();

    /*******************************************************************************************************************
     * 加载目标点云
     ******************************************************************************************************************/
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTtarget(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("./data/person.pcd", *cloudTtarget);
    std::cout << "目标点云读取完成" << std::endl;

    // 直通滤波
    {
        pcl::PassThrough<pcl::PointXYZ> pass;
        pass.setInputCloud(cloudTtarget);
        pass.setFilterFieldName("z");
        pass.setFilterLimits(0, 1.0);
        pass.filter(*cloudTtarget);

        std::cout << "目标点云直通滤波完成" << std::endl;
    }

    // 体素网格降采样
    {
        pcl::VoxelGrid<pcl::PointXYZ> vox_grid;
        vox_grid.setInputCloud(cloudTtarget);
        vox_grid.setLeafSize(0.005f, 0.005f, 0.005f);
        pcl::PointCloud<pcl::PointXYZ>::Ptr tempCloud(new pcl::PointCloud<pcl::PointXYZ>);
        vox_grid.filter(*tempCloud);
        cloudTtarget = tempCloud;

        std::cout << "目标点云降采样完成" << std::endl;
    }

    // 计算待匹配点云特征
    pcl::PointCloud<pcl::FPFHSignature33>::Ptr targetFeaturePtr;
    calculateTemplate(cloudTtarget, 0.02f, 0.02f, targetFeaturePtr);

    // 定义匹配对象
    pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> sacIA;

    // 设置匹配参数
    sacIA.setMinSampleDistance(0.05f);
    sacIA.setMaxCorrespondenceDistance(0.01f * 0.01f);
    sacIA.setMaximumIterations(500);

    // 设置目标点云与特征
    sacIA.setInputTarget(cloudTtarget);
    sacIA.setTargetFeatures(targetFeaturePtr);

    // 遍历模板,获取匹配结果
    std::vector<float> scores;
    std::vector<Eigen::Matrix4f> transformations;
    for (size_t i = 0; i < clouds.size(); i++)
    {
        sacIA.setInputSource(clouds[i]);
        sacIA.setSourceFeatures(features[i]);

        pcl::PointCloud<pcl::PointXYZ> registration_output;
        sacIA.align(registration_output);

        std::cout << "第 " << i << " 个模板匹配成功" << std::endl;

        scores.push_back((float)sacIA.getFitnessScore(0.01f * 0.01f));
        transformations.push_back(sacIA.getFinalTransformation());
    }

    // 获取最佳匹配
    float lowest_score = std::numeric_limits<float>::infinity();
    int indexBest = 0;
    for (std::size_t i = 0; i < scores.size(); ++i)
    {
        if (scores[i] < lowest_score)
        {
            lowest_score = scores[i];
            indexBest = (int)i;
        }
    }
    auto transformBest = transformations[indexBest];

    // 输出匹配得分(一般小于0.0002是比较好的)
    printf("Best fitness score: %f\n", lowest_score);

    // 输出旋转矩阵与平移向量
    Eigen::Matrix3f rotation = transformBest.block<3, 3>(0, 0);
    Eigen::Vector3f translation = transformBest.block<3, 1>(0, 3);

    printf("\n");
    printf("    | %6.3f %6.3f %6.3f | \n", rotation(0, 0), rotation(0, 1), rotation(0, 2));
    printf("R = | %6.3f %6.3f %6.3f | \n", rotation(1, 0), rotation(1, 1), rotation(1, 2));
    printf("    | %6.3f %6.3f %6.3f | \n", rotation(2, 0), rotation(2, 1), rotation(2, 2));
    printf("\n");
    printf("t = < %0.3f, %0.3f, %0.3f >\n", translation(0), translation(1), translation(2));

    // 保存最佳匹配模板
    pcl::PointCloud<pcl::PointXYZ> transformed_cloud;
    pcl::transformPointCloud(*clouds[indexBest], transformed_cloud, transformBest);
    pcl::io::savePCDFileBinary("output.pcd", transformed_cloud);

    return EXIT_SUCCESS;
}

4. 效果图

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
PCL (Point Cloud Library) 中的 SAC-IA (Sample Consensus Initial Alignment) 和 ICP (Iterative Closest Point) 都是点云配准中常用的算法,结合使用可以实现更准确的配准结果。 SAC-IA 是一种采样一致性算法,可以快速地计算出两个点云之间的初步变换矩阵。ICP 算法则是一种迭代优化算法,可以在初步变换矩阵的基础上进一步优化获取更精确的变换矩阵。 下面是使用 PCL 进行 SAC-IA+ICP 配准的示例代码: ```cpp pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_source (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_source_aligned (new pcl::PointCloud<pcl::PointXYZ>); // 加载源点云和目标点云 pcl::io::loadPCDFile<pcl::PointXYZ> ("source_cloud.pcd", *cloud_source); pcl::io::loadPCDFile<pcl::PointXYZ> ("target_cloud.pcd", *cloud_target); // 创建 SAC-IA 对象 pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> sac_ia; sac_ia.setInputCloud (cloud_source); sac_ia.setSourceFeatures (source_features); sac_ia.setInputTarget (cloud_target); sac_ia.setTargetFeatures (target_features); sac_ia.setMinSampleDistance (0.05f); sac_ia.setMaxCorrespondenceDistance (0.1); sac_ia.setMaximumIterations (500); // 计算初步变换矩阵 pcl::PointCloud<pcl::PointXYZ>::Ptr sac_aligned (new pcl::PointCloud<pcl::PointXYZ>); sac_ia.align (*sac_aligned); // 创建 ICP 对象 pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp; icp.setInputSource (sac_aligned); icp.setInputTarget (cloud_target); icp.setMaxCorrespondenceDistance (0.05); icp.setMaximumIterations (100); // 优化变换矩阵 icp.align (*cloud_source_aligned); // 输出配准结果 std::cout << "SAC-IA+ICP has converged:" << icp.hasConverged () << " score: " << icp.getFitnessScore () << std::endl; // 保存配准后的点云 pcl::io::savePCDFile ("aligned_cloud.pcd", *cloud_source_aligned); ``` 在上述代码中,我们首先加载了源点云和目标点云。然后创建了 SAC-IA 对象,设置了输入点云、特征、最小采样距离、最大对应距离和最大迭代次数,然后调用 `align()` 函数计算初步变换矩阵。接着创建了 ICP 对象,设置了输入源点云和目标点云,最大对应距离和最大迭代次数,然后调用 `align()` 函数优化变换矩阵。最后输出配准结果并保存配准后的点云。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值