处理3D数据使用Python多重库
今天我们将介绍一些非常方便的大数据量的工具。我不会告诉你只可能在手册中找到的一般信息,但大家分享一些小技巧,我发现,比如使用 TQDM.
多处理 IMAP.
与并行档案,绘图及处理3D数据,以及如何寻找对象网格内的类似物体,如果你有一个点云工作。
那么我们为什么还要求助于并行计算?现在,如果您有任何你可能会面临与“大数据”问题数据的工作。每当我们有不适合我们需要一块来处理它一块RAM中的数据。幸运的是,现代编程语言使我们能够在多核处理器的完美产卵多个进程(甚至线程)的工作。 (NB.:这并不意味着单核处理器无法处理的多处理。 这是 关于该主题的堆栈溢出线程。)
今天我们就来试试我们的手在计算网格和点云之间的距离的频繁出现的3D计算机视觉任务。你可能会面临这样的问题,例如,当你需要找到一个定义了相同的3D对象为给定的点云的所有可用网格内的网格。
我们的数据包括 .obj.
存储在文件中 .7z压缩
存档,这在存储效率方面是很大的。但是,当我们需要访问它的确切的部分,我们应该努力。在这里,我定义类,它包装了7-zip存档,并提供对基础数据的接口。
Python
= LEN(self.names_list):
提高终止
name = self.names_list [self.cur_id]
self.cur_id + = 1
返回self.get(名称)”数据琅= “文本/ X-蟒”>
从IO进口BytesIO
进口py7zlib
类MeshesArchive(对象):
高清__init __(自我,ARCHIVE_PATH):
FP =开放(ARCHIVE_PATH, 'RB')
self.archive = py7zlib.Archive7z(FP)
self.archive_path = ARCHIVE_PATH
self.names_list = self.archive.getnames()
self.cur_id = 0
def __len __(self):
返回LEN(self.names_list)
DEF得到(个体经营,名):
BYTES_IO = BYTESIO(self.archive.getmember(name).read())
返回bytes_io.
def __getitem __(self,Idx):
返回self.get(self.names [idx])
def __iter __(self):
回归自我
def __next __(self):
如果self.cur_id> = len(self.names_list):
提高终止
name = self.names_list [self.cur_id]
self.cur_id + = 1
返回self.get(姓名)
这个课程几乎没有依赖 py7zlib.
允许我们每次调用时都可以解压缩数据的包 得到
方法并向我们提供存档内部的文件数。我们也定义了 __Ters__
这将有助于我们开始多处理 地图
在该对象上,如迭代。
正如您所知,可以创建一个Python类,其中一个人可以实例化可迭代对象。这些类应符合以下条件:覆盖 __GETITEM__
返回 自己
和 __下一个__
返回以下元素。我们肯定遵循这条规则。
上述定义为我们提供了迭代档案的可能性 但 它是否允许我们这样做 随机访问内容并行还这是一个有趣的问题,我没有在线找到答案,但我们可以研究源代码 py7zlib.
并试图由自己回答。
在这里,我提供了减少的代码片段 幽门:
Python
Class Archive7z(基础):
def __init __(self,file,password = none):
#...
self.files = {}
#...
对于文件中的信息.FILES:
#创建一个认识磁盘位置的archivefile实例
file = archivefile(信息,pos,src_pos,文件夹,self,maxsize = maxsize)
#...
self.files.append(文件)
#...
self.files_map.update([self.files的x的[(x.filename,x)])
#方法从files_map字典返回archivefile
def getmember(self,name):
如果是isinstance(名称,(int,long)):
尝试:
返回self.files [name]
除IndexError之外:
返回None
返回self.files_map.get(name,none)
Class Archive7z(基础):
def读(self):
#...
对于级别,枚举中的编码器(self._folder.coders):
#...
#获取解码器并解码底层数据
数据= getattr(self,解码器)(编码器,数据,级别,num_coders)
返回数据
在代码中,您可以看到在从存档中读取下一个对象期间调用的方法。我相信从上面可以清楚地清楚,只要同时读取多次,就没有归档的原因被阻止。
接下来,让我们快速介绍网格和点云的内容。
第一,网格是一组 顶点那 边缘, 和 面孔。 顶点由 (x,y,z) 在空间中坐标并分配唯一的数字。边缘和面是相应的点对和三元组的组,并定义了提到的独特点ID。通常,当我们谈论“网格”时,我们的意思是“三角网”,即由三角形组成的表面。使用Python的网格工作得更容易得多 Trimesh.
图书馆。例如,它提供了加载的接口 .obj.
文件中的文件。显示和交互与3D对象 jupyter笔记本
一个人可以使用 K3D.
图书馆。
所以,通过以下代码片段我回答问题:“你怎么绘制一个Trimesh.
对象 詹耶特
和 K3D.
?“
Python
导入TrimeSh.
进口K3D.
与打开(“./ data / meshes / stanford-bunny.obj”)作为f:
bunny_mesh = trimesh.load(f,'obj')
plot = k3d.plot()
网格= k3d.mesh(bunny_mesh.vertices,bunny_mesh.faces)
plot + =网格
plot.display()
斯坦福兔兔网显示K3D
其次,点云是表示空间中对象的3D点阵列。许多3D扫描仪产生点云作为扫描对象的表示。出于演示目的,我们可以阅读相同的网格并将其顶点显示为点云。
导入TrimeSh.
进口K3D.
与打开(“./ data / meshes / stanford-bunny.obj”)作为f:
bunny_mesh = trimesh.load(f,'obj')
plot = k3d.plot()
cloud = k3d.points(bunny_mesh.vertices,point_size = 0.0001,shader =“flat”)
plot + =云
plot.display()
K3D绘制的点云
如上所述,3D扫描仪向我们提供点云。让我们假设我们有一个网格数据库,我们希望在我们的数据库中找到与扫描对象,AKA点云对齐的网格。为了解决这个问题,我们可以建议一个天真的方法。我们将搜索给定点云的点之间的最大距离和我们存档中的每个网格。如果这样的距离会减少 1E-4
对于某些网格,我们将考虑此网格与点云对齐。
最后, 我们已经到了多处理部分。记住我们的存档有大量文件可能不适合在一起,因为我们更愿意并行处理它们。要实现我们将使用多处理 水池
,它处理多个用户定义函数的多个呼叫 地图
或者 IMAP / IMAP_UNORDERED.
方法。和...之间的不同 地图
和 IMAP.
影响我们的是 地图
在将其发送到工作进程之前将迭代转换为列表。如果存档太大而无法在RAM中写入,它不应该卸载到Python列表。换句话说,两者的执行速度都是相似的。
[加载网格:Pool.map W / O Manager] 4个进程的池经过时间:37.213207403818764秒 [加载网格:pool.imap_unorded w / o Manager]池4个进程经过时间:37.219303369522095秒
在上面,您可以看到从符合内存的网格存档的简单读取的结果。
进一步移动 IMAP.
:让我们讨论如何完成我们找到靠近点云的网格的目标。这里是 数据。我们有5种不同的网格来自斯坦福车型。通过向斯坦福兔兔网的顶点添加噪音,我们将模拟3D扫描。
Python
将numpy导入np
来自numpy.random导入default_rng
def normalize_pc(point):
点=点 - 点..ean(Axis = 0)[无,:]
dists = np.linalg.norm(点,轴= 1)
scaled_points = points / dists.max()
返回scaled_points.
def load_bunny_pc(bunny_path):
std = 1e-3
用open(bunny_path)作为f:
bunny_mesh = load_mesh(f)
#标准化点云
scaled_bunny = normalize_pc(bunny_mesh.vertices)
#为点云添加一些噪音
rng = default_rng()
噪声= rn正常(0.0,std,scaled_bunny.shape)
迷恋_bunny = scaled_bunny +噪音
返回distorted_bunny.
当然,我们之前将点云和网格顶点正常化,以便在3D立方体中缩放它们。
计算点云和我们将使用的网格之间的距离 IgL.
。完成我们需要编写一个将调用每个进程及其依赖项的函数。让我们与以下代码段一起。
Python
导入itertools.
进口时间
将numpy导入np
来自numpy.random导入default_rng
导入TrimeSh.
导入IGL.
来自TQDM Import TQDM
来自多处理进口池
def load_mesh(obj_file):
网格= trimeSh.load(obj_file,'obj')
返回网格
def get_max_dist(base_mesh,point_cloud):
Quitient_sq,mesh_face_indexes,_ = ingl.point_mesh_squared_distance(
point_cloud,
base_mesh.vertices,
base_mesh.faces.faces.
的)
return vieety_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(网格,point_cloud)
return max_dist.
def read_meshes_get_distans_pool_imap(archive_path,point_cloud,num_proc,num_ interations):
#在池中进行网格处理
Elapsed_time = []
对于范围(NUM_ITINATIONS):
archive = meshesarchive(archive_path)
池=池(num_proc)
start = time.time()
结果=列表(tqdm(pool.imap(
load_mesh_get_distance,
zip(存档,itertools.repeat(point_cloud)),
),总= Len(档案)))
pool.close()
pool.join()
结束= time.time()
Elapsed_time.append(结束 - 开始)
打印(f'[进程网格:pool.imap] {num_proc}进程的池经过时间:{np.array(Elapsed_time).mean()} sec')
对于名称,zip中的dist(archive.names_list,结果):
打印(f“{name} {dist}”)
返回结果
如果__name__ ==“__main__”:
bunny_path =“./data/meshes/stanford-bunny.obj”
archive_path =“./data/meshes.7z”
num_proc = 4.
num_ istations = 3
point_cloud = load_bunny_pc(bunny_path)
read_meshes_get_distans_pool_no_manager_imap(archive_path,point_cloud,num_proc,num_ entations)
这里 read_meshes_get_distans_pool_imap.
是以下完成的中心功能:
网格化
和multiprocessing.pool.
初始化TQDM.
应用于观看池进度和整个池的分析手动完成- 执行的输出
注意我们如何传递参数 IMAP.
从中创建一个新的解释 档案
和 point_cloud.
使用 zip(存档,itertools.repeat(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] [过程网格:pool.imap w / o Manager] 4个流程池经过时间:1.0080536206563313秒 Armadillo.obj 0.16176825266293382 beast.obj 0.28608649819198073. 牛。波夫0.41653845909820164 Spot.obj 0.22739556571296735 Stanford-Bunny.obj 2.3699851136074263e-05
我们可以眼球,斯坦福兔子是最接近给定点云的网格。还可以看出,我们不使用大量数据,但是我们已经表明,即使我们在存档内部有广泛的网格,也可以使用此解决方案。
多处理允许数据科学家不仅在3D计算机视觉中实现了良好的性能,也可以在机器学习的其他领域中实现良好的性能。了解并行执行比循环中的执行快得多。差异变得显着,特别是当正确写入算法时。大量数据揭示了在没有如何使用有限资源的创造性方法的情况下没有解决的问题。幸运的是,Python语言及其广泛的库帮助我们数据科学家解决了这些问题。
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/160404.html