如何使用open3d合并多组mesh并输出结果

本文介绍了如何使用Python结合open3d、plyfile库,将多个mesh合并成一个带有纹理的ply文件。通过理解ply文件格式,处理无纹理mesh的属性填充,实现了合并与纹理信息的统一存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关注公众号,发现CV技术之美

最近在学习open3d的相关应用,然后遇到了一个很有趣的问题。给定多个mesh,我们可能会需要把他们全部合并到一个文件并使用。但是这并不好实现,因为open3d自己不支持这样的操作。相比之下,其他一些集成度非常高的软件,是可以实现这样的操作的,例如meshlab通过交互栏中的“flatten visible layer”指令来实现。

唯一的缺点是,你每次都需要手动操作才行,这对于需要高度自动化的使用场景,就不是很合适了。因此,如何可以实现一个自动化的脚本,支持直接合并多个可染色的mesh,并输出带有纹理的最终结果,是一个非常重要的功能。遗憾的是度娘和谷歌目前没有相关的教程。因此本文带大家了解一下,如何重头写一个ply文件并且合并输出所有需要合并的m

esh。

▍如何存储一个带纹理的obj格式的mesh

这里我们首先介绍一下,怎么去存储一个mesh。为了方便,我们使用这篇文章中的代码 (https://zhuanlan.zhihu.com/p/569974846),先自己生成若干个mesh(有些带有纹理,有些没有),然后进行存储。单模型存储在open3d中是很简单的,open3d提供了一个接口来直接存储对应的mesh,接口是o3d.io.write_triangle_mesh。

但是要注意的是,如果要存纹理信息,这个命令需要使用obj格式,因为另外一种常见的ply格式,则无法存储纹理信息。因此,作为合并的第一步,我们手动输出全部mesh为obj格式以支持纹理信息,并且分开存储。

以下代码把场景内的全部mesh文件输出为obj格式。

if not os.path.exists("save_mesh"):


    os.makedirs("save_mesh", exist_ok=False)


o3d.io.write_triangle_mesh("save_mesh/obj_back.obj", back_obj)


o3d.io.write_triangle_mesh("save_mesh/obj_left.obj", left_obj)


o3d.io.write_triangle_mesh("save_mesh/obj_front.obj", front_obj)


o3d.io.write_triangle_mesh("save_mesh/obj_right.obj", right_obj)


o3d.io.write_triangle_mesh("save_mesh/box_back.obj", back_box)


o3d.io.write_triangle_mesh("save_mesh/box_left.obj", left_box)


o3d.io.write_triangle_mesh("save_mesh/box_front.obj", front_box)


o3d.io.write_triangle_mesh("save_mesh/box_right.obj", right_box)

▍如何存储一个带纹理的ply格式的mesh

存储为obj格式之后,我们通过meshlab自带的命令行格式,把所有带有纹理的mesh全部转化为ply文件。这里要注意的是,如果你的mesh模型本身是不带有色彩的,那么这一步可以直接加载mesh模型然后转为ply文件,上一步输出为obj格式则是可以跳过的。

下面我们依次加载obj文件并转存为ply文件。代码如下:

if not os.path.exists("save_mesh_ply"):


    os.makedirs("save_mesh_ply", exist_ok=False)


for obj in ["save_mesh/obj_back.obj", "save_mesh/obj_left.obj", "save_mesh/obj_front.obj",


            "save_mesh/obj_right.obj", "save_mesh/box_back.obj", "save_mesh/box_left.obj",


            "save_mesh/box_front.obj", “save_mesh/box_right.obj"]: #简单粗暴的列出来所有mesh


    ms = pymeshlab.MeshSet()


    ms.load_new_mesh(obj)


    ms.save_current_mesh(os.path.join(obj.split("/")[0]+"_ply", obj.split("/")[1].replace("obj", “ply")))

最终存储的mesh,重新使用meshlab可视化结果如下:

f79ccae0db69f1ada20e5170141f94b1.png

注意右侧红框,此时存在8个不同的层(layers)。我们的最终目的是把他们全部合并为一层并且统一存储。

▍ply文件格式介绍

下面我们来介绍一下ply文件格式的组成。ply文件有两个重要组成部分。第一组是头部(header),之后是对应于头部定义的数值组。

首先是头部(header)的定义,对于无纹理mesh文件来说,直接套用ply头部固定模板即可。

ply


format ascii 1.0


comment VCGLIB generated


element vertex vertex_count


property float x


property float y


property float z


property uchar red


property uchar green


property uchar blue


property uchar alpha


element face face_count


property list uchar int vertex_indices


end_header

关于无纹理文件的头部的定义,大部分情况下可以直接照抄,无需修改,除了点、面对应的数量(红色变量对应位置替换即可)。这里进一步解释一下关键字:header中的comment是注释的意思,property详细定义了所需要的数据结构。最后使用end_header标注定义结束。另外ply文件格式的编码,我强烈推荐使用ascii格式,否则使用文本编辑工具打开是乱码,不利于分析问题。

头部的定义具体包含了顶点与面的定义。对于不带纹理的ply文件,其对应顶点的定义需要如下关键参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值