我有 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()
结果很慢而且视觉效果很差
网格也有 vectors 属性,但我不知道如何使用它。 在 matplotlib 中我可以使用:
figure = plt.figure()
axes = mplot3d.Axes3D(figure)
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(my_mesh.vectors))
plt.show()
结果
可以使用,但速度非常慢,而且几乎无法使用。
有更好的方法来绘制这个吗?
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()
结果看起来正确。请忽略绘图顶部的蓝点和顶部环附近的孔,它是文件伪影并以两种变体形式呈现。
由于顶点被多次使用,因此首先找到向量数组中的唯一点可能会有所帮助。这是一个使用 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])