3D模型处理的多进程并行【Python】

今天我们将讨论如何使用 Python 多进程来处理大量3D数据。 我将讲述一些可能在手册中找到的一般信息,并分享我发现的一些小技巧,例如将 tqdm 与多处理 imap 结合使用以及并行处理存档。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

那么我们为什么要诉诸并行计算呢? 使用数据有时会出现与大数据相关的问题。 每次我们遇到 RAM 不适合的数据时,我们都需要逐段处理它。 幸运的是,现代编程语言允许我们生成在多核处理器上完美工作的多个进程(甚至线程)。注意:这并不意味着单核处理器无法处理多处理,这是有关该主题的 Stack Overflow 讨论。

今天我们将尝试计算网格和点云之间的距离这一常见的 3D 计算机视觉任务。 例如,当你需要在所有可用网格中查找定义与给定点云相同的 3D 对象的网格时,可能会遇到此问题。

我们的数据由存储在 .7z 存档中的 .obj 文件组成,这在存储效率方面非常出色。 但是当我们需要访问它的确切部分时,我们应该付出努力。 在这里,我定义了包装 7-zip 存档并提供底层数据接口的类。

from io import BytesIO
import py7zlibclass MeshesArchive(object):def __init__(self, archive_path):fp = open(archive_path, 'rb')self.archive = py7zlib.Archive7z(fp)self.archive_path = archive_pathself.names_list = self.archive.getnames()def __len__(self):return len(self.names_list)def get(self, name):bytes_io = BytesIO(self.archive.getmember(name).read())return bytes_iodef __getitem__(self, idx):return self.get(self.names[idx])def __iter__(self):for name in self.names_list:yield self.get(name)

这个类几乎不依赖 py7zlib 包,它允许我们在每次调用 get 方法时解压缩数据,并为我们提供存档内的文件数量。 我们还定义了 __iter__ ,它将帮助我们像在可迭代对象上一样在该对象上启动多处理映射。

这个定义为我们提供了迭代存档的可能性,但它是否允许我们并行随机访问内容? 这是一个有趣的问题,我在网上没有找到答案,但如果深入研究 py7zlib 的源代码,我们可以回答它。

在这里,我提供了 pylzma 的代码片段:

class Archive7z(Base):def __init__(self, file, password=None):# ...self.files = {}# ...for info in files.files:# create an instance of ArchiveFile that knows location on diskfile = ArchiveFile(info, pos, src_pos, folder, self, maxsize=maxsize)# ...self.files.append(file)# ...self.files_map.update([(x.filename, x) for x in self.files])# method that returns an ArchiveFile from files_map dictionarydef getmember(self, name):if isinstance(name, (int, long)):try:return self.files[name]except IndexError:return Nonereturn self.files_map.get(name, None)class Archive7z(Base):def read(self):# ...for level, coder in enumerate(self._folder.coders):# ...# get the decoder and decode the underlying datadata = getattr(self, decoder)(coder, data, level, num_coders)return data

摘自pylzma源码,省略了很多

我相信从上面的要点可以清楚地看出,只要同时多次读取存档,就没有理由被阻止。

接下来我们快速介绍一下什么是网格和点云。 首先是网格,它们是顶点、边和面的集合。 顶点由空间中的 (x,y,z) 坐标定义,并分配有唯一的编号。 边和面相应地是点对和三元组的组,并使用提到的唯一点 ID 进行定义。 通常,当我们谈论“网格”时,我们指的是“三角形网格”,即由三角形组成的表面。 使用 trimesh 库在 Python 中处理网格要容易得多,例如它提供了在内存中加载 .obj 文件的接口。 要在 Jupyter Notebook 中显示 3D 对象并与之交互,可以使用 k3d 库。

因此,通过以下代码片段,我回答了这个问题:“如何使用 k3d 在 jupyter 中绘制 atrimeshobject?”

import trimesh
import k3dwith open("./data/meshes/stanford-bunny.obj") as f:bunny_mesh = trimesh.load(f, 'obj')plot = k3d.plot()
mesh = k3d.mesh(bunny_mesh.vertices, bunny_mesh.faces)
plot += mesh
plot.display()

k3d 显示的斯坦福兔子网格(不幸的是这里没有响应)

其次,点云,它们是表示空间中物体的 3D 点阵列。 许多 3D 扫描仪生成点云作为扫描对象的表示。 为了演示目的,我们可以读取相同的网格并将其顶点显示为点云。

import trimesh
import k3dwith open("./data/meshes/stanford-bunny.obj") as f:bunny_mesh = trimesh.load(f, 'obj')plot = k3d.plot()
cloud = k3d.points(bunny_mesh.vertices, point_size=0.0001, shader="flat")
plot += cloud
plot.display()

将顶点绘制为点云

k3d绘制的点云

正如上面提到的,3D 扫描仪为我们提供了点云。 假设我们有一个网格数据库,并且希望在数据库中找到与扫描对象(即点云)对齐的网格。 为了解决这个问题,我们可以提出一种简单的方法。 我们将搜索给定点云的点与存档中的每个网格之间的最大距离。 如果对于某些网格来说,1e-4 的距离较小,我们会认为该网格与点云对齐。

最后,我们来到了多处理部分。 请记住,我们的存档有大量文件可能无法同时放入内存中,我们更喜欢并行处理它们。 为了实现这一点,我们将使用多处理池,它使用 map 或 imap/imap_unordered 方法处理用户定义函数的多次调用。 map 和 imap 之间影响我们的区别在于, map 在发送到工作进程之前将可迭代对象转换为列表。 如果存档太大而无法写入 RAM,则不应将其解压到 Python 列表中。 在另一种情况下,它们的执行速度相似。

[Loading meshes: pool.map w/o manager] Pool of 4 processes elapsed time: 37.213207403818764 sec
[Loading meshes: pool.imap_unordered w/o manager] Pool of 4 processes elapsed time: 37.219303369522095 sec

在上面你可以看到从适合内存的网格存档中进行简单读取的结果。

使用 imap 更进一步。 让我们讨论如何实现找到靠近点云的网格的目标。 这是数据,我们有来自斯坦福模型的 5 个不同的网格。 我们将通过向斯坦福兔子网格的顶点添加噪声来模拟 3D 扫描。

import numpy as np
from numpy.random import default_rngdef normalize_pc(points):points = points - points.mean(axis=0)[None, :]dists = np.linalg.norm(points, axis=1)scaled_points = points / dists.max()return scaled_pointsdef load_bunny_pc(bunny_path):STD = 1e-3 with open(bunny_path) as f:bunny_mesh = load_mesh(f)# normalize point cloud scaled_bunny = normalize_pc(bunny_mesh.vertices)# add some noise to point cloudrng = default_rng()noise = rng.normal(0.0, STD, scaled_bunny.shape)distorted_bunny = scaled_bunny + noisereturn distorted_bunny

当然,我们之前对下面的点云和网格顶点进行了标准化,以在 3D 立方体中缩放它们。

为了计算点云和网格之间的距离,我们将使用 igl。 为了最终确定,我们需要编写一个将在每个进程及其依赖项中调用的函数。 让我们用下面的片段来总结一下。

import itertools
import timeimport numpy as np
from numpy.random import default_rngimport trimesh
import igl
from tqdm import tqdmfrom multiprocessing import Pooldef load_mesh(obj_file):mesh = trimesh.load(obj_file, 'obj')return meshdef get_max_dist(base_mesh, point_cloud):distance_sq, mesh_face_indexes, _ = igl.point_mesh_squared_distance(point_cloud,base_mesh.vertices,base_mesh.faces)return distance_sq.max()def load_mesh_get_distance(args):obj_file, point_cloud = args[0], args[1]mesh = load_mesh(obj_file)mesh.vertices = normalize_pc(mesh.vertices)max_dist = get_max_dist(mesh, point_cloud)return max_distdef read_meshes_get_distances_pool_imap(archive_path, point_cloud, num_proc, num_iterations):# do the meshes processing within a poolelapsed_time = []for _ in range(num_iterations):archive = MeshesArchive(archive_path)pool = Pool(num_proc)start = time.time()result = list(tqdm(pool.imap(load_mesh_get_distance,zip(archive, itertools.repeat(point_cloud)),), total=len(archive)))pool.close()pool.join()end = time.time()elapsed_time.append(end - start)print(f'[Process meshes: pool.imap] Pool of {num_proc} processes elapsed time: {np.array(elapsed_time).mean()} sec')for name, dist in zip(archive.names_list, result):print(f"{name} {dist}")return resultif __name__ == "__main__":bunny_path = "./data/meshes/stanford-bunny.obj"archive_path = "./data/meshes.7z"num_proc = 4num_iterations = 3point_cloud = load_bunny_pc(bunny_path)read_meshes_get_distances_pool_no_manager_imap(archive_path, point_cloud, num_proc, num_iterations)

这里 read_meshes_get_distances_pool_imap 是一个核心函数,其中完成了以下操作:

  • MeshesArchive 和 multiprocessing.Pool 已初始化
  • 应用 tqdm 来监视池进度,并手动完成整个池的分析
  • 执行结果的输出

请注意我们如何将参数传递给 imap,使用 zip(archive, itertools.repeat(point_cloud)) 从 archive 和 point_cloud 创建新的可迭代对象。 这使我们能够将点云数组粘贴到存档的每个条目,从而避免将存档转换为列表。

执行结果如下所示:

100%|####################################################################| 5/5 [00:00<00:00,  5.14it/s]
100%|####################################################################| 5/5 [00:00<00:00,  5.08it/s]
100%|####################################################################| 5/5 [00:00<00:00,  5.18it/s]
[Process meshes: pool.imap w/o manager] Pool of 4 processes elapsed time: 1.0080536206563313 sec
armadillo.obj 0.16176825266293382
beast.obj 0.28608649819198073
cow.obj 0.41653845909820164
spot.obj 0.22739556571296735
stanford-bunny.obj 2.3699851136074263e-05

我们可以发现斯坦福兔子是最接近给定点云的网格。 还可以看出,我们没有使用大量数据,但我们已经证明,即使存档中有大量网格,该解决方案也能发挥作用。

多重处理使数据科学家不仅在 3D 计算机视觉方面而且在机器学习的其他领域都取得了出色的表现。 理解并行执行比循环内执行要快得多,这一点非常重要。 尤其是当算法编写正确时,差异变得非常显着。 大量数据揭示的问题如果没有创造性的方法来利用有限的资源就无法解决。 幸运的是,Python 语言及其丰富的库可以帮助我们数据科学家解决此类问题。


原文链接:3D模型处理的并行化 - BimAnt

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SHELL编程----Nginx日志分析2-统计某个时间段的IP访问量

描述 假设 Nginx 的日志存储在 nowcoder.txt 里&#xff0c;内容如下&#xff1a; 192.168.1.20 - - [21/Apr/2020:14:27:49 0800] "GET /1/index.php HTTP/1.1" 404 490 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:45.0) Gecko/20100101 F…

AI论文速读 | 2024[VLDB]TFB:全面与公正的时间序列预测方法基准测试研究

论文标题&#xff1a;TFB: Towards Comprehensive and Fair Benchmarking of Time Series Forecasting Methods 作者&#xff1a;Xiangfei Qiu ; Jilin Hu&#xff08;胡吉林&#xff09; ; Lekui Zhou ; Xingjian Wu ; Junyang Du ; Buang Zhang ; Chenjuan Guo&#xff08;郭…

【贪心算法经典应用】哈夫曼编码原理与算法详解 python

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 python数据分析…

【软件】如何下载谷歌安装包?

1、访问谷歌浏览器官网&#xff1a;https://www.google.cn/chrome/index.html 2、在浏览器地址栏最后添加?standalone1&#xff0c;按回车&#xff0c;重新加载页面。页面和之前的一样&#xff0c;点击下载 完整地址&#xff1a;https://www.google.cn/chrome/index.html?…

2024年第十六届“华中杯”(A题)大学生数学建模挑战赛| 物理建模,多目标优化| 数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看华中杯 (A题&#xff09;&#xff01; CS团队倾…

c++学习笔记1,c的扩充

目录 命名空间与c标准库的使用 非面向对象方面的扩充 输入输出方面 引用 结构体、枚举、联合 重载函数 默认参数的函数 作用域运算符 动态内存分配 命名空间与c标准库的使用 为了将c标准库兼容进入std命名空间&#xff0c;c使用c库时要在原名前加c来和c标准库加以区分…

Java面试八股之Iterator和ListIterator的区别是什么

Iterator和ListIterator的区别是什么 这道题也是考查我们对迭代器相关的接口的了解程度&#xff0c;从代码中我们可以看出后者是前者的子接口&#xff0c;在此基础上做了一些增强&#xff0c;并且只用于List集合类型。 定义与基本概念 Iterator&#xff1a; 定义&#xff1a…

虚拟人多元化互动玩法,助力各领域发布会/直播活动“玩转”营销新高度

在数字新科技推动下&#xff0c;各地方文旅、品牌纷纷在发布会、展会、行业峰会论坛、推广直播等场景中&#xff0c;融入虚拟人IP&#xff0c;将虚拟人IP作为虚拟主播、虚拟主持人、虚拟嘉宾、虚拟推荐官、AI数字迎宾员、AI播报员等多重身份&#xff0c;与观众实时互动交流&…

A24 STM32_HAL库函数 之 I2s通用驱动 -- A-- 所有函数的介绍及使用

A24 STM32_HAL库函数 之 I2s通用驱动 -- A-- 所有函数的介绍及使用 1 该驱动函数预览1.1 HAL_I2S_Init1.2 HAL_I2S_DeInit1.3 HAL_I2S_MspInit1.4 HAL_I2S_MspDeInit1.5 HAL_I2S_Transmit1.6 HAL_I2S_Receive1.7 HAL_I2S_Transmit_IT1.8 HAL_I2S_Receive_IT1.9 HAL_I2S_Transmi…

【动态规划】C++解决斐波那契模型题目(三步问题、爬楼梯、解码方法...)

1. 前言 - 介绍动态规划算法 动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09; 是一种解决复杂问题的算法设计技术&#xff0c;通常用于解决具有重叠子问题和最优子结构性质的问题。它将问题分解成较小的子问题&#xff0c;通过解决这些子问题并保存其…

android车机代码结构分析

1 先看了android系统的整体目录 art虚拟机&#xff0c; device 支持的设备及相关配置&#xff0c; external使用的外部开源库 frameworks // Android基础框架&#xff0c; hardware // HAL层&#xff0c; kernel // packages // 各种app 其他的目录都是系统辅助相关的&am…

NFTScan | 04.08~04.14 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2024.04.08~ 2024.04.14 NFT Hot News 01/ 数据&#xff1a;Runestone 地板价突破 0.07 BTC&#xff0c;创历史新高 4 月 8 日&#xff0c;据数据显示&#xff0c;Runestone 地板价突破 …

阿里面试:DDD中的实体、值对象有什么区别?

在领域驱动设计&#xff08;DDD&#xff09;中&#xff0c;有两个基础概念&#xff1a;实体&#xff08;Entity&#xff09;和值对象&#xff08;Value Object&#xff09;。 使用这些概念&#xff0c;我们可以把复杂的业务需求映射成简单、明确的数据模型。正确使用实体和值对…

每日三个JAVA经典面试题(四十)

1.如何使用设计模式来提高数据库操作的性能&#xff1f; 设计模式可以在数据库操作中提高性能&#xff0c;尤其是在应用程序需要频繁访问数据库时。以下是一些设计模式和技术&#xff0c;可以帮助提高数据库操作的性能&#xff1a; 数据访问对象模式&#xff08;DAO模式&#…

Java详解:GUI容器组件 | 功能组件

✎ 简介&#xff1a; Graphical User Interface&#xff08;GUI&#xff09;图形用户界面 图形界面对于用户来说在视觉上更易于接受. ✎ 关于swing: • swing是一个为java设计的GUI工具包javax.swing&#xff0c;包括了用户界面的各种组件. • swing中组件可以分为两大类&…

基于FPGA的OMEGA东京奥运会计时器

截至2019年共举办了31届奥运会&#xff0c;其中27届的计时设备都由欧米茄&#xff08;OMEGA&#xff0c;Ω&#xff09;提供&#xff0c;今年的东京奥运会将会是第28届。 瑞士计时公司&#xff08;Swiss Timing&#xff09;基于火星Mars ZX2核心板打造了为奥运会等大型体育赛事…

AWVS+子域名平台联合自动化渗透测试工具(非常详细)零基础入门到精通,收藏这一篇就够了

项目地址 https://github.com/Minority2310/awvs-subdomain_platformawvs-subdomain_platform&#xff1a;AWVS子域名平台联合自动化渗透测试 如有侵权&#xff0c;请联系删除 为了帮助大家更好的学习网络安全&#xff0c;我给大家准备了一份网络安全入门/进阶学习资料&#…

【Python100+例】练完所有例题

前言&#xff1a; 有疑问的可以相互沟通学习交流&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 1.两数之和 a, b 3.5, 4.0print(f"{a}{b}的和是{ab}")------------------------------------- 1.元组赋值可以省略括号 2.…

PLC程序远程上下载

在工业自动化领域&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;扮演着至关重要的角色。然而&#xff0c;传统的PLC程序上传与下载方式往往受限于物理距离和现场环境&#xff0c;给工程师们带来了诸多不便。如今&#xff0c;随着远程技术的不断发展&#xff0c;PLC程…

IA-32处理器寄存器浅析

IA-32架构下寄存器分为基本寄存器和系统寄存器。 一、基本寄存器 基本寄存器包括通用寄存器&#xff08;EAX、EBA、ECX、EDX、ESI、EDI、EBP、ESP&#xff09;、段寄存器(CS、DS、SS等)、指令指针寄存器EIP、EFLAGS寄存器。通用寄存器的一些特殊用法&#xff1a; 1、EAX在乘法…