PCL 基于中值距离的点云对应关系

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 获取中值距离筛选后的对应点对

2.1.2获取初始点对

2.1.3可视化

2.2完整代码

三、实现效果


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

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


一、概述

        在点云配准过程中,初始对应点对可能包含错误匹配的点对,因此在执行进一步的精确配准(如ICP算法)之前,通常需要进行初步的筛选。通过基于中值距离的方法,可以有效剔除错误匹配的点对。此方法通过计算所有匹配点对的距离中值,然后剔除距离大于中值乘以系数的点对,从而保留正确匹配的点对

1.1原理

中值距离剔除算法 是通过以下步骤进行的:
1.获取初始对应点对:通过最近邻搜索等方法,找到源点云和目标点云之间的初始匹配点对。
2.计算距离:对于每对匹配点,计算两者之间的欧几里得距离。其计算公式为:

3.计算距离中值:对所有匹配点对的距离进行排序,找到中值距离 𝑑。
4.剔除错误匹配:将距离大于 𝑑×k 的匹配点对视为错误点对剔除,𝑘 为用户指定的系数,控制筛选的严格程度。通常,较小的 𝑘 值会剔除更多的点对,较大的 𝑘 值会保留更多的点对。
5.输出筛选结果:保留满足筛选条件的匹配点对,作为进一步配准或分析的基础。

1.2实现步骤

  1. 加载点云数据:读取源点云和目标点云。
  2. 获取对应关系:通过最近邻搜索获取初始的匹配点对。
  3. 基于中值距离进行筛选:计算匹配点对的距离中值,剔除大于中值乘以系数的匹配点对。
  4. 可视化结果:展示源点云、目标点云及其筛选后的匹配点对。

1.3应用场景

  1. 点云配准的初步过滤:基于中值距离剔除错误的对应点对,可以用于提高后续精配准算法(如ICP)的效率和准确性。
  2. 物体识别与姿态估计:通过剔除错误的对应关系,提高点云识别与定位的准确性。
  3. 多视角点云拼接:在多视角点云拼接中,基于中值距离可以有效剔除多余或错误的匹配点对。

二、代码实现

2.1关键函数

2.1.1 获取中值距离筛选后的对应点对

float reject_correspondences_by_median(const pcl::CorrespondencesPtr& correspondences,
                                       pcl::CorrespondencesPtr& correspondences_result_rej_media,
                                       float median_factor = 0.2)
{
    pcl::registration::CorrespondenceRejectorMedianDistance rejector;
    rejector.setInputCorrespondences(correspondences); // 输入初始匹配点对
    rejector.setMedianFactor(median_factor);  // 设置中值系数,控制筛选严格程度
    rejector.getCorrespondences(*corres
    
    
    
    pondences_result_rej_media); // 获取剔除后的匹配点对
    return rejector.getMedianDistance();  // 返回中值距离
}

2.1.2获取初始点对

// 函数:获取初始对应点对
void get_correspondences(const pcl::PointCloud<pcl::PointXYZ>::Ptr& source,
    const pcl::PointCloud<pcl::PointXYZ>::Ptr& target,
    pcl::CorrespondencesPtr& correspondences)
{
    pcl::registration::CorrespondenceEstimation<pcl::PointXYZ, pcl::PointXYZ> corr_est;
    corr_est.setInputSource(source);  // 设置源点云
    corr_est.setInputTarget(target);  // 设置目标点云
    corr_est.determineCorrespondences(*correspondences); // 获取初始匹配点对
}

2.1.3可视化

void visualize_correspondences(const pcl::PointCloud<pcl::PointXYZ>::Ptr& source,
                               const pcl::PointCloud<pcl::PointXYZ>::Ptr& target,
                               const pcl::CorrespondencesPtr& correspondences)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("media_distance"));

    viewer->setBackgroundColor(0, 0, 0);  // 设置背景颜色为黑色

    // 为目标点云设置红色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> target_color(target, 255, 0, 0);
    viewer->addPointCloud<pcl::PointXYZ>(target, target_color, "target cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target cloud");

    // 为源点云设置绿色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> source_color(source, 0, 255, 0);
    viewer->addPointCloud<pcl::PointXYZ>(source, source_color, "source cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "source cloud");

    // 可视化对应关系
    viewer->addCorrespondences<pcl::PointXYZ>(source, target, *correspondences, "correspondence");

    // 开启渲染循环,直到窗口关闭
    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/point_types.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/registration/correspondence_estimation.h>  // 获取对应关系的基类
#include <pcl/registration/correspondence_rejection_median_distance.h>  // 使用中值距离剔除的类

using namespace std;

// 函数:获取初始对应点对
void get_correspondences(const pcl::PointCloud<pcl::PointXYZ>::Ptr& source,
    const pcl::PointCloud<pcl::PointXYZ>::Ptr& target,
    pcl::CorrespondencesPtr& correspondences)
{
    pcl::registration::CorrespondenceEstimation<pcl::PointXYZ, pcl::PointXYZ> corr_est;
    corr_est.setInputSource(source);  // 设置源点云
    corr_est.setInputTarget(target);  // 设置目标点云
    corr_est.determineCorrespondences(*correspondences); // 获取初始匹配点对
}

// 函数:基于中值距离剔除错误对应关系并返回中值距离
float reject_correspondences_by_median(const pcl::CorrespondencesPtr& correspondences,
    pcl::CorrespondencesPtr& correspondences_result_rej_media,
    float median_factor = 0.2)
{
    pcl::registration::CorrespondenceRejectorMedianDistance rejector;
    rejector.setInputCorrespondences(correspondences); // 输入初始匹配点对
    rejector.setMedianFactor(median_factor);  // 设置中值系数,控制筛选严格程度
    rejector.getCorrespondences(*correspondences_result_rej_media); // 获取剔除后的匹配点对
    return rejector.getMedianDistance();  // 返回中值距离
}

// 函数:可视化点云及其对应关系
void visualize_correspondences(const pcl::PointCloud<pcl::PointXYZ>::Ptr& source,
    const pcl::PointCloud<pcl::PointXYZ>::Ptr& target,
    const pcl::CorrespondencesPtr& correspondences)
{
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("基于中值距离的对应关系"));

    viewer->setBackgroundColor(0, 0, 0);  // 设置背景颜色为黑色

    // 为目标点云设置红色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> target_color(target, 255, 0, 0);
    viewer->addPointCloud<pcl::PointXYZ>(target, target_color, "target cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target cloud");

    // 为源点云设置绿色
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> source_color(source, 0, 255, 0);
    viewer->addPointCloud<pcl::PointXYZ>(source, source_color, "source cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "source cloud");

    // 可视化对应关系
    viewer->addCorrespondences<pcl::PointXYZ>(source, target, *correspondences, "correspondence");

    // 开启渲染循环,直到窗口关闭
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }
}

int main(int argc, char** argv)
{
    // 1. 加载点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr source(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr target(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile<pcl::PointXYZ>("1.pcd", *source);
    pcl::io::loadPCDFile<pcl::PointXYZ>("2.pcd", *target);

    cout << "源点云: " << source->size() << " 个点" << endl;
    cout << "目标点云: " << target->size() << " 个点" << endl;

    // 2. 获取初始对应点对
    pcl::CorrespondencesPtr correspondences(new pcl::Correspondences);
    get_correspondences(source, target, correspondences);

    // 3. 基于中值距离剔除错误对应点对,并获取中值距离
    pcl::CorrespondencesPtr correspondences_result_rej_media(new pcl::Correspondences);
    float median_distance = reject_correspondences_by_median(correspondences, correspondences_result_rej_media);

    cout << "初始对应点对数量: " << correspondences->size() << endl;
    cout << "中值距离为: " << median_distance << endl;
    cout << "基于中值距离剔除后剩余: " << correspondences_result_rej_media->size() << endl;

    // 4. 可视化结果
    visualize_correspondences(source, target, correspondences_result_rej_media);

    return 0;
}

三、实现效果

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

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

相关文章

NetSuite Transfer Order Saved Search的关键字段取值

针对于Transfer Order的Saved Search&#xff0c;我们最经常遇到的问题就是如何取到From Location&#xff0c;To Location&#xff0c;Quantity Fulfilled&#xff0c;Quantity Received这几个值。 原生的TO Register无法取到对应的信息&#xff0c;系统中也没有相应的标准Se…

关于vue3中如何实现多个v-model的自定义组件

实现自定义组件<User v-model"userInfo" v-model:gender"gender"></User> User组件中更改数据可以同步更改父组件中的数据&#xff1a; 1 父组件&#xff1a; <User v-model"userInfo" v-model:gender"gender">&…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第十七集:制作第一个BOSS苍蝇之母

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、战斗场景Battle Scene相关逻辑处理 1.防止玩家走出战斗场景的门2.制作一个简单的战斗场景二、制作游戏第一个BOSS苍蝇之母 1.导入素材和制作相关动画2.制作…

C#从零开始学习(GameObject实例)(unity Lab3)

这是书本中第三个unity Lab 在这次实验中,将学习如何使用C#编写代码用unity编写C#代码 GameObject实例 本次将完成的工作 将游戏资产配置在文件夹中创建材质把GameObject变成预制件脚本控制游戏防止球体重叠 将游戏资产配置在文件夹中 Script放代码 Prefabs放预制件 MAteria…

PostgreSQL的学习心得和知识总结(一百五十五)|[performance]优化期间将 WHERE 子句中的 IN VALUES 替换为 ANY

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

RabbitMQ系列学习笔记(八)--发布订阅模式

文章目录 一、发布订阅模式原理二、发布订阅模式实战1、消费者代码2、生产者代码3、查看运行结果 本文参考&#xff1a; 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程(配图) 一、发布订阅模式原理 在开发过程中&…

大数据治理的核心思想

目录 ​编辑1.1 大数据治理的定义与重要性 1.2 大数据治理的关键要素 1.2.1 数据质量管理 1.2.2 数据安全管理 1.2.3 合规性管理 1.2.4 数据共享与协作 1.2.5 数据驱动的决策 二、对未来趋势的看法 2.1 技术发展趋势 2.1.1 人工智能与机器学习 2.1.2 云计算与边缘计…

Python数据处理工具笔记 - matplotlib, Numpy, Pandas

matplotlib, Numpy, Pandas 由于有很多例子是需要运算后的图表看着更明白一些&#xff0c;很明显csdn不支持 所以用谷歌的Colab(可以理解为白嫖谷歌的云端来运行的jupyter notebook)来展示&#xff1a; Colab链接(需要梯子)&#xff1a;Python数据挖掘 当然如果实在没有梯子&…

算法打卡 Day43(动态规划)-背包问题 + 分割等和子集

文章目录 0-1 背包问题理论基础0-1 背包问题滚动数组Leetcode 416-分割等和子集题目描述解题思路 0-1 背包问题理论基础 0-1 背包一般的题目要求是给定不同重量不同价值的物品&#xff0c;每个物品只有一个&#xff0c;已知背包中最大的负重&#xff0c;求在此限制条件下背包中…

达那福发布新品音致系列:以顶尖降噪技术,开启清晰聆听新篇章

近日&#xff0c;国际知名助听器品牌达那福推出其最新研发的音致系列助听器。该系列产品旨在通过顶尖的声音处理技术&#xff0c;直面助听器市场中普遍存在的挑战——如何在噪声环境中提供清晰的语音辨识。 根据助听器行业协会2022年的调查数据&#xff0c;高达86%的佩戴者认为…

数据结构——二叉树的基本操作及进阶操作

前言 介绍 &#x1f343;数据结构专区&#xff1a;数据结构 参考 该部分知识参考于《数据结构&#xff08;C语言版 第2版&#xff09;》116 ~ 122页 及 《数据结构教程》201 ~ 213页 重点 树的基本实现并不难&#xff0c;重点在于对递归的理解才是树这部分知识带来的最大收…

jmeter学习(8)界面的使用

1、新建test plan 3、 打开文件 4、保存 5、剪切 6、复制 7、粘贴 8、所有线程组展开 9、所有线程组收缩 10、置灰&#xff0c;操作后无法使用 11、执行 13、清空当前线程组结果 14、清空所有线程组结果 15、函数助手 搜索&#xff0c;可以用于搜索某个请求&#x…

Java基于微信小程序的健身小助手打卡预约教学系统(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

使用OpenCV进行视频边缘检测:案例Python版江南style

1. 引言 本文将演示如何使用OpenCV库对视频中的每一帧进行边缘检测&#xff0c;并将结果保存为新的视频文件。边缘检测是一种图像处理技术&#xff0c;它可以帮助我们识别出图像中不同区域之间的边界。在计算机视觉领域&#xff0c;这项技术有着广泛的应用&#xff0c;比如物体…

登录时用户名密码加密传输(包含前后端代码)

页面输入用户名密码登录过程中&#xff0c;如果没有对用户名密码进行加密处理&#xff0c;可能会导致传输过程中数据被窃取&#xff0c;就算使用https协议&#xff0c;在浏览器控制台的Request Payload中也是能直接看到传输的明文&#xff0c;安全感是否还是不足。 大致流程&a…

redis—cluster集群

一&#xff1a;Redis Cluster特点 多主多从&#xff0c;去中心化&#xff1a;从节点作为备用&#xff0c;复制主节点&#xff0c;不做读写操作&#xff0c;不提供服务不支持处理多个key&#xff1a;因为数据分散在多个节点&#xff0c;在数据量大高并发的情况下会影响性能&…

Columns Page “列”页面

“列”页提供了列管理工具&#xff0c;其中包括用于添加和删除列的按钮、显示绑定数据源中字段名称的列表框以及网格列、提供对所选列属性的访问的属性网格。 Columns 页面提供 Column properties &#xff08;列属性&#xff09;、Column options &#xff08;列选项&#xff…

Electron-(三)网页报错处理与请求监听

在前端开发中&#xff0c;Electron 是一个强大的框架&#xff0c;它允许我们使用 Web 技术构建跨平台的桌面应用程序。在开发过程中&#xff0c;及时处理网页报错和监听请求是非常重要的环节。本文将详细介绍 Electron 中网页报错的日志记录、webContents 的监听事件以及如何监…

如何使用JMeter进行性能测试的保姆级教程

性能测试是确保网站在用户访问高峰时保持稳定和快速响应的关键环节。作为初学者&#xff0c;选择合适的工具尤为重要。JMeter 是一个强大的开源性能测试工具&#xff0c;可以帮助我们轻松模拟多用户场景&#xff0c;测试网站的稳定性与性能。本教程将引导你通过一个简单的登录场…

微信小程序canvas 生成二维码图片,画图片,生成图片,将两个canvas结合并保存图片

需求实现步骤如下 先定义两个canvas一个canvas myQrcode画二维码的图片另一个canvas mycanvas画一个背景图&#xff0c;并把二维码画到这个canvas上&#xff0c;mycanvas这个canvas生成一张图片&#xff0c;返回图片的临时路径最后保存图片到手机 首先wxml,新版微信小程序can…