gpt4 book ai didi

python - 如何使用 PyVista 从列表/数组创建自定义 3D 对象?

转载 作者:行者123 更新时间:2023-12-01 00:21:08 26 4
gpt4 key购买 nike

我想创建由 2D 多边形组成的 3D 对象,每个多边形都有一个由单个 jpeg 图像组成的纹理。我有多边形的 X、Y 和 Z 值的 3D 坐标以及 [0, 1] 区间内的纹理坐标。我可以使用 Poly3DCollection 在 matplotlib 中绘制 3D 对象,但正如我到目前为止所读到的,matplotlib 不支持多边形的纹理映射。我找到了PyVista ,这似乎是 texture mapping 的不错选择,但我不明白如何从我的数据创建与 PyVista 兼容的数据集。这是我当前正在工作的 matplotlib-example:

from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt

# six polygons consisting of points with X, Y, and Z coordinates
polygon_a = [
[
(371982, 5812893, 47),
(371987, 5812889, 47),
(371993, 5812896, 47),
(371988, 5812900, 47),
(371982, 5812893, 47),
]
]
polygon_b = [
[
(371987, 5812889, 44),
(371987, 5812889, 47),
(371982, 5812893, 47),
(371982, 5812893, 44),
(371987, 5812889, 44),
]
]
polygon_c = [
[
(371993, 5812896, 44),
(371993, 5812896, 47),
(371987, 5812889, 47),
(371987, 5812889, 44),
(371993, 5812896, 44),
]
]
polygon_d = [
[
(371982, 5812893, 44),
(371982, 5812893, 47),
(371988, 5812900, 47),
(371988, 5812900, 44),
(371982, 5812893, 44),
]
]
polygon_e = [
[
(371988, 5812900, 44),
(371988, 5812900, 47),
(371993, 5812896, 47),
(371993, 5812896, 44),
(371988, 5812900, 44),
]
]
polygon_f = [
[
(371987, 5812889, 44),
(371982, 5812893, 44),
(371988, 5812900, 44),
(371993, 5812896, 44),
(371987, 5812889, 44),
]
]

# texture coordinates of interval [0, 1]

texture_coords_a = [
0.993515,
0.590665,
0.583403,
0.995886,
0.001318,
0.409513,
0.411194,
0.00281,
0.993515,
0.590665,
]
texture_coords_b = [
0.814495,
0.004965,
0.986562,
0.175202,
0.172649,
0.994582,
0.004011,
0.820917,
0.814495,
0.004965,
]
texture_coords_c = [
0.992976,
0.869131,
0.867654,
0.99699,
0.009377,
0.134356,
0.138307,
0.010153,
0.992976,
0.869131,
]
texture_coords_d = [
0.007693,
0.148416,
0.15451,
0.00767,
0.994519,
0.86112,
0.844256,
0.998197,
0.007693,
0.148416,
]
texture_coords_e = [
0.997322,
0.660826,
0.89938,
0.990736,
0.006374,
0.337104,
0.106732,
0.00748,
0.997322,
0.660826,
]

# textures for some of the polygons as .jpg-files

img_a = "tex_2962910.jpg"
img_b = "tex_2962971.jpg"
img_c = "tex_2962990.jpg"
img_d = "tex_2962933.jpg"
img_e = "tex_2962915.jpg"

polygons = [polygon_a, polygon_b, polygon_c, polygon_d, polygon_e, polygon_f]

# 3D plot of the polygons using matplotlib, but without textures
fig = plt.figure()
ax = Axes3D(fig)
for polygon in polygons:
ax.add_collection3d(Poly3DCollection(polygon, alpha=0.5))

ax.set_xlim3d(371980, 371995)
ax.set_ylim3d(5812889, 5812902)
ax.set_zlim3d(44, 48)

plt.show()

如果有任何正确方向的帮助,我将不胜感激!

最佳答案

对于任何有类似问题的人:我找到了两个易于使用的包,并提供纹理映射到 numpy 多边形所需的功能。第一个是PyVista,工作代码如下:

import pyvista as pv
import numpy as np
from PIL import Image

# six polygons consisting of points with X, Y, and Z coordinates
polygon_a = [
(371982, 5812893, 47),
(371987, 5812889, 47),
(371993, 5812896, 47),
(371988, 5812900, 47),
(371982, 5812893, 47),
]
polygon_b = [
(371987, 5812889, 44),
(371987, 5812889, 47),
(371982, 5812893, 47),
(371982, 5812893, 44),
(371987, 5812889, 44),
]
polygon_c = [
(371993, 5812896, 44),
(371993, 5812896, 47),
(371987, 5812889, 47),
(371987, 5812889, 44),
(371993, 5812896, 44),
]
polygon_d = [
(371982, 5812893, 44),
(371982, 5812893, 47),
(371988, 5812900, 47),
(371988, 5812900, 44),
(371982, 5812893, 44),
]
polygon_e = [
(371988, 5812900, 44),
(371988, 5812900, 47),
(371993, 5812896, 47),
(371993, 5812896, 44),
(371988, 5812900, 44),
]


texture_coords_a = np.array(
[
[0.993515, 0.590665],
[0.583403, 0.995886],
[0.001318, 0.409513],
[0.411194, 0.00281],
[0.993515, 0.590665],
]
)

texture_coords_b = np.array(
[
[0.814495, 0.004965],
[0.986562, 0.175202],
[0.172649, 0.994582],
[0.004011, 0.820917],
[0.814495, 0.004965],
]
)

texture_coords_c = np.array(
[
[0.992976, 0.869131],
[0.867654, 0.99699],
[0.009377, 0.134356],
[0.138307, 0.010153],
[0.992976, 0.869131],
]
)

texture_coords_d = np.array(
[
[0.007693, 0.148416],
[0.15451, 0.00767],
[0.994519, 0.86112],
[0.844256, 0.998197],
[0.007693, 0.148416],
]
)
texture_coords_e = np.array(
[
[0.997322, 0.660826],
[0.89938, 0.990736],
[0.006374, 0.337104],
[0.106732, 0.00748],
[0.997322, 0.660826],
]
)


# define polygon faces for each polygon
faces_a = np.hstack([[4, 0, 1, 2, 3]])
faces_b = np.hstack([[4, 0, 1, 2, 3]])
faces_c = np.hstack([[4, 0, 1, 2, 3]])
faces_d = np.hstack([[4, 0, 1, 2, 3]])
faces_e = np.hstack([[4, 0, 1, 2, 3]])

# textures for some of the polygons as .jpg-files

img_a = "tex_2962910.jpg"
img_b = "tex_2962971.jpg"
img_c = "tex_2962990.jpg"
img_d = "tex_2962933.jpg"
img_e = "tex_2962915.jpg"

polygons = [polygon_a, polygon_b, polygon_c, polygon_d, polygon_e]
faces = [faces_a, faces_b, faces_c, faces_d, faces_e]
textures = [img_a, img_b, img_c, img_d, img_e]
texture_coords = [
texture_coords_a,
texture_coords_b,
texture_coords_c,
texture_coords_d,
texture_coords_e,
]


def create_meshes_with_textures(polygon, face, texture, texture_coords):
""" Opens each image with PIL, converts them to np.arrays and converts those to
VTK textures. Each textur gets mapped to a polygon according to the coordinates.
"""
img = Image.open(texture)
img.load()
img = np.asarray(img, dtype=np.uint8)
img = pv.numpy_to_texture(img)

polygon = np.array(polygon)
mesh = pv.PolyData(polygon, face)
mesh.t_coords = texture_coords
return mesh, img


# create Plotter object from PyVista
p = pv.Plotter()

for polygon, face, texture, texture_coords in zip(
polygons, faces, textures, texture_coords
):

# map the textures to the polygons
mesh, img = create_meshes_with_textures(polygon, face, texture, texture_coords)
# add the resulting meshes to the Plotter object
p.add_mesh(mesh, texture=img)

p.show()

第二个选项是使用 vtkplotter ,感谢通过这个实现该功能的开发者GitHub Issue 。总的来说,这两个包都可以很好地解决这个问题,vtkplotter 需要更少的纹理数据转换步骤。

from vtkplotter import *
import numpy as np

# six polygons consisting of points with X, Y, and Z coordinates
polygon_a = [
[
(371982, 5812893, 47),
(371987, 5812889, 47),
(371993, 5812896, 47),
(371988, 5812900, 47),
(371982, 5812893, 47),
],
[[0, 1, 2, 3, 4]],
]
polygon_b = [
[
(371987, 5812889, 44),
(371987, 5812889, 47),
(371982, 5812893, 47),
(371982, 5812893, 44),
(371987, 5812889, 44),
],
[[0, 1, 2, 3, 4]],
]

polygon_c = [
[
(371993, 5812896, 44),
(371993, 5812896, 47),
(371987, 5812889, 47),
(371987, 5812889, 44),
(371993, 5812896, 44),
],
[[0, 1, 2, 3, 4]],
]
polygon_d = [
[
(371982, 5812893, 44),
(371982, 5812893, 47),
(371988, 5812900, 47),
(371988, 5812900, 44),
(371982, 5812893, 44),
],
[[0, 1, 2, 3, 4]],
]
polygon_e = [
[
(371988, 5812900, 44),
(371988, 5812900, 47),
(371993, 5812896, 47),
(371993, 5812896, 44),
(371988, 5812900, 44),
],
[[0, 1, 2, 3, 4]],
]
polygon_f = [
[
(371987, 5812889, 44),
(371982, 5812893, 44),
(371988, 5812900, 44),
(371993, 5812896, 44),
(371987, 5812889, 44),
],
[[0, 1, 2, 3, 4]],
]

# texture coordinates of X, Y with interval [0, 1]
texture_coords_a = [
0.993515,
0.590665,
0.583403,
0.995886,
0.001318,
0.409513,
0.411194,
0.00281,
0.993515,
0.590665,
]
texture_coords_b = [
0.814495,
0.004965,
0.986562,
0.175202,
0.172649,
0.994582,
0.004011,
0.820917,
0.814495,
0.004965,
]
texture_coords_c = [
0.992976,
0.869131,
0.867654,
0.99699,
0.009377,
0.134356,
0.138307,
0.010153,
0.992976,
0.869131,
]
texture_coords_d = [
0.007693,
0.148416,
0.15451,
0.00767,
0.994519,
0.86112,
0.844256,
0.998197,
0.007693,
0.148416,
]
texture_coords_e = [
0.997322,
0.660826,
0.89938,
0.990736,
0.006374,
0.337104,
0.106732,
0.00748,
0.997322,
0.660826,
]

texture_coords = [
texture_coords_a,
texture_coords_b,
texture_coords_c,
texture_coords_d,
texture_coords_e,
]

# textures for some of the polygons as .jpg-files
img_a = "tex_2962910"
img_b = "tex_2962971"
img_c = "tex_2962990"
img_d = "tex_2962933"
img_e = "tex_2962915"

polygons = [polygon_a, polygon_b, polygon_c, polygon_d, polygon_e]
textures = [img_a, img_b, img_c, img_d, img_e]

meshes = []

# loop through all polygons and their textures
for polygon, texture, texture_coord in zip(polygons, textures, texture_coords):
# reformat texture coordinates as [(u,v), ...]
texture_coord = np.split(np.array(texture_coord), 5)
# create an Actor object for each polygon
polygon = Actor(polygon)
# map the textur with the according coordinates
polygon.texture(texture, tcoords=texture_coord)
meshes.append(polygon)

# assemble the objects
polygons = Assembly(meshes)

show(polygons, viewup="z", axes=8)

关于python - 如何使用 PyVista 从列表/数组创建自定义 3D 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58963924/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com