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 语言及其丰富的库可以帮助我们数据科学家解决此类问题。
相关文章:

3D模型处理的并行化
今天我们将讨论如何使用 Python 多进程来处理大量3D数据。 我将讲述一些可能在手册中找到的一般信息,并分享我发现的一些小技巧,例如将 tqdm 与多处理 imap 结合使用以及并行处理存档。 那么我们为什么要诉诸并行计算呢? 使用数据有时会出现…...

盲人安全导航技巧:科技赋能让出行更自如
作为一名资深记者,长期关注并报道无障碍领域的发展动态。今日,我将聚焦盲人安全导航技巧,探讨这一主题下科技如何赋能视障人士实现更为安全、独立的出行。一款融合了实时避障、拍照识别物体及场景功能的盲人出行辅助应用叫做蝙蝠避障…...
问,由于java存在性能上,以及部分功能上的缺点,请问如何正确使用C,C++,Go,这三个语言,提升Java Web项目的性能?
拓展阅读:版本任你发,我用java8 我明白Java虽然在许多方面表现出色,但在某些特定场景下可能会遇到性能瓶颈或功能限制。为了提升Java Web项目的性能,可以考虑将C、C和Go这三种语言用于特定的组件或服务。以下是如何正确使用这些语…...
【信号与系统 - 9】傅里叶变换的性质习题
1 习题 已知 f ( t ) f(t) f(t) 的傅里叶变换为 F ( j w ) F(jw) F(jw) ,求如下信号的傅里叶变换 (1) t ⋅ f ( 3 t ) t\cdot f(3t) t⋅f(3t) 解: f ( 3 t ) ↔ 1 3 F ( j w 3 ) f(3t)\leftrightarrow \frac{1}{3}F(j\frac{w}…...
C#探索之路基础夯实篇(5):语法糖概念解析
C#探索之路基础夯实篇(5):语法糖概念解析 文章目录 C#探索之路基础夯实篇(5):语法糖概念解析1、概念定义2、Lua中的语法糖3、C#中的语法糖4、C中的语法糖5、优缺点辨析6、适用范围7、总结 从之前一开始接触lua的时候开始,开始第一次接触到语法…...

SeaTunnel 与 DataX 、Sqoop、Flume、Flink CDC 对比
产品概述 Apache SeaTunnel 是一个非常易用的超高性能分布式数据集成产品,支持海量数据的离线及实时同步。每天可稳定高效同步万亿级数据,已应用于数百家企业生产,也是首个由国人主导贡献到 Apache 基金会的数据集成顶级项目。 SeaTunnel 主要解决数据集成领域的常见问题:…...
深入理解汇编:平栈、CALL和RET指令详解
视频学习下载地址:https://pan.quark.cn/s/04e6946a803a 汇编语言以其接近硬件的特性和高效的执行速度,在系统编程、性能优化和逆向工程中占有不可或缺的地位。本文将深入探讨汇编语言中的平栈操作以及CALL和RET指令&#…...

DP4 最小花费爬楼梯
原题链接:最小花费爬楼梯_牛客题霸_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 dp。 开一个dp数组和a数组。dp[i]表示在当前这一格所需要的费用,a数组其实就是题目中的cost数组。 因为最后要求到顶楼的最低费用&a…...
OpenXR API概览与核心组件解析
在虚拟现实(VR)和增强现实(AR)领域,OpenXR API提供了一个重要的开放标准,使得开发者能够跨多种硬件和软件平台创建兼容的应用。本文将详细解释OpenXR中的核心组件和数据结构,并探讨它们如何共同…...

安装指定版本的ant-design-vue和指定版本的@ant-design/icons-vue 图标组件包
前言: 最近在完成公司的项目时,为了兼容其他的版本,需要安装指定版本的ant-design-vue和ant-design/icons-vue 图标组件包,安装成功之后,分享如下: 安装命令: ant-design-vue: 不…...
Zynq7000系列中的休眠模式
休眠模式是在系统层面定义的,它包括将APU置于待机模式,并将多个控制器保持在无时钟的复位状态。 进入休眠模式可以大大降低功耗。在休眠模式下,大多数功能时钟组都会被关闭或断电。唯一需要保持活动的设备是一个CPU、窥探控制单元(…...
在redhat7/8平台上部署ELK7.17.18的技术方案
部署环境说明 为节省资源直接使用1台测试机模拟3节点elasticsearch服务集群做部署,在该主机上同时部署了3个elasticsearch实例、1个logstash实例、1个kibana实例、1个filebeat实例。对于生产环境,以上实例服务应该做分布式部署。 ELK-TEST1 192.168.10…...
(Chat For Al,创新Al,汇语Al助手,AiTab新标签,万能助手,LLaVA)分享6个好用的ChatGPT
目录 1、Chat For AI 2、创想AI 3、汇语AL助手...
MySQL-锁篇
文章目录 表级锁和行级锁了解吗?有什么区别?行级锁使用有什么注意事项?InnoDB有哪几类行锁?共享锁和排他锁是什么?意向锁有什么用? 锁是一种常见的并发事务的控制方式 表级锁和行级锁了解吗?有什…...

滤波器笔记(杂乱)
线性相位是时间平移,相位不失真 零、基础知识 1、用相量表示正弦量 https://zhuanlan.zhihu.com/p/345546880 https://www.zhihu.com/question/347763932/answer/1103938667 A s i n ( ω t θ ) ⇔ A e j θ ⇔ A ∠ θ Asin(\omega t\theta) {\Leftrightarrow…...

【ARFoundation自学01】搭建AR框架,检测平面点击位置克隆物体
Unity开发ARFoundation相关应用首先安装ARFoundation包 然后设置XR 1.基础AR场景框架搭建 2.一个基本的点击克隆物体到识别的平面脚本 挂在XROrigin上 脚本AppController 脚本说明书 ## 业务逻辑 AppController 脚本旨在实现一个基本的 AR 应用程序功能:用户通过…...
.Net ajax 接收参数
后端部分代码 一般处理程序 public void ProcessRequest(HttpContext context){context.Response.ContentType "text/plain";string str_index context.Request.Form.AllKeys.Contains("index") ? context.Request.Form["index"].ToString(…...

智能零售:引领购物新时代
智能零售通过整合人工智能、物联网、大数据和机器学习等技术,正在彻底改变传统的购物模式,为消费者和零售商提供前所未有的效率和个性化体验。 智能零售利用消费者数据分析来提供个性化的购物推荐。无论是在线平台或是实体店内,智能系统都能…...

【AIGC】AIGC在虚拟数字人中的应用:塑造未来互动体验的革新力量
🚀 🚀 🚀随着科技的快速发展,AIGC已经成为引领未来的重要力量。其中,AIGC在虚拟数字人领域的应用更是引起了广泛关注。虚拟数字人作为一种先进的数字化表达形式,结合了3D建模、动画技术、人工智能等多种先进…...

电机控制器电路板布局布线参考指导(五)
电机控制器电路板布局布线参考指导(五)大容量电容和旁路电容的放置 1.大容量电容的放置2.电荷泵电容器3.旁路电容/去耦电容的放置3.1 靠近电源3.2 靠近功率器件3.3 靠近开关电流源3.4 靠近电流感测放大器3.5 靠近稳压器 tips:资料主要来自网络…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
当下AI智能硬件方案浅谈
背景: 现在大模型出来以后,打破了常规的机械式的对话,人机对话变得更聪明一点。 对话用到的技术主要是实时音视频,简称为RTC。下游硬件厂商一般都不会去自己开发音视频技术,开发自己的大模型。商用方案多见为字节、百…...

vxe-table vue 表格复选框多选数据,实现快捷键 Shift 批量选择功能
vxe-table vue 表格复选框多选数据,实现快捷键 Shift 批量选择功能 查看官网:https://vxetable.cn 效果 代码 通过 checkbox-config.isShift 启用批量选中,启用后按住快捷键和鼠标批量选取 <template><div><vxe-grid v-bind"gri…...
Neo4j 完全指南:从入门到精通
第1章:Neo4j简介与图数据库基础 1.1 图数据库概述 传统关系型数据库与图数据库的对比图数据库的核心优势图数据库的应用场景 1.2 Neo4j的发展历史 Neo4j的起源与演进Neo4j的版本迭代Neo4j在图数据库领域的地位 1.3 图数据库的基本概念 节点(Node)与关系(Relat…...

C++课设:实现本地留言板系统(支持留言、搜索、标签、加密等)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、项目功能概览与亮点分析1. 核心功能…...