点云转3D网格【Python】

在这里插入图片描述

推荐:使用 NSDT场景设计器 快速搭建 3D场景。

在本文中,我将介绍我的 3D 表面重建过程,以便使用 Python 从点云快速创建网格。 你将能够导出、可视化结果并将结果集成到您最喜欢的 3D 软件中,而无需任何编码经验。 此外,我将为你提供一种生成多层次细节 (LoD) 的简单方法,如果想要创建实时应用程序(例如,使用 Unity 的虚拟现实),这很有用。

3D 网格是几何数据结构,通常由一堆连接的三角形组成,这些三角形明确描述了一个表面🤔。 它们用于从地理空间重建到 VFX、电影和视频游戏的广泛应用。 我经常在需要物理副本时创建它们,或者如果我需要在游戏引擎中集成环境,而在游戏引擎中,点云支持是有限的。
在这里插入图片描述

它们很好地融入了大多数软件专业人员的工作中。 最重要的是,如果你想探索 3D 打印的奇迹,需要能够从你拥有的数据生成一致的网格。 本文旨在通过 5 个可自定义的步骤为你提供高效的工作流程,并在文末提供我的远程可执行脚本。 让我们开始吧!

1、搭建环境

在上一篇文章中,我们了解了如何使用 Anaconda 轻松设置环境,以及如何使用 GUI Spyder 来管理代码。 我们将继续这种方式,只使用 2 个库。

为了从点云中自动获取 3D 网格,我们将在我们的环境中添加另一个库 Open3D。 它是一个开源库,允许使用一组高效的数据结构和算法进行 3D 数据处理。 安装需要单击环境旁边的 ▶️ 图标。

打开终端并运行以下命令:

conda install -c open3d-admin open3d==0.8.0.0

🤓 注意:Open3D包兼容python 2.7、3.5和3.6版本。 如果你有另一个,你可以创建一个新环境(最好),或者如果你从上一篇文章开始,通过在终端中输入 conda install python=3.5 来更改终端中的 python 版本。

这将自动安装包及其依赖项,你可以在终端提示时输入 y 以允许此过程。 现在已经为项目做好了准备。

2、加载并准备数据

启动你的 python 脚本工具(Spyder GUI、Jupyter 或 Google Colab),我们将在其中调用 2 个库:Numpy 和 Open3D。

import numpy as np
import open3d as o3d

然后,我们创建保存数据路径和点云数据的变量:

input_path="your_path_to_file/"
output_path="your_path_to_output_folder/"
dataname="sample.xyz"
point_cloud= np.loadtxt(input_path+dataname,skiprows=1)

🤓 注意:至于上一篇文章,我们将使用采样点云,你可以从该存储库免费下载。 如果你想在不安装任何东西的情况下预先可视化它,你可以查看 webGL 版本。

最后,我们将 point_cloud 变量类型从 Numpy 转换为 Open3D o3d.geometry.PointCloud 类型以进行进一步处理:

pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(point_cloud[:,:3])
pcd.colors = o3d.utility.Vector3dVector(point_cloud[:,3:6]/255)
pcd.normals = o3d.utility.Vector3dVector(point_cloud[:,6:9])

🤓 注意:以下命令首先实例化Open3d点云对象,然后从原始NumPy数组中添加点、颜色和法线。

要快速查看加载的内容,可以执行以下命令(在 Google Colab 中不起作用):

o3d.visualization.draw_geometries([pcd])

3、选择网格生成策略

现在我们准备好通过对 pcd 点云进行网格化来开始表面重建过程。 我将给出我最喜欢的有效获取结果的方法,但在我们深入研究之前,需要一些浓缩的细节来掌握底层过程。 我将限制自己使用两种网格生成策略。

策略一:球旋转算法

球旋转算法 (BPA:Ball-Pivoting Algorithm) 背后的想法是模拟使用虚拟球从点云生成网格。 我们首先假设给定的点云由从物体表面采样的点组成。 点必须严格代表一个表面(无噪声),即重建的网格。

在这里插入图片描述

基于这个假设,想象一下在点云“表面”上滚动一个小球。 这个小球取决于网格的比例,应该略大于点之间的平均间距。 当你将球放到点的表面上时,球将被抓住并落在将形成种子三角形的三个点上。 从那个位置开始,球沿着由两点形成的三角形边滚动。 然后球落在一个新的位置:一个新的三角形由两个先前的顶点组成,一个新的三角形被添加到网格中。 当我们继续滚动和旋转球时,会形成新的三角形并将其添加到网格中。 球继续滚动和滚动,直到网格完全形成。
在这里插入图片描述

Ball-Pivoting Algorithm 背后的想法很简单,但当然,这里最初表达的过程有很多注意事项:

  • 球半径如何选择? 半径是根据输入点云的大小和比例凭经验获得的。 理论上,球的直径应该略大于点间的平均距离。
  • 如果某些位置的点相距太远并且球掉落怎么办? 当球沿边缘旋转时,它可能会错过表面上的适当点,而是击中物体上的另一个点,甚至正好是它的三个旧点。 在这种情况下,我们检查新三角形 Facet 的法线是否与点的 Vertex 法线一致。 如果不是,那么我们拒绝那个三角形并创建一个洞。
  • 如果表面有折痕或凹陷,使得表面与自身之间的距离小于球的大小怎么办? 在这种情况下,球只会滚过折痕而忽略折痕内的点。 但是,这不是理想的行为,因为重建的网格对对象不准确。
  • 如果表面被分隔成点区域,以至于球无法在区域之间成功滚动怎么办? 虚拟球在不同位置多次落到表面上。 这可确保球捕获整个网格,即使点的间距不一致也是如此。
    在这里插入图片描述

策略二:泊松重建

泊松重建更具技术/数学意义。 它的方法被称为隐式网格划分方法,我将其描述为试图将数据“包裹”在光滑的布料中。 在不涉及太多细节的情况下,我们尝试通过创建一个代表与法线链接的等值面的全新点集来从原始点集拟合水密表面。 有几个参数可以影响网格划分的结果:

  • 怎么设置深度? 树深度用于重建。 网格越高越详细(默认值:8)。 对于嘈杂的数据,你在生成的网格中保留异常值的顶点,但算法不会检测到它们。 所以较低的值(可能在 5 到 7 之间)提供平滑效果,但您会丢失细节。 深度值越高,生成的网格的顶点数量就越高。
    在这里插入图片描述

  • 怎么设置宽度? 这指定了树结构最细级别的目标宽度,称为八叉树🤯。 别担心,我将在另一篇文章中介绍这个和 3D 的最佳数据结构,因为它扩展了本文的范围。 无论如何,如果指定了深度,则忽略此参数。

  • 怎么设置缩放比例? 它描述了用于重建的立方体的直径与样本边界立方体的直径之间的比率。 非常抽象,默认参数通常效果很好(1.1)。
    在这里插入图片描述

  • 使用哪种拟合算法? linear_fit 参数如果设置为 true,让重建器使用线性插值来估计等顶点的位置。

4、处理数据

策略 1:BPA

我们首先根据从所有点之间的距离计算出的平均距离来计算必要的半径参数:

distances = pcd.compute_nearest_neighbor_distance()
avg_dist = np.mean(distances)
radius = 3 * avg_dist

在一个命令行中,我们可以创建一个网格并将其存储在 bpa_mesh 变量中:

bpa_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd,o3d.utility.DoubleVector([radius, radius * 2]))

在导出网格之前,我们可以将结果下采样到可接受的三角形数量,例如 100k 个三角形:

dec_mesh = mesh.simplify_quadric_decimation(100000)

此外,如果你认为网格会出现一些奇怪的伪影,可以运行以下命令来确保其一致性:

dec_mesh.remove_degenerate_triangles()
dec_mesh.remove_duplicated_triangles()
dec_mesh.remove_duplicated_vertices()
dec_mesh.remove_non_manifold_edges()

策略 2:泊松重建

🤓 注意:该策略从Open3D 0.9.0.0版本开始可用,因此目前只能远程使用。 你可以通过我在此处提供的 google colab 代码执行它。

要获得泊松结果,非常简单。 只需调整传递给函数的参数,如上所述:

poisson_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=8, width=0, scale=1.1, linear_fit=False)[0]

🤓 注意:该函数输出一个列表,该列表由一个 o3d.geometry 对象和一个 Numpy 数组组成。 你只需要选择最后证明 [0] 的 o3d.geometry。

为了获得干净的结果,通常需要添加一个裁剪步骤来清除下图中以黄色突出显示的不需要的伪影:
在这里插入图片描述

为此,我们计算包含原始点云的初始边界框,并使用它从边界框外的网格中过滤所有表面:

bbox = pcd.get_axis_aligned_bounding_box()
p_mesh_crop = poisson_mesh.crop(bbox)

你现在拥有一个或多个变量,每个变量都包含网格几何体! 在应用程序中获取它的最后一步是导出它!

5、导出和可视化

使用 write_triangle_mesh 函数导出网格数据非常简单。 我们只需在创建文件的名称中指定我们想要的 .ply、.obj、.stl 或 .gltf 扩展名,以及要导出的网格。 下面,我们将 BPA 和泊松重建导出为 .ply 文件:

o3d.io.write_triangle_mesh(output_path+"bpa_mesh.ply", dec_mesh)
o3d.io.write_triangle_mesh(output_path+"p_mesh_c.ply", p_mesh_crop)

为了快速生成细节层次 (LoD),让我们编写第一个函数。 这将非常简单。 该函数将采用网格、LoD 列表(作为三角形的目标数量)、生成文件的文件格式和写入文件的路径作为参数。 该函数(写在脚本中)如下所示:

def lod_mesh_export(mesh, lods, extension, path):
    mesh_lods={}
    for i in lods:
        mesh_lod = mesh.simplify_quadric_decimation(i)
        o3d.io.write_triangle_mesh(path+"lod_"+str(i)+extension, mesh_lod)
        mesh_lods[i]=mesh_lod
    print("generation of "+str(i)+" LoD successful")
    return mesh_lods

💡 提示:我将在另一篇文章中介绍该函数的作用及其结构的基础知识。 此时,知道该函数将 (1) 以所需文件格式将数据导出到您选择的指定位置,以及 (2) 如果需要更多处理,则可以将结果存储在变量中,这很有用 在 python 中需要。

该函数具有一些魔力,但一旦执行,它看起来什么也没有发生。 不用担心,你的程序现在知道 lod_mesh_export 是什么,可以直接在控制台中调用它,我们只需将参数更改为所需的值即可:

my_lods = lod_mesh_export(bpa_mesh, [100000,50000,10000,1000,100], ".ply", output_path)

非常有趣的是,现在不需要为不同的 LoD 每次都重写一堆代码。 只需要将不同的参数传递给函数:

my_lods2 = lod_mesh_export(bpa_mesh, [8000,800,300], ".ply", output_path)

如果你想在 python 中可视化一个特定的 LoD,比如说有 100 个三角形的 LoD,你可以通过以下命令访问和可视化它:

o3d.visualization.draw_geometries([my_lods[100]])

要在 python 之外进行可视化,可以使用选择的软件(例如开源 Blender、MeshLab 和 CloudCompare)并在 GUI 中加载导出的文件。 通过 WebGL 直接在 Web 上,也可以使用 Three.js 编辑器或 Flyvast 来简单地访问网格。

最后,可以在任何 3D 打印软件中导入它,并通过在线打印服务获得关于它需要多少费用的报价🤑。

在这里插入图片描述

6、错误的法线

在这个指南中,我们介绍了如何从点云设置自动 Python 3D 网格创建器。 这是一个非常好的工具,将在许多 3D 自动化项目中证明非常方便! 然而,我们假设点云已经没有噪声,并且法线方向正确。

在这里插入图片描述

如果法线有问题,则需要一些额外的步骤,我们将在另一篇文章中介绍如何处理。

完整代码可在此处访问:Google Colab notebook

7、结束语

我们刚刚学习了如何导入、划分网格、导出和可视化由数百万个具有不同 LoD 的点组成的点云! 做得好! 但路径并没有就此结束,未来的帖子将深入探讨点云空间分析、文件格式、数据结构、可视化、动画和网格划分。 我们将特别研究如何管理下文定义的大点云数据。


原文链接:点云转3D网格 — BimAnt

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python-PCL是一个Python绑定库,它提供了对PointCloud库的访问。点云网格化算法是将点云数据进行处理后生成一张网格表面的算法。网格化可以使点云数据更容易可视化、分析和处理。Python-PCL点云网格化算法可以将点云数据分割成均匀分布的三角形网格,并构建一个平滑的网格表面。 Python-PCL点云网格化算法的主要步骤包括: 1.加载点云数据并将其转换为PointNormal格式,以便于法线估计和网格化操作。 2.对点云数据进行法线估计。该过程使用一种求点云曲率的技术,将每个点的法线计算出来,并保存在其对应的点中。 3.将法线信息与点云数据结合,构建一个SurfaceReconstruction3D对象来执行网格化操作。在这个过程中,算法使用一个梯度下降优化算法,将点云数据映射到一个均匀分布的三角形网格上。优化约束条件限制每个三角形的边长,使网格表面更加平滑。 4.最后根据三角形间的相交情况对网格进行修复,并输出网格数据。在这个过程中,算法检查每个三角形是否与其他三角形相交,并尝试通过联通、压缩网格等修复操作,使网格曲面更加平滑。 Python-PCL点云网格化算法是一种实现点云数据可视化、处理和分析的有效工具。在3D打印、机器人视觉和虚拟现实等领域都有广泛的应用。 ### 回答2: Python-PCL是一个Python的PCL(点云库)封装库,允许用户在Python中使用PCL中的众多算法。点云网格化算法就是Python-PCL之中的一个非常重要的算法。 点云网格化算法是将点云数据转化为网格表示的过程,在这个过程中,将点云数据转换为一个等间距的二元矩阵表示。由于点云数据是一个由众多点组成的体,因此,这个矩阵是被空缺的网格填充而成的。在这个过程中,点云数据通过多次计算,不断地从自由形状变为一种规则形状,从而提高点云数据的处理效率。 点云网格化算法是通过点云曲面重构的算法实现的。曲面重构算法能够将点云数据转化为一个规则的几何模型,从而为相关应用提供了非常大的便捷,因此,点云网格化算法的应用非常广泛,例如:机器视觉,三维打印等方面。在Python-PCL的应用中,点云网格化算法的实现基于VTK(Visualization ToolKit)工具包,通过VTK包中的vtkPolyDataMapper类实现点云网格化。 点云网格化算法的实现需要通过多次迭代计算,使点云数据沿着均匀分布的空间方向发生变化,从而最终能够得到一种规则的几何形状。在实际应用中,点云数据可能会受到很多干扰,例如:噪音、数据不完整等因素,这对点云网格化算法的计算效率提出了非常高的要求,因此,Python-PCL提供了一系列优化的算法来满足实际应用的需求。 ### 回答3: Python-PCL是Point Cloud Library的Python封装库,提供了一组Python模块,可以在Python中使用PCL的功能。PCL是一个C++库,是开发点云处理算法和应用的一流工具,具有许多点云处理功能,如配准、滤波、分割、聚类、特征提取和识别等。 点云网格化是一种将点云转化为网格模型的技术。在点云数据中,所有的点都是离散的,而在网格模型中,点是有序的,因此点云网格化是将离散的点云数据转换为有序的网格数据的过程。 Python-PCL库提供了函数pcl.surface包来执行点云到三角网格转换,使用点云同步方法定义的半径搜索方式构建三角网格。 下面是一个简单的例程,它将点云转换为三角网格: ```python import pcl cloud = pcl.PointCloud.PointXYZRGB() mesh = cloud.make_mesh_cuboid() print('PointCloud before meshing') print(cloud) print('PointCloud after meshing') print(mesh.cloud) print(mesh.polygons) ``` 该例程首先定义了一个PointCloud对象,然后使用make_mesh_cuboid()函数将其转换为三角网格。最后,程序将输出PointCloud以及转换后的mesh。由于make_mesh_cuboid()函数是在一个立方体形状上生成网格对象,因此输出结果可能会有所不同。 总体而言,Python-PCL是一个非常强大的工具,它为Python程序员提供了使用点云数据处理的功能。尤其是对于点云网格化算法,Python-PCL提供了一个方便的方式来将点云数据转换为有序的网格数据。这个库是在点云领域做开发非常有帮助的,它为点云的开发和应用提供了大量的可靠和高效的处理工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值