PCL 点云配准-改进的RANSAC算法(粗配准)

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 计算FPFH特征

2.1.2 RANSAC配准

2.1.3 可视化点云

2.2完整代码

三、实现效果


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

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


一、概述

        RANSAC(Random Sample Consensus)是一种通过迭代来估计数据集内数学模型参数的算法,用于处理包含大量离群点的场景。在点云配准中,RANSAC算法可以在未知的条件下配准两个不同视角的点云,找到最佳的匹配变换矩阵。本文结合FPFH(Fast Point Feature Histograms)特征计算和改进的RANSAC算法,实现点云的粗配准。

1.1原理

        FPFH特征描述子是一种局部几何特征,用于提高点云之间的特征匹配精度。它通过计算点与邻域点的法向量关系来描述局部几何特征。FPFH与RANSAC结合,通过特征匹配找到两个点云间的最佳配准矩阵。

RANSAC配准的主要步骤:

  1. 随机选择三个点进行配准计算。
  2. 根据这些点生成初步的配准矩阵。
  3. 使用该矩阵配准整个点云,计算内点数量。
  4. 迭代多次,选择最佳配准结果。

1.2实现步骤

  1. 加载点云数据:从文件中加载源点云和目标点云。
  2. 计算FPFH特征:计算源点云和目标点云的FPFH特征。
  3. RANSAC配准:使用RANSAC算法配准两组点云,得到最佳配准矩阵。
  4. 可视化结果:展示配准前后的点云

1.3应用场景

  1. 多视角的点云配准。
  2. 无序数据点的粗配准。
  3. 机器人视觉中环境地图的构建和配准。

二、代码实现

2.1关键函数

2.1.1 计算FPFH特征

用于计算输入点云的FPFH特征,计算法向量并基于邻域特征计算FPFH描述子。

fpfhFeature::Ptr compute_fpfh_feature(pointcloud::Ptr input_cloud)
{pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());// 法向量估计pointnormal::Ptr normals(new pointnormal);pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;n.setInputCloud(input_cloud);    // 设置输入点云n.setNumberOfThreads(8);         // 使用8线程加速计算n.setSearchMethod(tree);         // 设置搜索方法为KD树n.setKSearch(10);                // 设置K近邻点个数n.compute(*normals);             // 计算法向量// FPFH特征估计fpfhFeature::Ptr fpfh(new fpfhFeature);pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fest;fest.setNumberOfThreads(8);      // 使用8线程并行计算fest.setInputCloud(input_cloud); // 设置输入点云fest.setInputNormals(normals);   // 设置输入法线fest.setSearchMethod(tree);      // 使用KD树搜索fest.setKSearch(10);             // 设置K近邻点个数fest.compute(*fpfh);             // 计算FPFH特征return fpfh;
}

2.1.2 RANSAC配准

该函数使用改进的RANSAC算法,通过特征匹配对两组点云进行配准,并返回配准后的点云。

pointcloud::Ptr ransac_registration(pointcloud::Ptr source, pointcloud::Ptr target, fpfhFeature::Ptr source_fpfh, fpfhFeature::Ptr target_fpfh)
{pcl::SampleConsensusPrerejective<PointT, PointT, pcl::FPFHSignature33> r_sac;r_sac.setInputSource(source);            // 设置源点云r_sac.setInputTarget(target);            // 设置目标点云r_sac.setSourceFeatures(source_fpfh);    // 设置源点云的FPFH特征r_sac.setTargetFeatures(target_fpfh);    // 设置目标点云的FPFH特征r_sac.setCorrespondenceRandomness(5);    // 随机特征对应时使用的邻居数量r_sac.setInlierFraction(0.5f);           // 设置所需的内点比例r_sac.setNumberOfSamples(3);             // 设置采样点的数量r_sac.setSimilarityThreshold(0.1f);      // 设置边缘长度相似度阈值r_sac.setMaxCorrespondenceDistance(1.0f);// 设置最大对应点距离r_sac.setMaximumIterations(100);         // 设置最大迭代次数pointcloud::Ptr aligned(new pointcloud); // 配准后的点云r_sac.align(*aligned);                   // 执行配准pcl::transformPointCloud(*source, *aligned, r_sac.getFinalTransformation()); // 对源点云进行变换cout << "变换矩阵:\n" << r_sac.getFinalTransformation() << endl;            // 输出变换矩阵return aligned;
}

2.1.3 可视化点云

在两个窗口中显示点云,窗口1显示配准前的点云,窗口2显示配准后的点云

void visualize_pcd(pointcloud::Ptr pcd_src, pointcloud::Ptr pcd_tgt, pointcloud::Ptr pcd_final)
{pcl::visualization::PCLVisualizer viewer("registration Viewer");// 创建两个显示窗口并设置背景颜色int v1, v2;viewer.createViewPort(0, 0.0, 0.5, 1.0, v1);viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);viewer.setBackgroundColor(255, 255, 255, v1);viewer.setBackgroundColor(255, 255, 255, v2);// 设置点云颜色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(pcd_src, 0, 255, 0);   // 源点云绿色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(pcd_tgt, 255, 0, 0);   // 目标点云红色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_h(pcd_final, 0, 255, 0); // 配准后的点云绿色// 添加点云到显示窗口viewer.addPointCloud(pcd_src, src_h, "source cloud", v1);viewer.addPointCloud(pcd_tgt, tgt_h, "target cloud", v1);viewer.addPointCloud(pcd_tgt, tgt_h, "tgt cloud", v2);viewer.addPointCloud(pcd_final, final_h, "final cloud", v2);while (!viewer.wasStopped()){viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}

2.2完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/features/fpfh_omp.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/registration/sample_consensus_prerejective.h> // RANSAC配准using namespace std;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<pcl::PointXYZ> pointcloud;
typedef pcl::PointCloud<pcl::Normal> pointnormal;
typedef pcl::PointCloud<pcl::FPFHSignature33> fpfhFeature;
typedef pcl::PointCloud<pcl::PointXYZ> pointcloud;// 计算FPFH特征
fpfhFeature::Ptr compute_fpfh_feature(pointcloud::Ptr input_cloud)
{pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());// 法向量估计pointnormal::Ptr normals(new pointnormal);pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;n.setInputCloud(input_cloud);    // 设置输入点云n.setNumberOfThreads(8);         // 使用8线程加速计算n.setSearchMethod(tree);         // 设置搜索方法为KD树n.setKSearch(10);                // 设置K近邻点个数n.compute(*normals);             // 计算法向量// FPFH特征估计fpfhFeature::Ptr fpfh(new fpfhFeature);pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fest;fest.setNumberOfThreads(8);      // 使用8线程并行计算fest.setInputCloud(input_cloud); // 设置输入点云fest.setInputNormals(normals);   // 设置输入法线fest.setSearchMethod(tree);      // 使用KD树搜索fest.setKSearch(10);             // 设置K近邻点个数fest.compute(*fpfh);             // 计算FPFH特征return fpfh;
}// RANSAC配准
pointcloud::Ptr ransac_registration(pointcloud::Ptr source, pointcloud::Ptr target, fpfhFeature::Ptr source_fpfh, fpfhFeature::Ptr target_fpfh)
{pcl::SampleConsensusPrerejective<PointT, PointT, pcl::FPFHSignature33> r_sac;r_sac.setInputSource(source);            // 设置源点云r_sac.setInputTarget(target);            // 设置目标点云r_sac.setSourceFeatures(source_fpfh);    // 设置源点云的FPFH特征r_sac.setTargetFeatures(target_fpfh);    // 设置目标点云的FPFH特征r_sac.setCorrespondenceRandomness(5);    // 随机特征对应时使用的邻居数量r_sac.setInlierFraction(0.5f);           // 设置所需的内点比例r_sac.setNumberOfSamples(3);             // 设置采样点的数量r_sac.setSimilarityThreshold(0.1f);      // 设置边缘长度相似度阈值r_sac.setMaxCorrespondenceDistance(1.0f);// 设置最大对应点距离r_sac.setMaximumIterations(100);         // 设置最大迭代次数pointcloud::Ptr aligned(new pointcloud); // 配准后的点云r_sac.align(*aligned);                   // 执行配准pcl::transformPointCloud(*source, *aligned, r_sac.getFinalTransformation()); // 对源点云进行变换cout << "变换矩阵:\n" << r_sac.getFinalTransformation() << endl;            // 输出变换矩阵return aligned;
}// 可视化
void visualize_pcd(pointcloud::Ptr pcd_src, pointcloud::Ptr pcd_tgt, pointcloud::Ptr pcd_final)
{pcl::visualization::PCLVisualizer viewer("registration Viewer");int v1, v2;viewer.createViewPort(0, 0.0, 0.5, 1.0, v1);viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);viewer.setBackgroundColor(255, 255, 255, v1);viewer.setBackgroundColor(255, 255, 255, v2);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(pcd_src, 0, 255, 0);   // 源点云绿色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(pcd_tgt, 255, 0, 0);   // 目标点云红色pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_h(pcd_final, 0, 255, 0); // 配准后的点云绿色viewer.addPointCloud(pcd_src, src_h, "source cloud", v1);viewer.addPointCloud(pcd_tgt, tgt_h, "target cloud", v1);viewer.addPointCloud(pcd_tgt, tgt_h, "tgt cloud", v2);viewer.addPointCloud(pcd_final, final_h, "final cloud", v2);while (!viewer.wasStopped()){viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}int main(int argc, char** argv)
{pcl::PointCloud<PointT>::Ptr source(new pcl::PointCloud<PointT>);pcl::io::loadPCDFile("1.pcd", *source);pcl::PointCloud<PointT>::Ptr target(new pcl::PointCloud<PointT>);pcl::io::loadPCDFile("2.pcd", *target);fpfhFeature::Ptr source_fpfh = compute_fpfh_feature(source);fpfhFeature::Ptr target_fpfh = compute_fpfh_feature(target);pointcloud::Ptr align = ransac_registration(source, target, source_fpfh, target_fpfh);visualize_pcd(source, target, align);return 0;
}

三、实现效果

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM高校课程评价的设计

教师账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;指标信息管理&#xff0c;课程信息管理&#xff0c;教师自评管理 学生账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;课程信息管理&#xff0c;学生评价管理 开发系统&#xff1a;…

不坑盒子在哪儿下载?

不坑盒子是一款Office办公软件的插件&#xff0c;支持MicroSoft Office和WPS的三件套&#xff08;Word、Excel、PPT&#xff09;。 可以为你的Office软件增加数百个实用功能&#xff0c;比如&#xff1a;自动排版、智能写作、仿手写、全文加拼音、稿子模板、一键删除、数据分发…

SAP物料凭证报表字段调整

业务场景&#xff1a; 报表MB51的输入和输出字段调整&#xff1a; 输入&#xff08;选择界面&#xff09; 输出界面 可以看到在这是没有布局调整的 后台路径&#xff1a; SPRO-物料管理-库存管理和实际库存-报表-定义物料凭证列表的字段选择 事务码&#xff1a;SM30-V_MMI…

docker构建jar镜像

文章目录 构建 DockerFile将jar包上传到创建的目录当中在目录中创建 Dockerfile 文件构建镜像创建并启动容器说明 构建 DockerFile [root192 /]# mkdir my [root192 /]# cd my [root192 my]# 将jar包上传到创建的目录当中 在目录中创建 Dockerfile 文件 vi Dockerfile FROM …

MFC工控项目实例二十四模拟量校正值输入

承接专栏《MFC工控项目实例二十三模拟量输入设置界面》 对模拟量输入的零点校正值及满量程对应的电压值进行输入。 1、在SenSet.h文件中添加代码 #include "BtnST.h" #include "ShadeButtonST.h"/ // SenSet dialogclass SenSet : public CDialog { // Co…

RPC通讯基础原理

1.RPC&#xff08;Remote Procedure Call&#xff09;概述 RPC是一种通过网络从远程计算机上调用程序的技术&#xff0c;使得构建分布式计算更加容易&#xff0c;在提供强大的远程调用能力时不损失本地调用的语义简洁性&#xff0c;提供一种透明调用机制&#xff0c;让使用者不…

Leetcode 跳跃游戏 二

核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 这段代码解决的是“跳跃游戏 II”&#xff08;Leetcode第45题&#xff09;&#xff0c;其核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 class Solution {public int jump(int[] nums) {//首先处理特殊情…

【文化课学习笔记】【化学】选必三:同分异构体的书写

【化学】选必三&#xff1a;同分异构体的书写 如果你是从 B 站一化儿笔记区来的&#xff0c;请先阅读我在第一篇有机化学笔记中的「读前须知」(点开头的黑色小三角展开)&#xff1a;链接 链状烃的取代和插空法 取代法 一取代物 甲烷、乙烷、丙烷、丁烷的种类 甲烷&#xff1a;只…

【AAOS】Android Automotive 14模拟器源码下载及编译

源码下载 repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r20 repo sync -c --no-tags --no-clone-bundle 源码编译 source build/envsetup.sh lunch sdk_car_x86_64-trunk_staging-eng make -j8 运行效果 emualtor Home All apps …

计算机是如何输入存储输出汉字、图片、音频、视频的

计算机是如何输入存储输出汉字、图片、音频、视频的 为了便于理解&#xff0c;先了解一下计算机的组成。 冯诺依曼计算机的五大组成部分。分别是运算器、控制器、存储器、输入设备和输出设备。参见下图&#xff1a; 一、运算器 运算器又称“算术逻辑单元”&#xff0c;是计算…

Android Camera2在textureView中的预览和拍照

Camera2预览和拍照 1、Camera2相机模型2、Camera2的重要类3、Camera2调用流程4、Camera2调用实现 1)定义TextureView作为预览界面2)设置相机参数3)开启相机4)开启相机预览5)实现PreviewCallback6)拍照 1、Camera2相机模型 解释上诉示意图&#xff0c;假如想要同时拍摄两张不同…

图像及视频的基本操作

文章目录 一、认识计算机中的图像二、图像数据的读取三、数据读取-视频四、图像的其他操作 一、认识计算机中的图像 一张彩色图片是由很多个像素点组合而成的&#xff0c;而一个像素点是由R G B三个通道组成。RGB代表红色&#xff08;Red&#xff09;、绿色&#xff08;Green&a…

【远程监控新体验】OpenObserve结合内网穿透无公网IP远程访问全攻略

文章目录 前言1. 安装Docker2. Docker镜像源添加方法3. 创建并启动OpenObserve容器4. 本地访问测试5. 公网访问本地部署的OpenObserve5.1 内网穿透工具安装5.2 创建公网地址6. 配置固定公网地址前言 本文主要介绍如何在Linux系统使用Docker快速本地化部署OpenObserve云原生可观…

MacOS RocketMQ安装

MacOS RocketMQ安装 文章目录 MacOS RocketMQ安装一、下载二、安装修改JVM参数启动关闭测试关闭测试测试收发消息运行自带的生产者测试类运行自带的消费者测试类参考博客&#xff1a;https://blog.csdn.net/zhiyikeji/article/details/140911649 一、下载 打开官网&#xff0c;…

并发-线程

1, 线程 线程(thread)也是并发的一种形式&#xff0c;线程是比进程更小的活动单位&#xff0c;一个进程中可以有多个线程&#xff0c;线程是进程内部的一个执行分支。 一个进程刚开始时只有一个线程(称之为主线程)&#xff0c;后续的代码中可以创建新的线程&#xff0c;可以指…

git提交到github个人记录

windows下git下载 1.进入git官网https://git-scm.com/downloads/win 一直默认选项即可 2.在settings中SSH and GPG keys中Add SSH key 3.选择git cmd git使用 1.配置用户名&#xff0c;和邮箱 git config --global user.email "youexample.com" git config --g…

aws(学习笔记第六课) AWS的虚拟私有,共有子网以及ACL,定义公网碉堡主机子网以及varnish反向代理

aws(学习笔记第六课) AWS的虚拟私有&#xff0c;共有子网以及ACL&#xff0c;定义公网碉堡主机子网以及varnish反向代理 学习内容&#xff1a; AWS的虚拟私有&#xff0c;共有子网以及ACL定义公网碉堡主机子网&#xff0c;私有子网和共有子网以及varnish反向代理 1. AWS的虚拟…

深入理解WPF中的命令机制

Windows Presentation Foundation&#xff08;WPF&#xff09;是微软推出的一种用于构建桌面客户端应用程序的技术。它被认为是现代Windows应用程序的基础&#xff0c;具有强大的图形和媒体处理能力。在WPF中&#xff0c;“命令”是一个重要的概念&#xff0c;它为应用程序开发…

如何在算家云搭建Video-Infinity(视频生成)

一、模型介绍 Video-Infinity是一个先进的视频生成模型&#xff0c;使用多个 GPU 快速生成长视频&#xff0c;无需额外训练。它能够基于用户提供的文本或图片提示&#xff0c;创造出高质量、多样化的视频内容。 二、模型搭建流程 1.大模型 Video-Infinity 一键使用 基础环境…

Nest.js 实战 (十四):如何获取客户端真实 IP

问题解析 在 Nest.js 应用中&#xff0c;当你试图通过 request.ip 获取客户端的 IP 地址时&#xff0c;如果总是返回 ::1 或者 ::ffff:127.0.0.1&#xff0c;这通常意味着请求来自本地主机。 因为在前后端分离应用中&#xff0c;前端请求后端服务一般的做法都是通过代理&…