利用Python多处理库处理3D数据详解

 更新时间:2021年12月25日 21:16  点击:394 作者:一大口奶酪

今天我们将介绍处理大量数据时非常方便的工具。我不会只告诉您可能在手册中找到的一般信息,而是分享一些我发现的小技巧,例如tqdm与 multiprocessing​imap​​一起使用、并行处理档案、绘制和处理 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 语言及其广泛的库集帮助我们数据科学家解决了这些问题。

到此这篇关于利用Python多处理库处理3D数据详解的文章就介绍到这了,更多相关Python处理3D数据内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://blog.51cto.com/nailaoer/4832794

[!--infotagslink--]

相关文章

  • python opencv 画外接矩形框的完整代码

    这篇文章主要介绍了python-opencv-画外接矩形框的实例代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-04
  • Python astype(np.float)函数使用方法解析

    这篇文章主要介绍了Python astype(np.float)函数使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-08
  • 最炫Python烟花代码全解析

    2022虎年新年即将来临,小编为大家带来了一个利用Python编写的虎年烟花特效,堪称全网最绚烂,文中的示例代码简洁易懂,感兴趣的同学可以动手试一试...2022-02-14
  • python中numpy.empty()函数实例讲解

    在本篇文章里小编给大家分享的是一篇关于python中numpy.empty()函数实例讲解内容,对此有兴趣的朋友们可以学习下。...2021-02-06
  • python-for x in range的用法(注意要点、细节)

    这篇文章主要介绍了python-for x in range的用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-10
  • Python 图片转数组,二进制互转操作

    这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
  • Python中的imread()函数用法说明

    这篇文章主要介绍了Python中的imread()函数用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
  • python实现b站直播自动发送弹幕功能

    这篇文章主要介绍了python如何实现b站直播自动发送弹幕,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...2021-02-20
  • python Matplotlib基础--如何添加文本和标注

    这篇文章主要介绍了python Matplotlib基础--如何添加文本和标注,帮助大家更好的利用Matplotlib绘制图表,感兴趣的朋友可以了解下...2021-01-26
  • 解决python 使用openpyxl读写大文件的坑

    这篇文章主要介绍了解决python 使用openpyxl读写大文件的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-13
  • python 计算方位角实例(根据两点的坐标计算)

    今天小编就为大家分享一篇python 计算方位角实例(根据两点的坐标计算),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-27
  • python实现双色球随机选号

    这篇文章主要为大家详细介绍了python实现双色球随机选号,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-02
  • python中使用np.delete()的实例方法

    在本篇文章里小编给大家整理的是一篇关于python中使用np.delete()的实例方法,对此有兴趣的朋友们可以学习参考下。...2021-02-01
  • 使用Python的pencolor函数实现渐变色功能

    这篇文章主要介绍了使用Python的pencolor函数实现渐变色功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-09
  • python自动化办公操作PPT的实现

    这篇文章主要介绍了python自动化办公操作PPT的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-05
  • Python getsizeof()和getsize()区分详解

    这篇文章主要介绍了Python getsizeof()和getsize()区分详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-20
  • 解决python 两个时间戳相减出现结果错误的问题

    这篇文章主要介绍了解决python 两个时间戳相减出现结果错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-12
  • python实现学生通讯录管理系统

    这篇文章主要为大家详细介绍了python实现学生通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-25
  • PyTorch一小时掌握之迁移学习篇

    这篇文章主要介绍了PyTorch一小时掌握之迁移学习篇,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-08
  • Python绘制的爱心树与表白代码(完整代码)

    这篇文章主要介绍了Python绘制的爱心树与表白代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06