PCL 点云配准-4PCS算法(粗配准)

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 加载点云数据

2.1.2 执行4PCS粗配准

2.1.3 可视化源点云、目标点云和配准结果

2.2完整代码

三、实现效果

3.1原始点云

3.2配准后点云


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

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


一、概述

        4PCS(四点一致集)算法是一种用于点云配准的粗配准方法。该算法通过寻找目标点云和源点云之间具有几何约束的四点集合进行匹配,继而估计出变换矩阵。4PCS 算法具有较好的抗噪性和计算效率,适用于较大尺度的点云配准场景。

1.1原理

4PCS 算法通过以下步骤进行粗配准:

  1. 点云采样:从源点云和目标点云中采样若干点,形成四点集合。
  2. 几何一致性验证:计算这四个点在两个点云中的相对距离,通过几何一致性约束找到符合要求的四点集合。
  3. 估计变换矩阵:使用一致的四点集合,计算源点云到目标点云的变换矩阵。
  4. 应用变换矩阵:将计算得到的变换矩阵应用到源点云上,使其与目标点云对齐。

配准结果的质量依赖于:

  • 重叠率:设置源点云和目标点云的近似重叠率。
  • 采样点数量:设置参与匹配的采样点数量。
  • 精度参数 Delta:控制配准的精度,通过对配准点云的稀疏化进行加速。

1.2实现步骤

  1. 加载源点云和目标点云。
  2. 设置4PCS配准参数:包括近似重叠率、采样点数量、精度参数等。
  3. 执行4PCS粗配准:通过设置参数执行粗配准,得到变换矩阵。
  4. 应用变换矩阵:将源点云应用变换矩阵对齐至目标点云。
  5. 可视化结果:将源点云、目标点云以及对齐后的点云进行可视化对比。

1.3应用场景

  1. 粗配准阶段:4PCS 可以用于点云配准的初步阶段,提供较为快速的粗略对齐结果,后续可以使用更精细的算法(如ICP)进行精配准。
  2. 多场景拼接:在多视角点云场景下,4PCS 可以帮助快速匹配不同视角的点云数据。
  3. 点云地图生成:在SLAM(同步定位与地图构建)中,4PCS 可以用于不同帧之间的点云匹配与对齐。

二、代码实现

2.1关键函数

2.1.1 加载点云数据

void loadPointClouds(pcl::PointCloud<pcl::PointXYZ>::Ptr& source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& target_cloud)
{
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("hand_trans.pcd", *target_cloud) == -1) {
        PCL_ERROR("读取目标点云失败 \n");
    }

    if (pcl::io::loadPCDFile<pcl::PointXYZ>("hand.pcd", *source_cloud) == -1) {
        PCL_ERROR("读取源点云失败 \n");
    }
}

2.1.2 执行4PCS粗配准

void perform4PCSRegistration(pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr aligned_cloud, Eigen::Matrix4f& transformation_matrix)
{
    pcl::registration::FPCSInitialAlignment<pcl::PointXYZ, pcl::PointXYZ> fpcs;
    fpcs.setInputSource(source_cloud);
    fpcs.setInputTarget(target_cloud);
    fpcs.setApproxOverlap(0.7);         // 设置近似重叠率
    fpcs.setDelta(0.01);                // 精度参数
    fpcs.setNumberOfSamples(100);       // 采样点数量

    fpcs.align(*aligned_cloud);         // 执行配准
    transformation_matrix = fpcs.getFinalTransformation(); // 获取变换矩阵
}

2.1.3 可视化源点云、目标点云和配准结果

// 可视化源点云、目标点云和配准结果
void visualizePointClouds(pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Point Cloud Registration Viewer"));

    viewer->setBackgroundColor(1.0, 1.0, 1.0);  // 设置背景颜色为黑色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> target_color(target_cloud, 255, 0, 0);
    viewer->addPointCloud(target_cloud, target_color, "target cloud"); // 目标点云(红色)

    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> source_color(source_cloud, 0, 0, 255);
    viewer->addPointCloud(source_cloud, source_color, "source cloud"); // 源点云(蓝色)

    

    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "source cloud");


    while (!viewer->wasStopped()) {
        viewer->spinOnce();
    }
}

2.2完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/ia_fpcs.h>
#include <pcl/console/time.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>

// 加载点云数据
void loadPointClouds(pcl::PointCloud<pcl::PointXYZ>::Ptr& source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& target_cloud)
{
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("hand_trans.pcd", *target_cloud) == -1) {
        PCL_ERROR("读取目标点云失败 \n");
    }

    if (pcl::io::loadPCDFile<pcl::PointXYZ>("hand.pcd", *source_cloud) == -1) {
        PCL_ERROR("读取源点云失败 \n");
    }
}

// 执行4PCS粗配准
void perform4PCSRegistration(pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr aligned_cloud, Eigen::Matrix4f& transformation_matrix)
{
    pcl::registration::FPCSInitialAlignment<pcl::PointXYZ, pcl::PointXYZ> fpcs;
    fpcs.setInputSource(source_cloud);
    fpcs.setInputTarget(target_cloud);
    fpcs.setApproxOverlap(0.7);         // 设置近似重叠率
    fpcs.setDelta(0.01);                // 精度参数
    fpcs.setNumberOfSamples(1000);       // 采样点数量

    fpcs.align(*aligned_cloud);         // 执行配准
    transformation_matrix = fpcs.getFinalTransformation(); // 获取变换矩阵
}

// 可视化源点云、目标点云和配准结果
// 可视化源点云、目标点云和配准结果
void visualizePointClouds(pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Point Cloud Registration Viewer"));

    viewer->setBackgroundColor(1.0, 1.0, 1.0);  // 设置背景颜色为黑色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> target_color(target_cloud, 255, 0, 0);
    viewer->addPointCloud(target_cloud, target_color, "target cloud"); // 目标点云(红色)

    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> source_color(source_cloud, 0, 0, 255);
    viewer->addPointCloud(source_cloud, source_color, "source cloud"); // 源点云(蓝色)

    

    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "source cloud");


    while (!viewer->wasStopped()) {
        viewer->spinOnce();
    }
}




int main(int argc, char** argv)
{
    pcl::console::TicToc time;
    pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud(new pcl::PointCloud<pcl::PointXYZ>);

    loadPointClouds(source_cloud, target_cloud);

    pcl::PointCloud<pcl::PointXYZ>::Ptr aligned_cloud(new pcl::PointCloud<pcl::PointXYZ>);
    Eigen::Matrix4f transformation_matrix;

    time.tic();
    perform4PCSRegistration(source_cloud, target_cloud, aligned_cloud, transformation_matrix);
    cout << "FPCS配准用时: " << time.toc() << " ms" << endl;
    cout << "变换矩阵:" << transformation_matrix << endl;

    //显示原始点云
    visualizePointClouds(source_cloud, target_cloud);
    //显示配准后点云
    visualizePointClouds(target_cloud, aligned_cloud);


    return 0;
}

三、实现效果

3.1原始点云

3.2配准后点云

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试八股(自用)

什么是java序列化&#xff0c;什么时候需要序列化? 序列化是指将java对象转化成字节流的过程&#xff0c;反序列化是指将字节流转化成java对象的过程。 当java对象需要在网络上传输 或者 持久化到存储文件中&#xff0c;就需要对java对象进行序列化处理。 JVM的主要组成部分…

Lumerical学习——分析工具(Analysis tools)

一、分析工具和模拟环境&#xff08;Analysis tools and the simulation environment&#xff09; 模拟计算完成后&#xff0c;模拟计算数据紧接着写到模拟工程文件中&#xff1b;甚至当模拟计算提前结束时计算得到的部分数据集也会写到文件中。当模拟完成后单击退出按钮、或者…

为什么inet_ntoa会返回错误的IP地址?

目录 1、调用inet_addr和inet_ntoa实现整型IP与点式字符串之间的转换 1.1、调用inet_addr将点式字符串IP转换成整型IP 1.2、调用inet_ntoa将整型IP转换成点式字符串IP 2、调用inet_ntoa返回错误点式字符串IP的原因分析 3、解决多线程调用inet_ntoa返回错误点式字符串IP的办…

RTSP与ONVIF协议的区别及其在EasyCVR视频汇聚平台中的应用

在视频监控和物联网设备领域&#xff0c;RTSP&#xff08;Real Time Streaming Protocol&#xff09;和ONVIF&#xff08;Open Network Video Interface Forum&#xff09;是两个重要的协议&#xff0c;它们各自在视频流的传输和控制上发挥着不同的作用&#xff0c;并在实际应用…

,1.2,unity动画Animator

1.步骤&#xff1a; &#xff08;1&#xff09;导入模型 &#xff08;2&#xff09;添加状态机 &#xff08;3&#xff09;添加动画控制器 &#xff08;4&#xff09;通过脚本触发条件 (5)控制脚本代码 using System.Collections; using System.Collections.Generic; usin…

HarmonyOS中ArkUi框架中常用的装饰器

目录 1.装饰器 1&#xff09;Component 1--装饰内容 2&#xff09;Entry 1--装饰内容 2--使用说明 3&#xff09;Preview 1--装饰内容 2--使用说明 4&#xff09;CustomDialog 1--装饰内容 2--使用说明 5&#xff09;Observed 1--装饰内容 2--使用说明 6&#xff09;ObjectLin…

我的创作纪念日-365天的感悟

时光荏苒&#xff0c;岁月如梭。转眼间&#xff0c;自己在CSDN注册已经整整15个年头了。回想起当初&#xff0c;还是个满怀憧憬、对未来充满无限好奇的学生哥。如今&#xff0c;虽然身份和角色发生了诸多变化&#xff0c;但CSDN始终陪伴着我&#xff0c;见证了我的成长与蜕变。…

HDFS详细分析

目录 一、HDFS架构 &#xff08;1&#xff09;Block - 数据块 &#xff08;2&#xff09;MetaData - 元数据 &#xff08;3&#xff09;NameNode - 主结点 &#xff08;4&#xff09;DataNode - 从结点 &#xff08;5&#xff09;SecondaryNameNode 二、HDFS的特点 &…

Spring Security 基础配置详解(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09; 1. 基本知识 HttpSecurity 是 Spri…

ubuntu 安装docker, docker-compose

1. 安装curl apt-get update apt upgradeapt install curl 2.安装&#xff1a; curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 3. 验证&#xff1a; docker -v 4. 安装docker-compose : # 下载 curl -L "https://github.com/docker/compose/rel…

无人机之定高算法篇

一、无人机高度测量原理 无人机的高度测量通常依赖于多种传感器&#xff0c;其中主要包括&#xff1a; 气压计&#xff1a;通过测量大气压力的变化来确定高度。在大气中&#xff0c;随着高度的增加&#xff0c;气压会逐渐降低。无人机搭载的气压计会感知大气的压力变化&#…

DBSwitch和Seatunel

一、DBSwitch 什么是DBSwitch?它主要用在什么场景&#xff1f; 通过步骤分析可以看到这个是通过配置数据源&#xff0c;采用一次性或定时方案&#xff0c;同步到数据仓库的指定表&#xff0c;并且指定映射关系的工具。有点类似于flinkcdc的增量同步。 参考&#xff1a; dbs…

【SpringBoot】13 XML格式的请求和响应

Gitee仓库 https://gitee.com/Lin_DH/system 介绍 可扩展标记语言 (Extensible Markup Language, XML) &#xff0c;标准通用标记语言的子集&#xff0c;可以用来标记数据、定义数据类型&#xff0c;是一种允许用户对自己的标记语言进行定义的源语言。 XML是标准通用标记语言…

重学SpringBoot3-集成Redis(十二)之点赞功能实现

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;十二&#xff09;之点赞功能实现 1. 点赞功能的场景分析2. 项目环境配置2.1. 依赖引入2.2. Redis 配置 3. 点赞功能的实现3.1. 点…

【R语言】gadm全球行政区划数据库

我R语言不熟、也不是学GIS的。仅用于记录。 文章目录 一、gadm 数据库简介二、R 语言示例三、sf 包的函数 一、gadm 数据库简介 GADM&#xff08;全称Database of Global Administrative Areas&#xff09;是一个高精度的全球行政区划数据库&#xff0c;它包含了全球所有国家和…

步步精科技诚邀您参加2024慕尼黑华南电子展

尊敬的客户&#xff1a; 我们诚挚地邀请您参加即将于2024年10月14日至10月16日在深圳国际会展中心 &#xff08;宝安新馆&#xff09;举办的慕尼黑华南电子展(electronica South China)。本届将聚焦人工智能、数据中心、新型储能、无线通信、硬件安全、新能源汽车、第三代半导…

ubuntu系统使用Linux版原生微信

背景 既想用ubuntu操作系统&#xff0c;又同时想使用微信&#xff0c;但是ubuntu默认的应用商店是不支持安装微信的 解决 本电脑安装的当前最新版本的ubuntu系统24.04.1TLS操作系统 使用终端命令行安装铜豌豆软件源。注意需要用到sudo权限。需要切换到root用户&#xff08;…

【C++标准模版库】unordered_map和unordered_set的介绍及使用

unordered_map和unordered_set 一.unordered_set1.unordered_set类的介绍2.unordered_set和set的使用差异 二.unordered_map1.unordered_map和map的使用差异 三.unordered_multimap/unordered_multiset四.unordered_map/unordered_set的哈希相关接口 一.unordered_set 1.unord…

C++入门基础知识116—【关于C++多维数组】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C多维数组的相关内容&#xff01; 关于【…

springboot将logback替换成log4j2

一 为何要替换成log4j2 1.1 log4j2的优点 log4j2使用了两种方式记录日志&#xff1a;AsyncAppender和AsyncLogger。 1.AsyncAppender使用队列异步记录日志&#xff0c;但是一旦队列已满&#xff0c;appender线程需要等待。2.AsyncLogger是采用Disruptor&#xff0c;通过环形…