PCL库简单的icp配准

news2024/11/17 0:02:45
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>

int main(int argc, char** argv)
{
    // 确保提供了两个PCD文件作为输入
    if (argc != 3) {
        PCL_ERROR("请提供两个PCD文件作为输入。\n");
        return (-1);
    }

    // 读取源点云和目标点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_reg(new pcl::PointCloud<pcl::PointXYZ>);

    if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud_in) == -1) {
        PCL_ERROR("无法读取文件 %s\n", argv[1]);
        return (-1);
    }
    if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[2], *cloud_out) == -1) {
        PCL_ERROR("无法读取文件 %s\n", argv[2]);
        return (-1);
    }

    // 创建ICP配准对象
    pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
    icp.setInputSource(cloud_in);
    icp.setInputTarget(cloud_out);

    // 进行配准
    icp.align(*cloud_reg);

    if (icp.hasConverged())
    {
        std::cout << "配准成功!" << std::endl;
        std::cout << "最终变换矩阵:" << icp.getFinalTransformation() << std::endl;
        std::cout << "配准后的点云:" << std::endl;
        for (size_t i = 0; i < cloud_reg->size(); ++i)
            std::cout << "    " << cloud_reg->points[i].x
                      << " " << cloud_reg->points[i].y
                      << " " << cloud_reg->points[i].z << std::endl;
    // 保存配准后的点云为PCD文件
        pcl::io::savePCDFile("aligned_cloud.pcd", *cloud_reg);
        std::cout << "已保存配准后的点云为 'aligned_cloud.pcd'" << std::endl;
    }
    else
    {
        std::cout << "配准失败!" << std::endl;
    }

    return 0;
}

测试了一下PCL库的icp效果,对于40度左右的旋转的配准效果还是不好。

joey@joey-Legion-Y7000P-IRX9:~/code/pclregistration/build$ ./simple_icp '/home/joey/code/pclregistration/data/1564024971.235044000.pcd' '/home/joey/code/pclregistration/data/1564025000.934826000.pcd'

在命令行调用生成的可执行文件。

可以看到初始点云(紫色),目标点云(白色),配准结果(蓝色)。

可以看到在角度比较大的时候,icp的效果不是很好。

简单调了一下参数,效果显著提升。


    // 设置ICP参数
    icp.setMaxCorrespondenceDistance(1); // 设置最大对应距离
    icp.setEuclideanFitnessEpsilon(0.0001); // 设置欧几里得拟合度阈值
    icp.setMaximumIterations(200); // 设置最大迭代次数
    icp.convergence_criteria_->setAbsoluteMSE(1e-5); // 设置绝对均方误差
    icp.convergence_criteria_->setMaximumIterationsSimilarTransforms(10); // 设置最大相似变换迭代次数

  
  1. setMaxCorrespondenceDistance(float distance):

    • 作用:设置最大对应距离,即源点云中的点与目标点云中最近点之间的最大允许距离。如果距离超过这个值,这对点将不会被考虑在内,以避免错误的匹配。
    • 参数:1 表示最大距离为1米。这个值越小,算法越倾向于只匹配非常接近的点对,但可能会导致有效匹配点对数量减少;值越大,可能会包含错误的匹配,但匹配点对数量会增加。
  2. setEuclideanFitnessEpsilon(float epsilon):

    • 作用:设置欧几里得拟合度阈值,用于确定算法是否收敛。如果连续两次迭代的均方误差(MSE)的相对变化小于这个值,则认为算法已经收敛。
    • 参数0.0001 表示相对误差阈值为0.01%。这是一个不太严格的收敛条件,意味着算法会在接近最优解时停止迭代。
  3. setMaximumIterations(int iterations):

    • 作用:设置最大迭代次数。无论算法是否收敛,达到最大迭代次数后都会停止。
    • 参数200 表示最大迭代次数为200次。这个值可以根据实际情况调整,较大的值可能会得到更精确的结果,但计算时间会更长。
  4. convergence_criteria_->setAbsoluteMSE(double mse):

    • 作用:设置绝对均方误差(MSE)阈值。如果当前迭代的MSE小于这个值,则认为算法已经收敛。
    • 参数1e-5 表示绝对MSE阈值为0.00001。这意味着如果算法的MSE降至这个值以下,即使没有达到最大迭代次数,算法也会停止。
  5. convergence_criteria_->setMaximumIterationsSimilarTransforms(int iterations):

    • 作用:设置在算法收敛前,允许的最大连续迭代次数,其中变换矩阵变化不大(即两次迭代的MSE变化很小)。
    • 参数:10 表示如果连续10次迭代的变换矩阵变化都很小,则认为算法已经收敛。这有助于避免在接近最优解时进行不必要的额外迭代。

最终的配准效果如图:

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

dcatadmin 自定义登录页面

一、问题&#xff1a; 在后台管理系统中&#xff0c;不同的项目想要不同的登录页面&#xff0c;但是框架自带的登录页面就只有一个。 解决&#xff1a; 由芒果系统改造的dcatadmin登录插件&#xff0c;实现一键安装改变登录页面。 项目介绍 基于Laravel和Vue的快速开发的后台管…

html5 + css3(上)

目录 HTML认知web标准vscode的简介和使用注释标题和段落换行和水平线标签文本格式化标签图片图片-基本使用图片-属性 绝对路径相对路径音频标签视频标签超链接 HTML基础列表列表-无序和有序列表-自定义 表格表格-使用表格-表格标题和表头单元格表格-结构标签&#xff08;了解&a…

CentOS 6文件系统

由冯诺依曼在 1945 年提出的计算机五大组成部分&#xff1a;运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设 备&#xff0c;输出设备。 1. 硬盘结构&#xff1a; &#xff08;1&#xff09;机械硬盘结构&#xff1a; 磁盘拆解图&#xff1a; 扇区&#xff0c;…

白杨SEO:抖音上做自然搜索流量怎么挖掘出抖音流量关键词及布局进去?【举例】

前言&#xff1a;为什么想到再分享这个&#xff1f;因为发现很多人在抖音做搜索流量时怎么挖掘抖音关键词这个基础以及怎么布局进去不太清楚&#xff0c;所以再来写下&#xff0c;希望对大家有帮助。 文章大纲&#xff1a; 1、抖音搜索流量如何确定业务词&#xff1f; 2、抖音…

Ubuntu下安装Zookeeper集群

Zookeeper集群是一个开源的分布式协调服务系统&#xff0c;它由Apache软件基金会维护&#xff0c;旨在为分布式应用提供一致性和可靠性的服务。 在Zookeeper集群中&#xff0c;服务器可以扮演三种角色——领导者&#xff08;Leader&#xff09;、跟随者&#xff08;Follower&a…

开放式耳机哪个品牌好?值得选购的开放式蓝牙耳机推荐

2024年&#xff0c;蓝牙耳机市场迎来了开放式耳机的热潮。但其实对于许多消费者来说&#xff0c;如何选择合适的开放式耳机仍然充满疑问&#xff1a;佩戴稳固舒适的开放式耳机应该怎么选择&#xff1f;开放式耳机的蓝牙版本该怎么选择&#xff1f;又有哪些开放式耳机品牌是可靠…

SkyWalking 高可用

生产环境中,后端应用需要支持高吞吐量并且支持高可用来保证服务的稳定,因此需要高可用集群管理。 集群方案 Skywalking集群是将 skywalking oap 作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一个skywalking oap在运行,就可以提供服务。 高可用…

【mmsegmentation】Loss模块(进阶)自定义自己的LOSS

1、定义自己的loss driving\models\losses\shuai_loss.py import torch from torch import nn from mmseg.models import LOSSESLOSSES.register_module() class ShuaiLoss(nn.Module):def __init__(self,loss_weight1.0):super().__init__()self.ce_loss nn.CrossEntropyLo…

躺平成长:微信小程序运营日记第二天

在进行属于生活的开源之后&#xff0c;自己更加感受到自己存在的渺茫&#xff0c;同时更加开始深刻领会&#xff0c;开源的重要性&#xff0c;在开源&#xff0c;开放&#xff0c;创造&#xff0c;再创新的思维模式下&#xff0c;不发布八部金刚功相关的训练视频&#xff0c;自…

详解Java中的Collection单列集合(从底层到用法超详细解析和细节分析)

⭕在 Java 中&#xff0c;集合框架是开发过程中最常用的数据结构之一&#xff0c;其中 Collection 接口是整个集合框架的基础。Collection 是处理单列数据的接口&#xff0c;它定义了一些通用的操作&#xff0c;允许对一组对象进行操作。今天我们将深入介绍 Java 中的单列集合 …

ECharts图表图例4

jave 用eclipse软件 代码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <!-- 引入ECharts脚本 --> <script src"js/echarts.js"></script> <title>绘制堆积面积图</title&g…

Unraid的cache使用btrfs或zfs?

Unraid的cache使用btrfs或zfs&#xff1f; 背景&#xff1a;由于在unraid中添加了多个docker和虚拟机&#xff0c;因此会一直访问硬盘。然而&#xff0c;单个硬盘实在难以让人放心。在阵列盘中&#xff0c;可以通过添加校验盘进行数据保护&#xff0c;在cache中无法使用xfs格式…

Leecode热题100-283.移动零

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入: nums [0] 输出: […

【Python报错已解决】ImportError: No module named ‘module‘

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

单目操作符、--、++和do-while循环

昨天我们算术操作符的除法和乘法&#xff0c;以及引入while和for循环&#xff0c;今天我们来看新的内容。 借助我们之前写的计算器代码来深入学习一下其他东西。 单目操作符——、--、& 除了昨天说的那些操作符之外&#xff0c;记不记得输入函数中有一个&这么一个符…

分散加载文件 scatter files

目录 一、加载域和执行域二、Image entry points三、映射符号四、链接器预定义符号1、将符号引入到程序中1.1 引入到 C/C1.2 引入到汇编 2、域相关的符号2.1 执行域符号 Image$$2.2 执行域符号 Load$$2.3 加载域符号 Load$$LR$$2.4 节相关的符号2.5 镜像符号2.6 输入节符号 五、…

HarmonyOS鸿蒙 Next 实现协调布局效果

HarmonyOS鸿蒙 Next 实现协调布局效果 ​ 假期愉快! 最近大A 的涨势实在是红的让人晕头转向&#xff0c;不知道各位收益如何&#xff0c;这会是在路上&#xff0c;还是已经到目的地了? 言归正传&#xff0c;最近有些忙&#xff0c;关于鸿蒙的实践系列有些脱节了&#xff0c;…

Electron 是如何工作的

1. 创建electron项目 pnpm init pnpm add -D electron修改配置项 package.json {"name": "electron-menu","version": "1.0.0","description": "","main": "main.js", // eletron入口&quo…

【重学 MySQL】四十七、表的操作技巧——修改、重命名、删除与清空

【重学 MySQL】四十七、表的操作技巧——修改、重命名、删除与清空 修改表添加字段语法示例注意事项 删除字段语法示例 修改字段使用 MODIFY COLUMN语法示例 使用 CHANGE COLUMN语法示例 重命名表语法示例 删除表语法示例 清空表使用 TRUNCATE TABLE使用 DELETE FROM对比 TRUNC…

聊聊晶圆厂中的常见口语(1)

知识星球里的学员问&#xff1a;半导体公司的工程师总爱用一些英语代替中文&#xff0c;比如care,show&#xff0c;用这种简单的单词代替中文&#xff0c;能不能给我们总结工程师常用的英语单词&#xff0c;比较口语化的&#xff01; 为什么晶圆厂会用很多英文口语&#xff1f…