利用Python多处理库处理3D数据详解_第1页
利用Python多处理库处理3D数据详解_第2页
利用Python多处理库处理3D数据详解_第3页
利用Python多处理库处理3D数据详解_第4页
利用Python多处理库处理3D数据详解_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第利用Python多处理库处理3D数据详解今天我们将介绍处理大量数据时非常方便的工具。我不会只告诉您可能在手册中找到的一般信息,而是分享一些我发现的小技巧,例如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的方法

defgetmember(self,name):

ifisinstance(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的方法

defgetmember(self,name):

ifisinstance(name,(int,long)):

回归自我。文件[名称]

除了IndexError:

回归自我。文件映射。获取(名称,无)

类Archive7z(基础):

定义读取(自我):

#...

对于水平,编码器在枚举(自我。_folder。编码器):

#...

#获取解码器并解码底层数据

data=getattr(self,decoder)(coder,data,level,num_coders)

返回数据

在代码中,您可以看到在从存档中读取下一个对象期间调用的方法。我相信从上面可以清楚地看出,只要同时多次读取存档,就没有理由阻止存档。

接下来,我们快速介绍一下什么是网格和点云。

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

所以,用下面的代码片段我回答这个问题:“你怎么绘制​​trimesh​​​的对象​​jupyter​​​有​​k3d​​?”

导入k3d

使用open(w./data/meshes/stanford-bunny,obj")作为f:bunny_mesh=网眼。力口载(f,'obj')

情节=k3d。情节()

网格=k3d。网格(bunny_mesh.verticesbunny_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​​某些网格的距离更小,我们将认为该网格与点云对齐。

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

[加载网格:pool.mapw/omanager]4个进程的池经过时间:37.213207403818764秒

[加载网格:pool.imap_unorderedw/omanager]4个进程的池经过时间:37.219303369522095秒

上面您可以看到从适合内存的网格档案中简单读取的结果。

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

将numpy导入为np

Anumpy。随机导入defaulting

defnormalize_pc(点):

点额=点额-点额。平均值(轴=0)[无,:]

分布=np。linalg范数(点,轴=1)scaled_points=点/dists中。最大值。返回scaled_points

defload_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)畸变兔子=缩放兔子+噪声

返回distorted_bunny

当然,我们之前在下面将点云和网格顶点归一化,以在3D立方体中缩放它们。

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

导入迭代工具

将numpy导入为np

nwnpyo随机导入defaultrng

面以1口口如进进从

A多处理导入池

de£load_mesh(obj_file):

目二trimesh。力口载(obj_file,'obj')

返回网格

defget_max__dist(basjmesh,point_cloud):

distance_sq,mesh_face__indexes,_=igl。point_mesh_squared_distance(

basjmesho顶点,

basjmesho面孔

返回distancjsq。最大值0

def1oad_mesh__get_distance(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__distances_pool__imap(archive_path,point_cloud,nwn_proc,nwn_iterations):

#在疝中进行向格“理

elapsed__time=[]

为一在范围(nujn-iterations):

归档二MeshesArchive(ARCHIVE-PATH)

池二池(nwn_proc)

开始=时间。时间0

导致=名单(tqdm(池。IMAP(

1oad_mesh__get_distance,

zip(存档,itertoolso重复(point_cloud)),

),总计=len辱档)))

池。关闭0

池。加入o

结束=时间。时间0

elapsedtimeo追加(结束一开始)

print(F[Processmeshes:pool,imap]{num_proc}个进程的池经过的时间:{np.array(elapsed_time).mean()}sec)

对于name,distinzip(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__distances_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:0000:00,5.14it/s]

100%|#########

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论