当前位置: 首页 > news >正文

基于Open3D的点云处理16-特征点匹配

点云配准

将点云数据统一到一个世界坐标系的过程称之为点云配准或者点云拼接。(registration/align)

点云配准的过程其实就是找到同名点对;即找到在点云中处在真实世界同一位置的点。

常见的点云配准算法:
ICP、Color ICP、Trimed-ICP 算法流程:

  1. 选点:
    确定参与到配准过程中的点集。
  2. 匹配确定同名点对:
    ICP以两片点云中欧式空间距离最小的点对为同名点
  3. 非线性优化求解:
    采用SVD或者四元数求解变换
  4. 变换:
    将求解的变换参数应用到待配准点云上
  5. 迭代:
    计算此时的状态参数判断配准是否完成。以前后两次参数迭代变
    化的差或者RMSE值是否小于给定阈值为迭代终止条件。否则返回(1)

ICP 算法以两片点云中欧式空间距离最小的点对为同名点,如果初始点选择不合适,可能会陷入局部最优配准失败。

基于点特征的配准方法
两种方式:
一种通过特征描述,先分割出场景里的点线等特征,利用这些点进行同名点的匹配,如基于几何空间一致性筛选同名点对。
一种通过点特征描述符确定同名点,如基于FPFH双向最近邻确定同名点对,FPFH描述向量最大的特性是对于点云的同名点的特征向量表现出相似性,即该点云的同名点之间的FPFH特征描述子的二范数趋于零。

测试用例

基于icp的点云匹配(参考)

  • 点到点的配准
import open3d as o3d
import numpy as np# 获取示例数据
source_cloud = o3d.io.read_point_cloud("./data/cloud_bin_0.pcd")
target_cloud = o3d.io.read_point_cloud("./data/cloud_bin_1.pcd")
source_cloud.paint_uniform_color([1, 0.706, 0])
target_cloud.paint_uniform_color([0, 0.651, 0.929])
threshold = 0.02# RMSE残差阈值,小于该残差阈值,迭代终止#初始位姿
trans_init = np.asarray([[0.862, 0.011, -0.507, 0.5],[-0.139, 0.967, -0.215, 0.7],[0.487, 0.255, 0.835, -1.4], [0.0, 0.0, 0.0, 1.0]])# 显示未配准点云
o3d.visualization.draw_geometries([source_cloud, target_cloud],zoom=0.4459,front=[0.9288, -0.2951, -0.2242],lookat=[1.6784, 2.0612, 1.4451],up=[-0.3402, -0.9189, -0.1996])# 点到点的ICP
result = o3d.pipelines.registration.registration_icp(source_cloud, target_cloud, threshold,trans_init,o3d.pipelines.registration.TransformationEstimationPointToPoint())
print(result)
print("Transformation is:")
print(result.transformation)# 显示点到点的配准结果
source_cloud.transform(result.transformation)
o3d.visualization.draw_geometries([source_cloud, target_cloud],zoom=0.4459,front=[0.9288, -0.2951, -0.2242],lookat=[1.6784, 2.0612, 1.4451],up=[-0.3402, -0.9189, -0.1996])

配准前:
配准前
配准结果:
配准结果
在这里插入图片描述

  • 点到面的配准
import open3d as o3d
import numpy as np# 获取示例数据
source_cloud = o3d.io.read_point_cloud("./data/cloud_bin_0.pcd")
target_cloud = o3d.io.read_point_cloud("./data/cloud_bin_1.pcd")
source_cloud.paint_uniform_color([1, 0.706, 0])
target_cloud.paint_uniform_color([0, 0.651, 0.929])
threshold = 0.02# RMSE残差阈值,小于该残差阈值,迭代终止#初始位姿
trans_init = np.asarray([[0.862, 0.011, -0.507, 0.5],[-0.139, 0.967, -0.215, 0.7],[0.487, 0.255, 0.835, -1.4], [0.0, 0.0, 0.0, 1.0]])source_cloud = o3d.io.read_point_cloud("./data/cloud_bin_0.pcd")
target_cloud = o3d.io.read_point_cloud("./data/cloud_bin_1.pcd")
source_cloud.paint_uniform_color([1, 0.706, 0])
target_cloud.paint_uniform_color([0, 0.651, 0.929])# 显示未配准点云
o3d.visualization.draw_geometries([source_cloud, target_cloud],zoom=0.4459,front=[0.9288, -0.2951, -0.2242],lookat=[1.6784, 2.0612, 1.4451],up=[-0.3402, -0.9189, -0.1996])# 点到面的ICP
result = o3d.pipelines.registration.registration_icp(source_cloud, target_cloud, threshold,trans_init,o3d.pipelines.registration.TransformationEstimationPointToPlane())
print(result)
print("Transformation is:")
print(result.transformation, "\n")# 显示点到面的配准结果
source_cloud.transform(result.transformation)
o3d.visualization.draw_geometries([source_cloud, target_cloud],zoom=0.4459,front=[0.9288, -0.2951, -0.2242],lookat=[1.6784, 2.0612, 1.4451],up=[-0.3402, -0.9189, -0.1996])

配准结果如图:
在这里插入图片描述
在这里插入图片描述

基于Color ICP的点云匹配 参考


import open3d as o3d
import numpy as np
import copydef draw_registration_result_original_color(source, target, transformation):source_temp = copy.deepcopy(source)source_temp.transform(transformation)o3d.visualization.draw_geometries([source_temp, target],zoom=0.5,front=[-0.2458, -0.8088, 0.5342],lookat=[1.7745, 2.2305, 0.9787],up=[0.3109, -0.5878, -0.7468])
print("1. Load two point clouds and show initial pose")
demo_colored_icp_pcds = o3d.data.DemoColoredICPPointClouds()
source = o3d.io.read_point_cloud(demo_colored_icp_pcds.paths[0])
target = o3d.io.read_point_cloud(demo_colored_icp_pcds.paths[1])# draw initial alignment
current_transformation = np.identity(4)
draw_registration_result_original_color(source, target, current_transformation)# point to plane ICP
current_transformation = np.identity(4)
print("2. Point-to-plane ICP registration is applied on original point")
print("   clouds to refine the alignment. Distance threshold 0.02.")
result_icp = o3d.pipelines.registration.registration_icp(source, target, 0.02, current_transformation,o3d.pipelines.registration.TransformationEstimationPointToPlane())
print(result_icp)
draw_registration_result_original_color(source, target,result_icp.transformation)# colored pointcloud registration
# This is implementation of following paper
# J. Park, Q.-Y. Zhou, V. Koltun,
# Colored Point Cloud Registration Revisited, ICCV 2017
voxel_radius = [0.04, 0.02, 0.01]
max_iter = [50, 30, 14]
current_transformation = np.identity(4)
print("3. Colored point cloud registration")
for scale in range(3):iter = max_iter[scale]radius = voxel_radius[scale]print([iter, radius, scale])print("3-1. Downsample with a voxel size %.2f" % radius)source_down = source.voxel_down_sample(radius)target_down = target.voxel_down_sample(radius)print("3-2. Estimate normal.")source_down.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=radius * 2, max_nn=30))target_down.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=radius * 2, max_nn=30))print("3-3. Applying colored point cloud registration")result_icp = o3d.pipelines.registration.registration_colored_icp(source_down, target_down, radius, current_transformation,o3d.pipelines.registration.TransformationEstimationForColoredICP(),o3d.pipelines.registration.ICPConvergenceCriteria(relative_fitness=1e-6,relative_rmse=1e-6,max_iteration=iter))current_transformation = result_icp.transformationprint(result_icp)
draw_registration_result_original_color(source, target,result_icp.transformation)

配准前:
在这里插入图片描述

基于点到平面icp的配准:
在这里插入图片描述

基于color icp的配准结果:
在这里插入图片描述

基于fpfh特征的点云匹配

import numpy as np
import copy
import open3d as o3ddef draw_registration_result(source, target, transformation):source_temp = copy.deepcopy(source)target_temp = copy.deepcopy(target)source_temp.paint_uniform_color([1, 0.706, 0])target_temp.paint_uniform_color([0, 0.651, 0.929])source_temp.transform(transformation)o3d.visualization.draw_geometries([source_temp, target_temp],zoom=0.4559,front=[0.6452, -0.3036, -0.7011],lookat=[1.9892, 2.0208, 1.8945],up=[-0.2779, -0.9482, 0.1556])def preprocess_point_cloud(pcd, voxel_size):print(":: Downsample with a voxel size %.3f." % voxel_size)pcd_down = pcd.voxel_down_sample(voxel_size)radius_normal = voxel_size * 2print(":: Estimate normal with search radius %.3f." % radius_normal)pcd_down.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))radius_feature = voxel_size * 5print(":: Compute FPFH feature with search radius %.3f." % radius_feature)pcd_fpfh = o3d.pipelines.registration.compute_fpfh_feature(pcd_down,o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100))return pcd_down, pcd_fpfhdef prepare_dataset(voxel_size):print(":: Load two point clouds and disturb initial pose.")demo_icp_pcds = o3d.data.DemoICPPointClouds()source = o3d.io.read_point_cloud(demo_icp_pcds.paths[0])target = o3d.io.read_point_cloud(demo_icp_pcds.paths[1])trans_init = np.asarray([[0.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 0.0],[0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]])source.transform(trans_init)draw_registration_result(source, target, np.identity(4))source_down, source_fpfh = preprocess_point_cloud(source, voxel_size)target_down, target_fpfh = preprocess_point_cloud(target, voxel_size)return source, target, source_down, target_down, source_fpfh, target_fpfhdef execute_global_registration(source_down, target_down, source_fpfh,target_fpfh, voxel_size):distance_threshold = voxel_size * 1.5print(":: RANSAC registration on downsampled point clouds.")print("   Since the downsampling voxel size is %.3f," % voxel_size)print("   we use a liberal distance threshold %.3f." % distance_threshold)result = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(source_down, target_down, source_fpfh, target_fpfh, True,distance_threshold,o3d.pipelines.registration.TransformationEstimationPointToPoint(False),3, [o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(0.9),o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(distance_threshold)], o3d.pipelines.registration.RANSACConvergenceCriteria(100000, 0.999))return resultvoxel_size = 0.05  # means 5cm for this dataset
source, target, source_down, target_down, source_fpfh, target_fpfh = prepare_dataset(voxel_size)result_ransac = execute_global_registration(source_down, target_down,source_fpfh, target_fpfh,voxel_size)
print(result_ransac)
draw_registration_result(source_down, target_down, result_ransac.transformation)

匹配前:
在这里插入图片描述
匹配结果:
在这里插入图片描述

相关文章:

基于Open3D的点云处理16-特征点匹配

点云配准 将点云数据统一到一个世界坐标系的过程称之为点云配准或者点云拼接。(registration/align) 点云配准的过程其实就是找到同名点对;即找到在点云中处在真实世界同一位置的点。 常见的点云配准算法: ICP、Color ICP、Trimed-ICP 算法…...

设计模式—简单工厂

目录 一、前言 二、简单工厂模式 1、计算器例子 2、优化后版本 3、结合面向对象进行优化(封装) 3.1、Operation运算类 3.2、客户端 4、利用面向对象三大特性(继承和多态) 4.1、Operation类 4.2、加法类 4.3、减法类 4…...

真机安装Linux Centos7

准备工具: 8G左右U盘最新版UltraISOCentOS7光盘镜像 操作步骤 下载镜像 地址:http://isoredirect.centos.org/centos/7/isos/x86_64/ 安装刻录工具UltraISO,刻录镜像到U盘 ① 选择ISO镜像文件 ② 写入磁盘镜像,在这里选择你的U盘…...

ceph peering机制-状态机

本章介绍ceph中比较复杂的模块: Peering机制。该过程保障PG内各个副本之间数据的一致性,并实现PG的各种状态的维护和转换。本章首先介绍boost库的statechart状态机基本知识,Ceph使用它来管理PG的状态转换。其次介绍PG的创建过程以及相应的状…...

Java | File类

目录: File类File类中常用的方法:boolean exists( ) :判断此 文件/目录 是否存在boolean createNewFile( ) :创建一个文件boolean mkdir( ) :创建 “单层” 目录/文件夹boolean mkdirs( ) :创建 “多层” 目…...

数学建模之灰色预测

灰色预测(Grey Forecasting)是一种用于时间序列数据分析和预测的方法,通常用于处理具有较少历史数据的情况或者数据不够充分的情况。它是一种非常简单但有效的方法,基于灰色系统理论,用来估计未来的趋势。 以下是灰色…...

03_nodejd_npm install报错

npm install报错 npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: 5kcrm11.0.0 npm ERR! Found: vue2.5.17 npm ERR! node_modules/vue npm ERR! vue"2.5.17" from the root project npm ERR! np…...

three.js(二):webpack + three.js + ts

用webpackts 开发 three.js 项目 webpack 依旧是主流的模块打包工具;ts和three.js 是绝配,three.js本身就是用ts写的,ts可以为three 项目提前做好规则约束,使项目的开发更加顺畅。 1.创建一个目录,初始化 npm mkdir demo cd de…...

最小二乘法处理线性回归

最小二乘法是一种数学优化技术,用于查找最适合一组数据点的函数。 该方法主要用于线性回归分析,当然,也可用于非线性问题。 开始之前,我们先理解一下什么是回归。 回归:回归是一种监督学习算法,用于建模和…...

ModbusCRC16校验 示例代码

作者: Herman Ye Galbot Auromix 测试环境: Ubuntu20.04 更新日期: 2023/08/30 注1: Auromix 是一个机器人爱好者开源组织。 注2: 本文在更新日期经过测试,确认有效。 笔者出于学习交流目的, 给…...

一不留神就掉坑

乘除顺序问题 在据卡特兰数[1]公式,解决leetcode-96 不同的二叉搜索树[2]时,遇到一个非常诡异的问题, package mainimport "fmt"func main() { for i : 0; i < 40; i { fmt.Printf("第%d个卡特兰数为:%d\n", i, numTrees(i)) }}func numTrees(n int) i…...

Redis数据类型(list\set\zset)

"maybe its why" List类型 列表类型是⽤来存储多个有序的字符串&#xff0c;列表中的每个字符串称为元素&#xff08;element&#xff09;&#xff0c;⼀个列表最多可以存储个2^32 - 1个元素。在Redis中&#xff0c;可以对列表两端插⼊&#xff08;push&#xff09…...

TongWeb安装以及集成

TongWeb 安装步骤 静默安装 获取linux可执行安装包 如: Install_TWx.x.x.x_Enterprise_Linux.bin 创建安装所需配置文件 install.properties 内容如下 [root@node5 tongweb]# cat install.properties INSTALL_UI=silent USER_INSTALL_DIR=/home/tongweb SILENT_JDK_HOME=/jd…...

ScreenToGif-动图制作软件实用操作

ScreenToGif官网&#xff1a;ScreenToGif ⭕第一步&#xff1a;启动页面 ⭕第二步&#xff1a;选项 &#x1f95d;录像机-捕获频率选择手动-播放延迟1000ms(可以任意) ⭕第三步&#xff1a;录像机开始录屏 &#x1f95d;我们调整录屏的大小后&#xff0c;打开画图&#xff0c…...

sqlibs安装及复现

sqlibs安装 安装phpstudy后&#xff0c;到github上获取sqlibs源码 sqli-labs项目地址—Github获取&#xff1a;GitHub - Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based. 在phpstudy本地文件中的Apache目录中解压上方下载的源码。 将sq…...

OpenAI 创始人 Sam Altman 博客有一篇 10 年前的文章

OpenAI 创始人 Sam Altman 博客有一篇 10 年前的文章《Advice for ambitious 19 year olds》&#xff0c;给 19 岁年轻人的建议&#xff0c;从 #参考答案 看到&#xff0c;非常适合我们&#x1f923;年轻人&#xff0c;顺便用 GPT4 重新翻译了下全文。 太长不读纯摘要版本如下&…...

写的一款简易的热点词汇记录工具

项目需要对用户提交的附件、文章、搜索框内容等做热词分析。如下图&#xff1a; 公司有大数据团队。本着不麻烦别人就不麻烦别人的原则&#xff0c;写了一款简易的记录工具&#xff0c;原理也简单&#xff0c;手工在业务插入锚点&#xff0c;用分词器分好词&#xff0c;排掉字…...

算法通关村——滑动窗口高频问题

1. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 1.1 滑动窗口 找到最长字串需要找到字串的首尾位置…...

mybatis源码学习-2-项目结构

写在前面,这里会有很多借鉴的内容,有以下三个原因 本博客只是作为本人学习记录并用以分享,并不是专业的技术型博客笔者是位刚刚开始尝试阅读源码的人,对源码的阅读流程乃至整体架构并不熟悉,观看他人博客可以帮助我快速入门如果只是笔者自己观看,难免会有很多弄不懂乃至理解错误…...

selenium 自动化测试——环境搭建

安装python&#xff0c;并且使用pip命令安装 selenium pip3 install selenium 然后尝试第一次使用selenium 完成一个简单的测试自动化脚本 from selenium import webdriver from selenium.webdriver.common.by import By import timedriver webdriver.Chrome() driver.get(…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

Matlab实现任意伪彩色图像可视化显示

Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中&#xff0c;如何展示好看的实验结果图像非常重要&#xff01;&#xff01;&#xff01; 1、灰度原始图像 灰度图像每个像素点只有一个数值&#xff0c;代表该点的​​亮度&#xff08;或…...

LangChain【6】之输出解析器:结构化LLM响应的关键工具

文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器&#xff1f;1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...

Tauri2学习笔记

教程地址&#xff1a;https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引&#xff1a;https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多&#xff0c;我按照Tauri1的教程来学习&…...

MeshGPT 笔记

[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭&#xff01;_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...