如何用plyfile库正确保存树木网格的PLY文件(Python)
问题原因与解决方案
问题根源
你把PLY文件的保存代码写在了树枝循环(for i in range(...))内部,每次处理一根树枝就会重新写入一次文件,后面的树枝数据会直接覆盖前面的,所以最终文件里只有最后一根树枝的点,不是整棵树的完整网格。
修复步骤
- 在树枝循环前,初始化一个空列表用来存储整棵树的所有顶点
- 每处理完一根树枝,就把当前树枝的顶点添加到这个列表里
- 等所有树枝都处理完,再一次性把所有顶点写入PLY文件
修改后的完整代码
from plyfile import PlyData, PlyElement import numpy as np from scipy.linalg import norm import matplotlib.pyplot as plt for tid,tree in enumerate(forest): tree_arr = np.array(tree).reshape((-1,6)) vertices = tree_arr[:,0:3].astype(float) radius = tree_arr[:,3].astype(float) parent_id = tree_arr[:,4].astype(int) section_id = tree_arr[:,5].astype(int) if np.max(vertices[:,2]) > 30: # 初始化空列表,存储整棵树的所有顶点 all_vertices = [] fig = plt.figure(figsize=[16,16]) ax = fig.add_subplot(111, projection='3d') ax.set_box_aspect([np.ptp(vertices[:,0]), np.ptp(vertices[:,1]), np.ptp(vertices[:,2])]) for i in range(1,parent_id.shape[0],1): j = parent_id[i] p0 = vertices[j] p1 = vertices[i] v = p1 - p0 mag = norm(v) v = v / mag not_v = np.array([1, 0, 0]) if (v == not_v).all(): not_v = np.array([0, 1, 0]) n1 = np.cross(v, not_v) n1 /= norm(n1) n2 = np.cross(v, n1) r0 = radius[j] r1 = radius[i] rv = np.array([r0, r1])[np.newaxis] t = np.linspace(0, mag, 2) theta = np.linspace(0, 2 * np.pi, 15) t, theta = np.meshgrid(t, theta) x,y,z = [p0[k] + v[k] * t + rv * np.sin(theta) * n1[k] + rv * np.cos(theta) * n2[k] for k in range(3)] # 把当前树枝的顶点添加到总列表 x_flat = x.flatten() y_flat = y.flatten() z_flat = z.flatten() branch_vertices = list(zip(x_flat, y_flat, z_flat)) all_vertices.extend(branch_vertices) # 所有树枝处理完后,统一保存PLY文件 if all_vertices: dtype=[('x', 'f4'), ('y', 'f4'),('z', 'f4')] M = np.array(all_vertices, dtype) el = PlyElement.describe(M, 'vertex') # 用树的索引命名避免文件覆盖,也可替换为树的唯一标识 name = f'modeled_tree_{tid}.ply' PlyData([el]).write(name)
额外提示
- 原代码里的文件名
f'modeled_tree{tree[5]}.ply'可能存在重复覆盖风险,建议用循环的tid(树的索引)或者整棵树的唯一标识来命名。 - 当前代码保存的是点云格式,如果需要保存带面的网格,还需生成三角形/四边形面元素并添加到
PlyData中。
内容的提问来源于stack exchange,提问作者Sher
相关产品推荐
相关产品推荐

