草庐IT

3D点云转Mesh网格【Python】

新缸中之脑 2023-07-14 原文

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

使用 Python 自动生成的几个网格。在本文结束时,你将能够从点云创建数据集

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

(左)3D 点云,(中)网格叠加的顶点,(右)纹理网格。

3D网格很好地集成在大多数与软件专业人员一起工作的软件中。最重要的是,如果想探索 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 转换为 Open3Do3d.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点云进行网格划分来开始表面重建过程。我将给出我最喜欢的有效获得结果的方法,但在我们深入研究之前,需要一些浓缩的细节来掌握底层过程。我将限制自己使用两种啮合策略。

策略 1:球旋转算法 [1]

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

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

Brett Rapponotti、Michael Snowden 和 Allen Zeng 的插图

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

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

5 种视觉效果中的半径影响。您可以看到,最佳网格会自动平衡最佳几何拟合和三角形数量。

策略2:泊松重建[2]

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

  • 哪个深度?树深度用于重建。网格越高,网格越详细(默认值: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()

策略二:泊松重构

🤓注意: 该策略从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 和 Poisson 的重建都导出为 .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 打印软件,并通过在线打印服务获取报价 🤑。

约 20 厘米的模型的金色打印示例。

太棒了。在这个 5 步指南中,我们介绍了如何从点云设置自动 python 3D 网格创建器。这是一个非常好的工具,将在许多 3D 自动化项目中证明非常方便!但是,我们假设点云已经无噪声,并且法线方向良好。

如果不是这种情况,则需要一些额外的步骤,并且已经在下面的文章中讨论过的一些重要见解将在另一篇文章中介绍。完整代码可在此处访问。

6、结束语

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


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

有关3D点云转Mesh网格【Python】的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  3. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  6. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  7. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  8. [Vuforia]二.3D物体识别 - 2

    之前说过10之后的版本没有3dScan了,所以还是9.8的版本或者之前更早的版本。 3d物体扫描需要先下载扫描的APK进行扫面。首先要在手机上装一个扫描程序,扫描现实中的三维物体,然后上传高通官网,在下载成UnityPackage类型让Unity能够使用这个扫描程序可以从高通官网上进行下载,是一个安卓程序。点到Tools往下滑,找到VuforiaObjectScanner下载后解压数据线连接手机,将apk文件拷入手机安装然后刚才解压文件中的Media文件夹打开,两个PDF图打印第一张A4-ObjectScanningTarget.pdf,主要是用来辅助扫描的。好了,接下来就是扫描三维物体。将瓶

  9. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  10. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

随机推荐