3D模型处理的并行化

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

那么我们为什么要诉诸并行计算呢? 使用数据有时会出现与大数据相关的问题。 每次我们遇到 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 语言及其丰富的库可以帮助我们数据科学家解决此类问题。

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

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

相关文章

Backend - DRF 序列化(django-rest-framework)

目录 一、restful 、django-rest-framework 、swagger 三者的关系 &#xff08;一&#xff09;restful API&#xff08;REST API&#xff09; 1. rest 2. restful 3. api 4. restfulAPI &#xff08;二&#xff09;django-rest-framework&#xff08;简称DRF&#xff09…

Web3D智慧医院平台(HTML5+Threejs)

智慧医院的建设将借助物联网、云计算、大数据、数字孪生等技术&#xff0c;以轻量化渲染、极简架构、三维可视化“一张屏”的形式&#xff0c;让医院各大子系统管理既独立又链接&#xff0c;数据相互融合及联动。 建设医院物联网应用的目标对象&#xff08;人、物&#xff09;都…

7 pytorch DataLoader, TensorDataset批数据训练方法

前言 本文主要介绍pytorch里面批数据的处理方法&#xff0c;以及这个算法的效果是什么样的。具体就是要弄明白这个批数据选取的算法是在干什么&#xff0c;不会涉及到网络的训练。 from torch.utils.data import DataLoader, TensorDataset主要实现就是上面的数据集和数据载入…

pdf做批注编辑工具 最新pdf reader pro3.3.1.0激活版

PDF Reader Pro是一款功能强大的PDF阅读和编辑工具。它提供了多种工具和功能&#xff0c;帮助用户对PDF文档进行浏览、注释、编辑、转换和签名等操作。以下是PDF Reader Pro的一些主要特色&#xff1a; 最新pdf reader pro3.3.1.0激活版下载 多种查看模式&#xff1a;PDF Reade…

STM32 PB3 PB4 无法作为 GPIO 使用解决办法

如下所示&#xff0c;PA13 PA14 PB3 PB4 PB5, 默认是JTAG SWD的 PIN, 需要引脚ReMap 才能作为GPIO 使用。 HAL库解决办法 // __HAL_AFIO_REMAP_SWJ_ENABLE(); //Full SWJ (JTAG-DP SW-DP):// __HAL_AFIO_REMAP_SWJ_NONJTRST(); //Full SWJ (JTAG-DP SW-DP) but without NJTR…

【代理模式】静态代理-简单例子

在Java中&#xff0c;静态代理是一种设计模式&#xff0c;它涉及到为一个对象提供一个代理以控制对这个对象的访问。静态代理在编译时就已经确定&#xff0c;代理类和被代理类会实现相同的接口或者是代理类继承被代理类。客户端通过代理类来访问&#xff08;调用&#xff09;被…

认识异常(1)

❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&a…

计算机网络:MAC地址 IP地址 ARP协议

计算机网络&#xff1a;MAC地址 & IP地址 & ARP协议 MAC地址IP地址ARP协议 MAC地址 如果两台主机通过一条链路通信&#xff0c;它们不需要使用地址就可以通信&#xff0c;因为连接在信道上的主机只有他们两个。换句话说&#xff0c;使用点对点信道的数据链路层不需要使…

开源 Ruo-Yi 项目引入 Mybatis-Plus:3.5.3 报错ClassNotFoundException:

开源 Ruo-Yi 项目引入 Mybatis-Plus:3.5.3 报错ClassNotFoundException&#xff1a; Caused by: java.lang.ClassNotFoundException: com.baomidou.mybatisplus.extension.plugins.MybatisPlusInter1 分析问题 控制台报错说明我们引入的 mybatis-plus 的依赖里找不到com.baom…

数字化转型-工具变量数据集

01、数据介绍 数字化转型是指企业或个人利用数字技术&#xff0c;如大数据、云计算、人工智能等&#xff0c;对其业务流程、运营模式、决策方式等进行全面、深入的变革&#xff0c;以提高效率、降低成本、提升质量、增强竞争力。在这个过程中&#xff0c;工具变量扮演着至关重…

JVM虚拟机(九)如何开启 GC 日志

目录 一、引言二、开启 GC 日志三、解析 GC 日志四、优化建议 一、引言 在 Java 应用程序的运行过程中&#xff0c;垃圾收集&#xff08;Garbage Collection&#xff0c;简称 GC&#xff09;是一个非常重要的环节。GC 负责自动管理内存&#xff0c;回收不再使用的对象所占用的…

zabbix 自动发现与自动注册 部署 zabbix 代理服务器

zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大。1.确保客户端…

一次配置Docker环境的完整记录

一次配置Docker环境的完整记录 Docker环境搭建报错与解决报错一报错二报错三 Docker环境搭建 本节介绍了一次配置docker环境的完整记录&#xff1a; 编写Dockerfile文件&#xff1a; FROM pytorch/pytorch:1.10.0-cuda11.3-cudnn8-develRUN rm /etc/apt/sources.list.d/cuda.l…

mfc 带有复选框的ListBox

mfc 带有复选框的 ListBox 效果&#xff1a; 添加 ListBox 控件 从工具箱拖拽 ListBox 控件到窗口上&#xff0c;并设置属性&#xff1a; 包含字符串&#xff1a;true所有者描述&#xff1a;Fixed 给ListBox添加控制变量 添加完后&#xff0c;将m_list_box的类型使用CC…

Qt+vstudio2022的报错信息积累

从今天开始记录一下平常开发工作中的报错记录&#xff0c;后续有错误动态补充&#xff01; 报错信息&#xff1a;【MSB8041】此项目需要 MFC 库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。 解决&#xff1a; 背景&#xff1a;换…

uniapp--登录和注册页面-- login

目录 1.效果展示 2.源代码展示 测试登录 login.js 测试请求 request.js 测试首页index.js 1.效果展示 2.源代码展示 <template><view><f-navbar title"登录" navbarType"4"></f-navbar><view class"tips"><…

图数据库Neo4J入门——Neo4J下载安装+Cypher基本操作+《西游记》人物关系图实例

这里写目录标题 一、效果图二、环境准备三、数据库设计3.1 人物节点设计3.2 关系设计 四、操作步骤4.1 下载、安装、启动Neo4J服务4.1.1 配置Neo4J环境变量4.1.2 启动Neo4J服务器4.1.3 启动Ne04J客户端 4.2 创建节点4.3 创建关系&#xff08;从已有节点创建关系&#xff09;4.4…

PhpStorm2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 PhpStorm是由JetBrains公司开发的一款商业的PHP集成开发环境&#xff08;IDE&#xff09;&#xff0c;深受全球开发人员的喜爱。它旨在提高开发效率&#xff0c;通过深刻理解用户的编码习惯&#xff0c;提供智能代码补全、快速导…

Java面试八股文(JVM篇)(❤❤)

Java面试八股文_JVM篇 1、知识点汇总2、知识点详解&#xff1a;3、说说类加载与卸载11、说说Java对象创建过程12、知道类的生命周期吗&#xff1f;14、如何判断对象可以被回收&#xff1f;17、调优命令有哪些&#xff1f;18、常见调优工具有哪些20、你知道哪些JVM性能调优参数&…

vue的就地更新与v-for的key属性

vue的就地更新 Vue中的就地更新到底是怎么回事&#xff0c;为什么会存在就地更新的现象&#xff1f; 注意下面的例子&#xff0c;使用v-for指令时&#xff0c;没有绑定key值&#xff0c;才有就地更新的现象&#xff0c;因为Vue默认按照就地更新的策略来更新v-for渲染的元素列表…