利用Python多处理库处理3D数据详解
作者:一大口奶酪 发布时间:2021-03-05 18:11:18
今天我们将介绍处理大量数据时非常方便的工具。我不会只告诉您可能在手册中找到的一般信息,而是分享一些我发现的小技巧,例如tqdm与 multiprocessingimap一起使用、并行处理档案、绘制和处理 3D 数据以及如何搜索如果您有点云,则用于对象网格中的类似对象。
那么我们为什么要求助于并行计算呢?如今,如果您处理任何类型的数据,您可能会面临与“大数据”相关的问题。每次我们有不适合 RAM 的数据时,我们都需要一块一块地处理它。幸运的是,现代编程语言允许我们生成在多核处理器上完美运行的多个进程(甚至线程)。(注意:这并不意味着单核处理器不能处理多处理。 这是关于该主题的堆栈溢出线程。)
今天,我们将尝试处理经常发生的计算网格和点云之间距离的 3D 计算机视觉任务。例如,当您需要在所有可用网格中找到定义与给定点云相同的 3D 对象的网格时,您可能会遇到此问题。
我们的数据由.obj存储在.7z存档中的文件组成,这在存储效率方面非常出色。但是当我们需要访问它的确切部分时,我们应该努力。在这里,我定义了包装 7-zip 存档并提供底层数据接口的类。
类 Archive7z(基础):
def __init__ ( self , file , password = None ):
# ...
自我。文件={}
# ...
对于信息的文件。文件:
#创建一个知道磁盘位置的ArchiveFile实例
file = ArchiveFile ( info , pos , src_pos , folder , self , maxsize = maxsize )
# ...
自我。文件。追加(文件)
# ...
自我。文件映射。更新([(X。文件名,X)为X的自我。文件])
#从files_map字典返回ArchiveFile的方法
def getmember ( self , name ):
if isinstance ( name , ( int , long )):
尝试:
回归自我。文件[名称]
除 了 IndexError:
返回无
回归自我。文件映射。获取(名称,无)
类 Archive7(基础):
定义读取(自我):
# ...
对于水平,编码器在枚举(自我。_folder。编码器):
# ...
#获取解码器并解码底层数据
data = getattr ( self , decoder ) ( coder , data , level , num_coders )
返回数据
这个类几乎不依赖py7zlib包,它允许我们在每次调用get方法时解压缩数据并为我们提供存档中的文件数。我们还定义了__iter__这将帮助我们map像在可迭代对象上一样在该对象上启动多处理。
您可能知道,可以创建一个 Python 类,从中可以实例化可迭代对象。该类应满足以下条件:覆盖__getitem__返回self和__next__返回后续元素。我们绝对遵守这条规则。
上面的定义为我们提供了遍历存档的可能性,但 它是否允许我们 并行随机访问内容,这是一个有趣的问题,我在网上没有找到答案,但我们可以研究源代码py7zlib并尝试自己回答。
在这里,我提供了来自pylzma的代码片段:
类 Archive7z(基础):
def __init__ ( self , file , password = None ):
# ...
自我。文件={}
# ...
对于信息的文件。文件:
#创建一个知道磁盘位置的ArchiveFile实例
file = ArchiveFile ( info , pos , src_pos , folder , self , maxsize = maxsize )
# ...
自我。文件。追加(文件)
# ...
自我。文件映射。更新([(X。文件名,X)为X的自我。文件])
#从files_map字典返回ArchiveFile的方法
def getmember ( self , name ):
if isinstance ( name , ( int , long )):
尝试:
回归自我。文件[名称]
除 了 IndexError:
返回无
回归自我。文件映射。获取(名称,无)
类 Archive7z(基础):
定义读取(自我):
# ...
对于水平,编码器在枚举(自我。_folder。编码器):
# ...
#获取解码器并解码底层数据
data = getattr ( self , decoder ) ( coder , data , level , num_coders )
返回数据
在代码中,您可以看到在从存档中读取下一个对象期间调用的方法。我相信从上面可以清楚地看出,只要同时多次读取存档,就没有理由阻止存档。
接下来,我们快速介绍一下什么是网格和点云。
首先,网格是顶点、边和面的集合。顶点由空间中的(x,y,z) 坐标定义并分配有唯一编号。边和面是相应的点对和三元组的组,并用提到的唯一点 id 定义。通常,当我们谈论“网格”时,我们指的是“三角形网格”,即由三角形组成的表面。使用trimesh库在 Python 中使用网格要容易得多。例如,它提供了一个接口来加载.obj内存中的文件。要在jupyter notebook一个3D 对象中显示和交互,可以使用k3d库。
所以,用下面的代码片段我回答这个问题:“你怎么绘制trimesh的对象jupyter有k3d?”
进口饰面
导入k3d
使用 open ( w. /data/meshes/stanford-bunny, obj")作为 f : bunny_mesh =网眼。力口载(f , 'obj')
情节=k3d。情节()
网格= k3d。网格 (bunny_mesh . vertices> bunny_mesh . faces) 绘图上网格
情节。显示。
其次,点云是表示空间中对象的 3D 点数组。许多 3D 扫描仪生成点云作为扫描对象的表示。出于演示目的,我们可以读取相同的网格并将其顶点显示为点云。
进口饰面
导入k3d
使用 open ( w. /data/meshes/stanford-bunny, obj")作为 f :
bunny_mesh =网眼。力口载(f , 'obj')
情节=k3d。情节()
云=k3d。点(bunny_mesh . vertices , point_size = 0. 0001 , shader = "flat")
情节+=云
情节。显示。
k3d绘制的点云
如上所述,3D 扫描仪为我们提供了一个点云。假设我们有一个网格数据库,我们想在我们的数据库中找到一个与扫描对象对齐的网格,也就是点云。为了解决这个问题,我们可以提出一种简单的方法。我们将从我们的档案中搜索给定点云的点与每个网格之间的最大距离。如果1e-4某些网格的距离更小,我们将认为该网格与点云对齐。
最后,我们来到了多处理部分。请记住,我们的存档中有大量文件可能无法放在一起放在内存中,因为我们更喜欢并行处理它们。为了实现这一点,我们将使用 multiprocessing Pool,它使用map或imap/imap_unordered方法处理用户定义函数的多次调用。map和imap影响我们的区别在于,map在将其发送到工作进程之前将可迭代对象转换为列表。如果存档太大而无法写入 RAM,则不应将其解压缩到 Python 列表中。换句话说,两者的执行速度是相似的。
[加载网格:pool.map w/o manager] 4 个进程的池经过时间:37.213207403818764 秒
[加载网格:pool.imap_unordered w/o manager] 4 个进程的池经过时间:37.219303369522095 秒
上面您可以看到从适合内存的网格档案中简单读取的结果。
更进一步imap:让我们讨论如何实现我们的目标,即找到靠近点云的网格。这是数据。我们有 5 种来自斯坦福模型的不同网格。我们将通过向斯坦福兔子网格的顶点添加噪声来模拟 3D 扫描。
将numpy导入为np
A numpy。随机 导入 defaulting
def normalize_pc (点):
点额=点额-点额。平均值(轴=0)[无,:]
分布=np。linalg<>范数(点,轴=1) scaled_points =点 / dists中。最大值。 返回 scaled_points
def load_bunny_pc ( bunny_path ):
标准差=lₑ-3
使用 open ( bunny_path )作为 f : bunny_mesh = load_mesh ( f )
#标准化后云
scaled_bunny = normalize_pc ( bunny_mesh . vertices )
#向点云添加一些噪声 rng = defaulting ()
噪音=rng。正常(0. 0 , STD , scaled_bunny . shape ) 畸变兔子=缩放兔子+噪声
返回 di st ort ed_bunny
当然,我们之前在下面将点云和网格顶点归一化,以在 3D 立方体中缩放它们。
要计算点云和网格之间的距离,我们将使用igl。为了完成,我们需要编写一个函数来调用每个进程及其依赖项。让我们用下面的代码片段来总结一下。
导入迭代工具
导入时间
将 numpy 导入为 np
nwnpyo 随机导入 default rng
面以1 口口如 进进从
A多处理导入池
de£ load_mesh ( obj_file ):
目二 trimesh。力口载(obj_file , ' obj')
返回网格
def get_max__dist ( basjmesh , point_cloud ):
distance_sq , mesh_face__indexes , _ = igl。point_mesh_squared_distance (
点云,
basjmesho 顶点,
basjmesho 面孔
)
返回distancjsq。最大值0
def 1 oad_mesh__get_di stance ( args ):
obj_file , point__cloud = args [ 0 ]/ args [ 1 ]
网格二 load_mesh ( obj_file )
网。顶点=RormaliNe_pc (网格。顶点)
max_dist = get_max_dist (网格,点云)
返回 max__dist
de£ read_meshes__get__di stances_pool__imap ( archive_path , point_cloud , nwn_proc , nwn_i terations ):
#在疝中进行向格“理
elapsed__time =[]
为一在 范围(nujn-i terati ons ):
归档二 MeshesArchive (ARCHIVE-PATH)
池二池(nwn_proc )
开始=时间。时间0
导致=名单(tqdm(池。IMAP (
1 o ad_m e sh__ge t_di s t anc e ,
zip (存档,itertoolso 重复(point_cloud)),
),总计=len辱档)))
池。关闭0
池。加入o
结束=时间。时间0
elapsed time o追加(结束一开始)
print ( F [Process meshes: pool, imap] {num_proc}个进程的池经过的时间:{np. array (elapsed_time). mean()} sec )
对于 name , di st in zip ( archive . namesjist , result ): 打印(r{name} {dist}")
返回结果
如果 _name_ ==
bunny_path = /data/meshes/stanford-bunny, obj"
archive_path = /data/meshes. 7zff
nwn_proc = 4
num_iterations = 3
point__cloud - load__bunny_pc ( bunny_path )
read_meshes__get__di stances_pool_no_manager__imap ( archive_path ,point_cloud , nwn_proc , num.
iterations )
这read_meshes_get_distances_pool_imap是一个中心函数,其中完成以下操作:
MeshesArchive并multiprocessing.Pool初始化
tqdm 用于观察池进度,并手动完成整个池的分析
执行结果的输出
请注意我们如何传递参数以imap从archive和point_cloud使用zip(archive, itertools.repeat(point_cloud)). 这允许我们将点云数组粘贴到存档的每个条目上,避免转换archive为列表。
执行结果如下:
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]
[进程网格:pool.imap w/o manager] 4 个进程的池经过时间:1.0080536206563313 秒
犰狳.obj 0.16176825266293382
野兽.obj 0.28608649819198073
牛.obj 0.41653845909820164
现货.obj 0.22739556571296735
stanford-bunny.obj 2.3699851136074263e-05
我们可以注意到斯坦福兔子是最接近给定点云的网格。还可以看出,我们没有使用大量数据,但我们已经证明,即使我们在存档中有大量网格,该解决方案也能奏效。
多处理使数据科学家不仅在 3D 计算机视觉中而且在机器学习的其他领域中都取得了出色的表现。理解并行执行比在循环内执行快得多是非常重要的。差异变得显着,尤其是在正确编写算法时。大量数据揭示了如果没有关于如何使用有限资源的创造性方法就无法解决的问题。幸运的是,Python 语言及其广泛的库集帮助我们数据科学家解决了这些问题。
来源:https://blog.51cto.com/nailaoer/4832794
猜你喜欢
- 之前在网上查找了很多相关资料,有说设置icon高度来支持item的,有说要添加自己写指定高度的view来填充的,但是对于一个只有文字的Qco
- 用selenium做自动化,有时候会遇到需要模拟鼠标操作才能进行的情况,比如单击、双击、点击鼠标右键、拖拽等等。而selenium给我们提供
- 前言:通常我们创建类都是使用class 类名,但是小伙伴们有没有想过,类是由谁来创建的呢,python中常说的万物皆对象,对象是由类创建的,
- 什么是协程在 Python 中,协程(Coroutine)是一种轻量级的并发编程方式,可以通过协作式多任务来实现高效的并发执行。协程是一种特
- Pycharm默认可以识别py脚本中的SQL语句,本身很不错,但当SQL拼接时就显示的代码特别难看,找了好久,终于知道怎么关闭SQL识别功能
- 1、Pylint是什么pylint是一个Python源代码中查找bug的工具,能找出错误,和代码规范的运行。也就是你的代码有Error错误的
- 本文实例讲述了Python使用Dijkstra算法实现求解图中最短路径距离问题。分享给大家供大家参考,具体如下:这里继续前面一篇《Pytho
- 一、安装matplotlib1)由于已安装anaconda,可直接打开anaconda prompt,再用命令pip install mat
- 前言不同于Linux服务器上的命令行操作,在windows系统上用户的使用习惯还是倾向于使用有界面的工具。如果工具是命令行交互操作的方式,可
- 大部分服务器管理员知道MySQL数据库管理系统(RDBMS)是高度灵活的软件块,带有范围广阔的启动选项,可以用来修改相关行为。然而,大部分人
- 先举个例子,分别以不指定编码、指定编码为 utf-8、指定编码为 utf-8-sig 三种方式来做比较,再将写入 csv 文件和 txt 文
- reduce() 函数在 python 2 是内置函数, 从python 3 开始移到了 functools 模块。官方文档是这样介绍的re
- 如果你能很好的理解我下面的一句话,那这些都不是问题了。asp是服务器端语言,它的作用是动态生成客户端浏览器所能识别的html css jav
- PDOStatement::setAttributePDOStatement::setAttribute — 设置一个语句属性(PHP 5
- 作为酷爱编程的老程序员,实在按耐不下这个冲动,Python真的是太火了,不断撩拨我的心。我是对Python存有戒备之心的,想当年我基于Dru
- 然而,微软sql server在处理这类索引时,有个重要的缺陷,那就是把本该编译成索引seek的操作编成了索引扫描,这可能导致严重性能下降
- 经常由于各种压缩格式的不一样用到文件的解压缩时就需要下载不同的解压缩工具去处理不同的文件,以至于桌面上的压缩工具就有三四种,于是使用pyth
- 深度学习中,模型训练一般都需要很长的时间,由于很多原因,导致模型中断训练,下面介绍继续断点训练的方法。方法一:载入模型时,不必指定迭代次数,
- 如何干预执行计划 - - 使用hints提示基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担。但有时它也
- 在SQL查询中,关键词Like可提供模糊查询功能,它通常与通配符一起使用。1 Like条件适用数据库字段类型 &nbs