常用的点云预处理算法

点云预处理是处理点云数据时的重要部分,其目的是提高点云数据的质量和处理效率。通过去除离群点、减少点云密度和增强特征,可以消除噪声、减少计算量、提高算法的准确性和鲁棒性,从而为后续的点云处理和分析步骤(如配准、分割和重建)提供更高质量的数据基础。

以下是常用的点云预处理算法介绍,内容包括离群点过滤、点云下采样、坐标上采样和特征上采样的数学原理以及Open3D实现代码。

离群点过滤

无效值剔除

无效值剔除是指移除点云中的值或无穷大的值。

数学原理: 假设点云数据集为,其中每个点。无效值剔除的规则可以表示为:

Open3D实现

import open3d as o3ddef remove_invalid_points(pcd):pcd = pcd.select_by_index(np.where(np.isfinite(np.asarray(pcd.points)).all(axis=1))[0])return pcd# 示例
pcd = o3d.io.read_point_cloud("example.ply")
pcd = remove_invalid_points(pcd)
o3d.visualization.draw_geometries([pcd])
统计方法剔除

统计方法剔除利用每个点的邻域统计信息来识别并移除离群点。

数学原理: 计算每个点到其个最近邻点的平均距离,并将该点的平均距离与全局平均距离进行比较。如果某点的平均距离超出某一阈值,则认为该点为离群点。

Open3D实现

def statistical_outlier_removal(pcd, nb_neighbors=20, std_ratio=2.0):cl, ind = pcd.remove_statistical_outlier(nb_neighbors=nb_neighbors, std_ratio=std_ratio)pcd = pcd.select_by_index(ind)return pcd# 示例
pcd = o3d.io.read_point_cloud("example.ply")
pcd = statistical_outlier_removal(pcd)
o3d.visualization.draw_geometries([pcd])
半径滤波方法剔除

半径滤波方法根据每个点在指定半径内的邻居数量来剔除离群点。

数学原理: 设定一个半径和最小点数阈值。对于每个点,如果其在半径内的邻居数量少于,则认为该点为离群点。

Open3D实现

def radius_outlier_removal(pcd, radius=0.05, min_points=5):cl, ind = pcd.remove_radius_outlier(nb_points=min_points, radius=radius)pcd = pcd.select_by_index(ind)return pcd# 示例
pcd = o3d.io.read_point_cloud("example.ply")
pcd = radius_outlier_removal(pcd)
o3d.visualization.draw_geometries([pcd])

离群点剔除代码示例:

import open3d as o3d
from copy import deepcopy
import numpy as npif __name__ == '__main__':file_path = 'rabbit.pcd'pcd = o3d.io.read_point_cloud(file_path)pcd = pcd.uniform_down_sample(50)#每50个点采样一次pcd.paint_uniform_color([0.5, 0.5, 0.5])#指定显示为灰色print(pcd)#剔除无效值pcd1 = deepcopy(pcd)pcd1.paint_uniform_color([0, 0, 1])#指定显示为蓝色pcd1.translate((20, 0, 0)) #整体进行x轴方向平移pcd1 = pcd1.remove_non_finite_points(True, True)#剔除无效值print(pcd1)#统计方法剔除pcd2 = deepcopy(pcd)pcd2.paint_uniform_color([0, 1, 0])#指定显示为蓝色pcd2.translate((-20, 0, 0)) #整体进行x轴方向平移res = pcd2.remove_statistical_outlier(20, 0.5)#统计方法剔除pcd2 = res[0]#返回点云,和点云索引print(pcd2)#半径方法剔除pcd3 = deepcopy(pcd)pcd3.paint_uniform_color([1, 0, 0])#指定显示为蓝色pcd3.translate((0, 20, 0)) #整体进行y轴方向平移res = pcd3.remove_radius_outlier(nb_points=20, radius=2)#半径方法剔除pcd3 = res[0]#返回点云,和点云索引print(pcd3)# # 点云显示o3d.visualization.draw_geometries([pcd, pcd1, pcd2, pcd3], #点云列表window_name="离群点剔除",point_show_normal=False,width=800,  # 窗口宽度height=600)  # 窗口高度

图片

点云下采样

点云下采样的主要目的是减少点云数据的规模,从而降低计算复杂度和存储需求。在实际应用中,点云数据通常包含大量的点,这会占用大量的存储空间并增加处理时间。通过下采样,可以去除冗余点,只保留关键点,既能加速后续处理(如配准、分类、分割等),又能减少内存使用。此外,下采样还能提高算法的鲁棒性,减少噪声影响,使得处理结果更加稳定和可靠。

体素下采样

体素下采样通过将点云划分为固定大小的三维网格,并用每个网格中的点的质心来代表该网格中的所有点。

数学原理: 设定体素网格的大小为,将点云划分为体素网格,每个体素中的点用其质心替代。

其中,为体素的质心,为体素中的点数。

Open3D实现

import open3d as o3d
from copy import deepcopyif __name__ == '__main__':file_path = 'rabbit.pcd'pcd = o3d.io.read_point_cloud(file_path)pcd.paint_uniform_color([0.5, 0.5, 0.5])#指定显示为灰色print(pcd)pcd1 = deepcopy(pcd)pcd1.paint_uniform_color([0, 0, 1])#指定显示为蓝色pcd1.translate((20, 0, 0)) #整体进行x轴方向平移pcd1 = pcd1.voxel_down_sample(voxel_size=1)print(pcd1)pcd2 = deepcopy(pcd)pcd2.paint_uniform_color([0, 1, 0])#指定显示为绿色pcd2.translate((0, 20, 0)) #整体进行y轴方向平移res = pcd2.voxel_down_sample_and_trace(1, min_bound=pcd2.get_min_bound()-0.5, max_bound=pcd2.get_max_bound()+0.5, approximate_class=True)pcd2 = res[0]print(pcd2)# 点云显示o3d.visualization.draw_geometries([pcd, pcd1, pcd2], #点云列表window_name="体素下采样",point_show_normal=False,width=800,  # 窗口宽度height=600)  # 窗口高度

图片

随机下采样

随机下采样是从点云中随机选取一定比例的点,以减少点云的点数。

数学原理: 设点云数据集为,随机下采样从中选取个点。其中,是从中随机选取的索引。

Open3D实现

import open3d as o3d
from copy import deepcopy
import numpy as npif __name__ == '__main__':file_path = 'rabbit.pcd'pcd = o3d.io.read_point_cloud(file_path)pcd.paint_uniform_color([0.5, 0.5, 0.5])#指定显示为灰色print(pcd)pcd1 = deepcopy(pcd)pcd1.paint_uniform_color([0, 0, 1])#指定显示为蓝色pcd1.translate((20, 0, 0)) #整体进行x轴方向平移pcd1 = pcd1.uniform_down_sample(100)#每100个点采样一次print(pcd1)pcd2 = deepcopy(pcd)pcd2.paint_uniform_color([0, 1, 0])#指定显示为绿色pcd2.translate((0, 20, 0)) #整体进行y轴方向平移pcd2 = pcd2.random_down_sample(0.1)#采1/10的点云print(pcd2)#自定义随机采样pcd3 = deepcopy(pcd)pcd3.translate((-20, 0, 0)) #整体进行x轴方向平移points = np.array(pcd3.points)n = np.random.choice(len(points), 500, replace=False) #s随机采500个数据,这种随机方式也可以自己定义pcd3.points = o3d.utility.Vector3dVector(points[n])pcd3.paint_uniform_color([1, 0, 0])#指定显示为红色print(pcd3)# # 点云显示o3d.visualization.draw_geometries([pcd, pcd1, pcd2, pcd3], #点云列表

图片

均匀下采样

均匀下采样是等间距选择点云中的点。

数学原理: 设点云数据集为,均匀下采样每隔个点选择一个点。

Open3D实现

def uniform_downsample(pcd, every_k_points=10):pcd = pcd.uniform_down_sample(every_k_points)return pcd# 示例
pcd = o3d.io.read_point_cloud("example.ply")
pcd = uniform_downsample(pcd)
o3d.visualization.draw_geometries([pcd])
最远点采样

最远点采样是一种迭代方法,每次选择距离当前已选点集最远的点。

数学原理: 初始化点集为随机选择的一个点,每次迭代选择距离当前已选点集最远的点:

Open3D实现

import open3d as o3d
from copy import deepcopy
import numpy as npdef farthest_point_sample(point, npoint):"""Input:xyz: pointcloud data, [N, D]npoint: number of samplesReturn:centroids: sampled pointcloud index, [npoint, D]"""N, D = point.shapexyz = point[:,:3]centroids = np.zeros((npoint,))distance = np.ones((N,)) * 1e10farthest = np.random.randint(0, N)for i in range(npoint):centroids[i] = farthestcentroid = xyz[farthest, :]dist = np.sum((xyz - centroid) ** 2, -1)mask = dist < distancedistance[mask] = dist[mask]farthest = np.argmax(distance, -1)point = point[centroids.astype(np.int32)]return pointif __name__ == '__main__':file_path = 'rabbit.pcd'pcd = o3d.io.read_point_cloud(file_path)pcd.paint_uniform_color([0.5, 0.5, 0.5])#指定显示为灰色print(pcd)pcd1 = deepcopy(pcd)pcd1.translate((20, 0, 0)) #整体进行x轴方向平移points = np.array(pcd1.points)points = farthest_point_sample(points, 500)pcd1 = o3d.geometry.PointCloud()pcd1.points = o3d.utility.Vector3dVector(points)pcd1.paint_uniform_color([0, 0, 1])#指定显示为蓝色print(pcd1)# # 点云显示o3d.visualization.draw_geometries([pcd, pcd1], #点云列表window_name="最远点采样",point_show_normal=False,width=800,  # 窗口宽度height=600)  # 窗口高度

图片

坐标上采样

点云上采样的目的是增加点云的密度,以提高其分辨率和细节表现。在许多应用中,特别是三维重建和表面细化时,原始点云的分辨率可能不足,导致重建结果不够精细或存在明显的缺陷。通过上采样,可以插值生成更多的点,使得点云更密集,从而更好地捕捉物体的几何细节,提升最终的三维模型质量。这对于需要高精度、高分辨率数据的任务(如精细的表面重建、细节检测等)尤为重要。

插值法

插值法是通过插值计算新增点的坐标。

数学原理: 常用的插值方法包括线性插值、双线性插值、三次样条插值等。以线性插值为例,两个点和之间新增点:

其中,为插值系数,取值范围为[0, 1]。

Open3D实现

import open3d as o3d
from copy import deepcopyif __name__ == '__main__':file_path = 'rabbit.pcd'pcd = o3d.io.read_point_cloud(file_path)pcd.paint_uniform_color([0.5, 0.5, 0.5])  # 指定显示为灰色print(pcd)pcd1 = deepcopy(pcd)pcd1.paint_uniform_color([0, 0, 1])  # 指定显示为蓝色pcd1.translate((20, 0, 0))  # 整体进行x轴方向平移pcd1 = pcd1.voxel_down_sample(voxel_size=1)print(pcd1)mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd1, alpha=2)pcd2 = mesh.sample_points_poisson_disk(number_of_points=3000, init_factor=5)pcd2.paint_uniform_color([0, 1, 0])  # 指定显示为绿色pcd2.translate((-40, 0, 0))  # 整体进行x轴方向平移print(pcd2)o3d.visualization.draw_geometries([pcd, pcd1, pcd2],  # 点云列表window_name="点云上采样",point_show_normal=False,width=800,  # 窗口宽度height=600)  # 窗口高度

图片

特征上采样

最近邻插值

最近邻插值是通过选择最近邻的特征值作为新增点的特征值。

数学原理: 设已知点云的特征为,新增点的特征值通过最近邻点的特征值确定:,其中,为距离最近的点。

Open3D实现

from sklearn.neighbors import NearestNeighborsdef nearest_neighbor_interpolation(pcd, features, num_points):points = np.asarray(pcd.points)new_points = np.array([]).reshape(0, 3)new_features = np.array([]).reshape(0, features.shape[1])for i in range(len(points) - 1):for t in np.linspace(0, 1, num_points):new_point = points[i] + t * (points[i + 1] - points[i])new_points = np.vstack((new_points, new_point))nn = NearestNeighbors(n_neighbors=1).fit(points)distances, indices = nn.kneighbors(new_points)new_features = features[indices.flatten()]pcd_interpolated = o3d.geometry.PointCloud()pcd_interpolated.points = o3d.utility.Vector3dVector(new_points)return pcd_interpolated, new_features# 示例
pcd = o3d.io.read_point_cloud("example.ply")
features = np.random.rand(len(pcd.points), 3)  # 假设特征是随机生成的
pcd, new_features = nearest_neighbor_interpolation(pcd, features, num_points=10)
o3d.visualization.draw_geometries([pcd])

以上内容总结自网络,如有帮助欢迎关注与转发,我们下次再见!

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

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

相关文章

防火墙--带宽管理

目录 核心思想 带宽限制 带宽保证 连接数的限制 如何实现 接口带宽 队列调度 配置位置 在接口处配置 带宽策略配置位置 带宽通道 配置地方 接口带宽、带宽策略和带宽通道联系 配置顺序 带块通道在那里配置 选项解释 引用方式 策略独占 策略共享 重标记DSCP优先…

keysight P9370A/P9375A USB矢量网络分析仪

Keysight P9370A USB 矢量网络分析仪&#xff0c;4.5 GHz P937xA 系列是是德科技紧凑型矢量网络分析仪&#xff08;VNA&#xff09;&#xff0c;其价格适中&#xff0c;并采用完整的双端口设计&#xff0c;可以显著减小测试需要的空间。这款紧凑型VNA 覆盖十分宽广的频 率范围…

移动终端的安全卫士

随着移动互联网的快速发展&#xff0c;移动端安全风险频发。设备指纹技术凭借高精度的设备识别能力&#xff0c;能够帮助企业提升移动端安全防护能力&#xff0c;精准区分合法与风险行为&#xff0c;跨行业赋能风控&#xff0c;为金融、电商、游戏等多领域提供强大的业务安全保…

基于python的图像去水印

1 代码 import cv2 import numpy as npdef remove_watermark(image_path, output_path):# 读取图片image cv2.imread(image_path)# 转换为灰度图gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 使用中值滤波去除噪声median_filtered cv2.medianBlur(gray, 5)# 计算图像的梯…

数据结构——栈和队列(C语言实现)

写在前面&#xff1a; 栈和队列是两种重要的线性结构。其也属于线性表&#xff0c;只是操作受限&#xff0c;本节主要讨论的是栈和队列的定义、表示方法以及C语言实现。 一、栈和队列的定义与特点 栈&#xff1a;是限定仅在表尾进行插入和删除的线性表。对栈来说&#xff0c;表…

ABAP小白开发操作手册+(六)创建维护视图及事件

目录 开发类型&#xff1a; 开发申请&#xff1a; 开发步骤&#xff1a; 1、创建后台表 2、生成维护视图 3、隐藏自带字段 4、事件代码编写 5、配置事务代码 6、其它个性化需求 6.1、修改维护视图字段的可见长度 6.2、根据后台表查看对应维护视图的事务代码 代码如下…

Modbus通讯接口选择分析

Modbus通讯接口选择分析 Modbus通讯接口的选择涉及到多个方面的考量&#xff0c;包括但不限于通讯距离、数据传输速率、成本、设备兼容性以及应用场景等。下面将从这些角度出发&#xff0c;对Modbus通讯接口的选择进行详细的分析。 Ip67防水面板法兰插座 通讯距离 Modbus通讯…

卸载docker简单且ok的方法

杀死所有容器 docker kill $(docker ps -a -q) 删除所有容器 docker rm $(docker ps -a -q) 删除所有镜像 docker rmi $(docker images -q) 停止docker服务 systemctl stop docker 查看安装列表 yum list installed|grep docker 依次卸载已安装的docker yum -y remove docke…

【iOS】——ARC源码探究

一、ARC介绍 ARC的全称Auto Reference Counting. 也就是自动引用计数。使用MRC时开发者不得不花大量的时间在内存管理上&#xff0c;并且容易出现内存泄漏或者release一个已被释放的对象&#xff0c;导致crash。后来&#xff0c;Apple引入了ARC。使用ARC&#xff0c;开发者不再…

《昇思25天学习打卡营第25天|第10天》

今天是打卡的第十天&#xff0c;今天开始学应用实践中的LLM原理和实践&#xff0c;今天学的是基于MindSpore实现BERT对话情绪识别。最先了解的是BERT模型的简介&#xff08;来自变换器的双向编码器表征量&#xff08;Bidirectional Encoder Representations from Transformers&…

代码随想录算法训练营第22天 | 题目:回溯算法part01 理论基础、77. 组合 、 216.组合总和III 、 17.电话号码的字母组合

代码随想录算法训练营第22天 | 题目&#xff1a;回溯算法part01 理论基础、77. 组合 、 216.组合总和III 、 17.电话号码的字母组合 文章来源&#xff1a;代码随想录 理论基础&#xff1a;代码随想录&#xff1a;回溯算法 模板&#xff1a; void backtracking(参数) {if (终止…

Spring MVC 的常用注解

RequestMapping 和 RestController注解 上面两个注解&#xff0c;是Spring MCV最常用的注解。 RequestMapping &#xff0c; 他是用来注册接口的路由映射。 路由映射&#xff1a;当一个用户访问url时&#xff0c;将用户的请求对应到某个方法或类的过程叫做路由映射。 Reques…

【Linux】将IDEA项目部署到云服务器上,让其成为后台进程(保姆级教学,满满的干货~~)

目录 部署项目到云服务器什么是部署一、 创建MySQL数据库二、 修改idea配置项三、 数据打包四、 部署云服务器五、开放端口号六 、 验证程序 部署项目到云服务器 什么是部署 ⼯作中涉及到的"环境" 开发环境:开发⼈员写代码⽤的机器.测试环境:测试⼈员测试程序使⽤…

【HarmonyOS】HarmonyOS NEXT学习日记:二、ArkTs语法

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;二、ArkTs语法 众所周知TS是JS的超集,而ArkTs则可以理解为是Ts的超集。他们的基础都基于JS&#xff0c;所以学习之前最好就JS基础。我的学习重点也是放在ArkTs和JS的不同点上。 文章主要跟着官方文档学习&#xff0c;跳过了一…

21天学通C++:第十三、十四章节

第十三章&#xff1a;类型转换运算符 类型转换是一种机制&#xff0c;让程序员能够暂时或永久性改变编译器对对象的解释。注意&#xff0c;这并不意味着程序员改变了对象本身&#xff0c;而只是改变了对对象的解释。可改变对象解释方式的运算符称为类型转换运算符。 为何需要…

追溯源码观察HashMap底层原理

引言&#xff08;Map的重要性&#xff09; 从事Java的小伙伴&#xff0c;在面试的时候几乎都会被问到Map&#xff0c;Map都被盘包浆了。Map是键值集合&#xff0c;使用的场景有很多比如缓存、数据索引、数据去重等场景&#xff0c;在算法中也经常出现&#xff0c;因为在Map中获…

论文《Revisiting Heterophily For Graph Neural Networks》笔记

【ACM】作者从聚合后节点相似性的角度重新审视异配性&#xff0c;并定义了新的同质性度量方法。基于聚合相似度度量这一指标&#xff0c;作者提出了一种新的框架&#xff0c;称为自适应信道混合&#xff08;Adaptive Channel Mixing&#xff0c;ACM&#xff09;&#xff0c;它通…

【青书学堂】2024年第一学期 生产与运作管理(高起专) 作业

【青书学堂】2024年第一学期 生产与运作管理(高起专) 作业 为了方便日后复习&#xff0c;青书学堂成人大专试题整理。 若有未整理的课程&#xff0c;请私信我补充&#xff0c;欢迎爱学习的同学们收藏点赞关注&#xff01;文章内容仅限学习使用&#xff01;&#xff01;&#xf…

Linux的前台进程和后台进程(守护进程)

前台进程 前台进程就是在某个终端中运行的进程&#xff0c;在该终端中通过运行命令运行起该进程&#xff0c;一旦该终端关闭&#xff0c;进程也就随之消失。 后台进程 后台进程顾名思义就是在后台运行的进程&#xff0c;与前台进程不同的是&#xff0c;它不受某一个终端控制…

VBA学习(21):遍历文件夹(和子文件夹)中的文件

很多时候&#xff0c;我们都想要遍历文件夹中的每个文件&#xff0c;例如在工作表中列出所有文件名、对每个文件进行修改。VBA给我们提供了一些方式&#xff1a;&#xff08;1&#xff09;Dir函数&#xff1b;&#xff08;2&#xff09;File System Object。 使用Dir函数 Dir…