You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用plyfile库正确保存树木网格的PLY文件(Python)

问题原因与解决方案

问题根源

你把PLY文件的保存代码写在了树枝循环(for i in range(...))内部,每次处理一根树枝就会重新写入一次文件,后面的树枝数据会直接覆盖前面的,所以最终文件里只有最后一根树枝的点,不是整棵树的完整网格。

修复步骤

  1. 在树枝循环前,初始化一个空列表用来存储整棵树的所有顶点
  2. 每处理完一根树枝,就把当前树枝的顶点添加到这个列表里
  3. 等所有树枝都处理完,再一次性把所有顶点写入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:05:14