如何正确绘制多边形集合(stl 文件)?

问题描述 投票:0回答:2

我有 stl 文件和 numpy-stl 库。网格类本身具有 .x、.y、.z 属性,可以绘制

my_mesh = mesh.Mesh.from_file(file)
x = my_mesh.x
y = my_mesh.y
z = my_mesh.z
mlab.points3d(x, y, z)
mlab.show()

结果很慢而且视觉效果很差

plot

网格也有 vectors 属性,但我不知道如何使用它。 在 matplotlib 中我可以使用:

figure = plt.figure()
axes = mplot3d.Axes3D(figure)
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(my_mesh.vectors))
plt.show()

结果

img

可以使用,但速度非常慢,而且几乎无法使用。

有更好的方法来绘制这个吗?

python 3d geometry mayavi.mlab
2个回答
0
投票

Numpy-stl 库将 stl 文件加载为 numpy 数组。 “向量”属性是 Nx3x3 numpy 数组。简单地说,这个数组是形状的面的集合。所以 N 代表面的数量,3 是定义图形面的点的数量,最终尺寸代表 3d 空间中的点坐标。

在大多数绘制 3D 形状的库中,您需要定义两件事 - 点的坐标和绘制图形面的点的索引。

numpy-stl 简化了流程,因为所有点都是唯一且有序的。这意味着定义面的点的索引只是顶点数组中的索引。

还值得一提的是,您需要的不是点本身,而是分别定义 x、y、z。脸部也同样重要。

基于此,我们冷写了这篇文章。我选择plotly是因为它快速且互动

import plotly.graph_objects as go
from stl import mesh  # numpy-stl
import numpy as np

data = mesh.Mesh.from_file('fabric.stl')

points = data.vectors.reshape(-1,3)  # reshape Nx3x3 to N*3x3 to convert polygons to points
faces_index = np.arange(len(points))  # get indexes of points

fig = go.Figure(data=[
    go.Mesh3d(
        x = points[:,0],  # pass first column of points array
        y = points[:,1],  # .. second column
        z = points[:,2],  # .. third column
        # i, j and k give the vertices of triangles
        i = faces_index[0::3],  # indexes of the points. k::3 means pass every third element 
        j = faces_index[1::3],  # starting from k element
        k = faces_index[2::3],  # for example 2::3 in arange would be 2,5,8,...
        opacity = .9
    )
])

fig.show()

会显示:

来自默认 Windows stl 文件查看工具的图像:

结果看起来正确。请忽略绘图顶部的蓝点和顶部环附近的孔,它是文件伪影并以两种变体形式呈现。


0
投票

由于顶点被多次使用,因此首先找到向量数组中的唯一点可能会有所帮助。这是一个使用 pandas 删除重复项并定义三角形和 open3d 进行可视化的示例。

df.drop_duplicates
删除了重复的顶点,现在我们需要根据旧的顶点列表找到新顶点列表的索引。我用 pandas 完成了这个
merge

import open3d as o3d
import numpy as np
import pandas as pd


def extract_vertices_and_triangles(mesh_vertices):
    # Reshape the array to (n*3, 3)
    flat_vertices = mesh_vertices.reshape(-1, 3)

    # Create a DataFrame for easy manipulation
    df = pd.DataFrame(flat_vertices, columns=["x", "y", "z"])

    # Create a new DataFrame with unique vertices
    unique_df = df.drop_duplicates(subset=["x", "y", "z"]).reset_index(drop=True)

    # Create a mapping from old indices to unique indices
    merged_df = (
        df.reset_index()
        .merge(unique_df.reset_index(), on=["x", "y", "z"], how="right")
        .sort_values(by="index_x")
    )
    triangles = merged_df["index_y"].to_numpy()

    triangles = triangles.reshape(-1, 3)

    # Reshape the unique vertices to the original shape
    unique_vertices = unique_df[["x", "y", "z"]].values

    return unique_vertices, triangles

if __name__ == "__main__":
    armadillo_mesh = o3d.data.ArmadilloMesh()

    mesh = o3d.io.read_triangle_mesh(armadillo_mesh.path)
    mesh.compute_vertex_normals()
    o3d.visualization.draw_geometries([mesh])

    vertices = np.array(mesh.vertices)
    triangles = np.array(mesh.triangles)

    np_vertices = vertices[triangles]

    vert, triangle = extract_vertices_and_triangles(np_vertices)

    # Create Open3D TriangleMesh
    mesh = o3d.geometry.TriangleMesh()
    mesh.vertices = o3d.utility.Vector3dVector(vert)
    mesh.triangles = o3d.utility.Vector3iVector(triangle)
    mesh.compute_vertex_normals()

    # Visualize the extracted mesh
    o3d.visualization.draw_geometries([mesh])
© www.soinside.com 2019 - 2024. All rights reserved.