PCL 点云配准-SAC-IA 初始配准算法(粗配准)

server/2024/10/18 1:14:55/

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 计算FPFH特征函数

2.1.2执行SAC-IA配准

2.1.3可视化函数

2.2完整代码

三、实现效果


PCL点云算法汇总及实战案例汇总的目录地址链接:

PCL点云算法与项目实战案例汇总(长期更新)


一、概述

        点云配准是3D计算机视觉中的重要技术,广泛应用于物体识别、机器人导航等领域。SAC-IA(Sample Consensus Initial Alignment)是基于RANSAC(随机采样一致性)算法的初始配准方法,可用于粗配准。在这篇博客中,我们将探讨如何使用SAC-IA算法进行点云粗配准,并详细介绍相关步骤和代码实现。

1.1原理

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

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

1.2实现步骤

  1. 点云加载:读取目标点云和源点云。
  2. 点云下采样:使用体素滤波对点云进行下采样以减少计算量。
  3. 算法向量:对下采样后的点云进行法向量计算。
  4. FPFH特征计算:提取FPFH特征,用于后续的特征匹配。
  5. SAC-IA初始配准:使用SAC-IA算法进行粗配准,计算源点云的最佳变换矩阵。
  6. 可视化配准结果:将配准前后的点云可视化,比较配准效果。

1.3应用场景

SAC-IA算法可广泛应用于以下场景:

  1. 机器人导航:在多次扫描过程中对不同时间的点云数据进行配准,帮助机器人建立环境地图。
  2. 3D重建:将多个视角下获取的物体点云进行拼接,构建完整的3D模型。
  3. 目标识别:通过配准将某个已知物体的模型与场景中的物体进行对齐,完成目标识别。

二、代码实现

2.1关键函数

2.1.1 计算FPFH特征函数

fpfhFeature::Ptr compute_fpfh_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(8);  // 使用OpenMP加速n.setSearchMethod(tree);  // KDTree搜索n.setKSearch(10);         // 计算法向量时使用10个近邻点n.compute(*normals);      // 计算法向量// -------------------------FPFH特征计算-------------------------fpfhFeature::Ptr fpfh(new fpfhFeature);pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh_estimator;fpfh_estimator.setNumberOfThreads(8);   // 使用OpenMP加速fpfh_estimator.setInputCloud(input_cloud);fpfh_estimator.setInputNormals(normals);  // 使用计算的法向量fpfh_estimator.setSearchMethod(tree);   // KDTree搜索fpfh_estimator.setKSearch(10);          // 使用10个近邻点fpfh_estimator.compute(*fpfh);          // 计算FPFH特征return fpfh;  // 返回FPFH特征
}

2.1.2执行SAC-IA配准

// 执行SAC-IA配准的函数
pointcloud::Ptr perform_sac_ia(pointcloud::Ptr source, fpfhFeature::Ptr source_fpfh, pointcloud::Ptr target, fpfhFeature::Ptr target_fpfh)
{// 使用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;return aligned_cloud;                              // 返回配准后的点云
}

2.1.3可视化函数

// 可视化点云的函数
void visualize_pcd(pointcloud::Ptr pcd_src, pointcloud::Ptr pcd_tgt, pointcloud::Ptr pcd_final)
{// 创建可视化窗口pcl::visualization::PCLVisualizer viewer("点云配准可视化");int v1, v2;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_color(pcd_src, 0, 255, 0);    // 源点云绿色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_color(pcd_tgt, 255, 0, 0);   // 目标点云红色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_color(pcd_final, 0, 255, 0); // 配准结果绿色// 在两个视口中分别添加点云viewer.addPointCloud(pcd_src, src_color, "source cloud", v1);    // 左视口添加源点云viewer.addPointCloud(pcd_tgt, tgt_color, "target cloud", v1);    // 左视口添加目标点云viewer.addPointCloud(pcd_tgt, tgt_color, "target cloud v2", v2); // 右视口添加目标点云viewer.addPointCloud(pcd_final, final_color, "aligned cloud", v2); // 右视口添加配准后的点云// 启动可视化窗口,直到用户关闭窗口while (!viewer.wasStopped()) {viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}

2.2完整代码

#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近邻点数量为10ne.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近邻点数量为10fpfh_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并保存有效索引
}// 执行SAC-IA配准的函数
pointcloud::Ptr perform_sac_ia(pointcloud::Ptr source, fpfhFeature::Ptr source_fpfh, pointcloud::Ptr target, fpfhFeature::Ptr target_fpfh)
{// 使用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;return aligned_cloud;                              // 返回配准后的点云
}// 可视化点云的函数
void visualize_pcd(pointcloud::Ptr pcd_src, pointcloud::Ptr pcd_tgt, pointcloud::Ptr pcd_final)
{// 创建可视化窗口pcl::visualization::PCLVisualizer viewer("点云配准可视化");int v1, v2;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_color(pcd_src, 0, 255, 0);    // 源点云绿色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_color(pcd_tgt, 255, 0, 0);   // 目标点云红色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_color(pcd_final, 0, 255, 0); // 配准结果绿色// 在两个视口中分别添加点云viewer.addPointCloud(pcd_src, src_color, "source cloud", v1);    // 左视口添加源点云viewer.addPointCloud(pcd_tgt, tgt_color, "target cloud", v1);    // 左视口添加目标点云viewer.addPointCloud(pcd_tgt, tgt_color, "target cloud v2", v2); // 右视口添加目标点云viewer.addPointCloud(pcd_final, final_color, "aligned cloud", v2); // 右视口添加配准后的点云// 启动可视化窗口,直到用户关闭窗口while (!viewer.wasStopped()) {viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}// 主函数
int main(int argc, char** argv)
{pointcloud::Ptr source_cloud(new pointcloud);  // 创建源点云对象pointcloud::Ptr target_cloud(new pointcloud);  // 创建目标点云对象// 加载点云数据pcl::io::loadPCDFile<pcl::PointXYZ>("1.pcd", *source_cloud);  // 加载源点云pcl::io::loadPCDFile<pcl::PointXYZ>("2.pcd", *target_cloud);  // 加载目标点云// 去除源点云和目标点云中的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配准pointcloud::Ptr aligned_cloud = perform_sac_ia(source, source_fpfh, target, target_fpfh);// 可视化源点云、目标点云和配准后的点云visualize_pcd(source_cloud, target_cloud, aligned_cloud);return 0;
}

三、实现效果


http://www.ppmy.cn/server/132638.html

相关文章

基于深度学习的对抗攻击的防御

基于深度学习的对抗攻击防御是一项重要的研究方向&#xff0c;旨在提高模型在面对对抗样本时的鲁棒性和安全性。对抗攻击通常通过向输入数据中添加微小扰动&#xff0c;使得深度学习模型做出错误的预测。为了应对这些攻击&#xff0c;研究人员提出了多种防御策略。 1. 对抗训练…

东方通 TongWebV7 Docker 部署与 Spring Boot 集成指南

东方通 TongWebV7 Docker 部署与 Spring Boot 集成指南 文章目录 东方通 TongWebV7 Docker 部署与 Spring Boot 集成指南一 TongWeb V7二 Spring Boot JAR 配置文件三 修改 maven 依赖四 docker compose 启动项目五 查看 docker 信息 本文详细讲解了如何在 Docker 环境中将东方…

Spring AI Java程序员的AI之Spring AI(一)

SpringAI 基础使用 前言Spring AIChatClientImageClientOpenAiAudioTranscriptionClientEmbeddingClient 总结 前言 Spring AI&#xff0c;听着名字就感觉很好使用&#xff0c;快速上手&#xff0c;虽然功能没有太完善&#xff0c;但是社区活跃度很高&#xff0c;可以看看源码…

kafka创建多个分区时,分区会自动分配到多个不同的broker

1.分区只有一个时所有的消息生产和消费都集中在单个Broker上&#xff0c;多个broker只是提高了抗风险能力&#xff08;因为副本存在不同的broker上&#xff0c;主节点挂掉&#xff0c;可以重新选取副本为主节点&#xff09;。 2.没有消息顺序性要求可以多个分区&#xff0c;注意…

LIN从节点:波特率测试

文章目录 1、为什么需要测&#xff1f;2、如何实现测试&#xff1f;3、测试结果4、注意事项 1、为什么需要测&#xff1f; 调节波特率的变化&#xff0c;使主节点同步场位速率变化&#xff0c;验证从节点能否通过同步段进行调节自身位速率。对应ISO17987协议。 2、如何实现测…

基于微信小程序的在线点歌系统(论文+源码)-kaic

摘 要 随着社会与互联网的发展&#xff0c;人们已经不在停留在温饱的层面上&#xff0c;而是开始了享受生活&#xff0c;而最能突出网络飞速发展的当属娱乐&#xff0c;从最初的网吧上网到现在的我们可以随时随地上网&#xff0c;观看自己喜欢的各式各样的电影电视剧和短视频&a…

双十一购物节:数码达人的必买清单,你准备好了吗?

双十一购物节即将来临&#xff0c;对于数码爱好者来说&#xff0c;这是一年一度的狂欢时刻。在这个特殊的日子里&#xff0c;各大电商平台纷纷推出各种优惠活动&#xff0c;让每一位消费者都能以更实惠的价格购买到心仪已久的数码产品。 作为一名数码达人&#xff0c;如何在众…

PROFINET 转 EtherCAT, EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关https://item.taobao.com/item.htm?ftt&id822721028899 协议转换通信网关 PROFINET 转 EtherCAT GW系列型号 MS-GW31 概述 简介 MS-GW31 是 PROFINET 和 EtherCAT 协议转换网关&#xff0c;为用户提供两…