gpt4 book ai didi

python - 如何对 Poly3DCollection 进行光照和着色

转载 作者:行者123 更新时间:2023-12-02 16:54:52 28 4
gpt4 key购买 nike

我正在尝试使 3D 等高线图变暗或具有阴影,以使其“看起来”为 3D。我正在使用 matplotlib,主要是因为绘图质量很高,我更愿意继续使用它。

最终,我想要一个单一或平坦的彩色表面,在 matplotlib 风格的绘图中转换阴影。

我正在使用 scipy 进行一些插值和 skimage 以及行进立方体算法来生成轮廓。然后最后使用它来创建和着色多边形集合。

import numpy as np
from skimage import measure
from scipy.interpolate import griddata
import matplotlib as mpl
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from matplotlib.colors import LightSource

# Generate an grid to inerpolate to
X, Y, Z = np.meshgrid(0.0:1.0:50j, 0.0:1.0:50j, 0.0:1.0:50j)

# Interpolate (coor and phi are the numerical grid and scalar values)
F = griddata(coor, phi, (X, Y, Z), method='nearest')

# Make the contour, marching cubes
marchCubeSpace = 1.0 / 50.0
verts, faces, normals, values = measure.marching_cubes_lewiner(F, 0.5, spacing=(marchCubeSpace, marchCubeSpace, marchCubeSpace))

# Create Ploy3D
mesh = Poly3DCollection(verts[faces], alpha=1.0)

# An attempt to get some sort of height data.
facearray = np.array([np.array((np.sum(verts[face[:], 0]/3), np.sum(verts[face[:], 1]/3), np.sum(verts[face[:], 2]/3))) for face in faces])

# light source, ultimately I want to use not `reds` but just a red for all faces.
ls = LightSource(azdeg=45.0, altdeg=90.0)
rgb = ls.blend_hsv(rgb=ls.shade(facearray, plt.cm.Reds), intensity=ls.shade_normals(normals, fraction=0.25))
mesh.set_facecolor(rgb[:, 0])

# Plot
fig = plt.figure()
ax = fig.add_subplot(0, 0, 0, projection='3d')
ax.add_collection3d(mesh)

我希望生成这样的东西: enter image description here

最佳答案

好的,所以我有一个可以接受的解决方案。如果您需要更多帮助,请给我留言,我很乐意帮助任何人解决这个问题。请注意,下面的代码需要您的数据集中的 coorphi,因此如果您不为其提供 3D 标量场,则此代码将不会运行。

import numpy as np
from skimage import measure
from scipy.interpolate import griddata
import matplotlib as mpl
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from matplotlib.colors import LightSource

# Generate an grid to inerpolate to
X, Y, Z = np.meshgrid(0.0:1.0:50j, 0.0:1.0:50j, 0.0:1.0:50j)

# Interpolate (coor and phi are the numerical grid and scalar values)
F = griddata(coor, phi, (X, Y, Z), method='nearest')

# Make the contour, marching cubes
marchCubeSpace = 1.0 / 50.0
verts, faces, normals, values = measure.marching_cubes_lewiner(F, 0.5, spacing=(marchCubeSpace, marchCubeSpace, marchCubeSpace))

# Create Ploy3D and set up a light source
mesh = Poly3DCollection(verts[faces], alpha=1.0)
ls = LightSource(azdeg=225.0, altdeg=45.0)

# First change - normals are per vertex, so I made it per face.
normalsarray = np.array([np.array((np.sum(normals[face[:], 0]/3), np.sum(normals[face[:], 1]/3), np.sum(normals[face[:], 2]/3))/np.sqrt(np.sum(normals[face[:], 0]/3)**2 + np.sum(normals[face[:], 1]/3)**2 + np.sum(normals[face[:], 2]/3)**2)) for face in faces])

# Next this is more asthetic, but it prevents the shadows of the image being too dark. (linear interpolation to correct)
min = np.min(ls.shade_normals(normalsarray, fraction=1.0)) # min shade value
max = np.max(ls.shade_normals(normalsarray, fraction=1.0)) # max shade value
diff = max-min
newMin = 0.3
newMax = 0.95
newdiff = newMax-newMin

# Using a constant color, put in desired RGB values here.
colourRGB = np.array((255.0/255.0, 54.0/255.0, 57/255.0, 1.0))

# The correct shading for shadows are now applied. Use the face normals and light orientation to generate a shading value and apply to the RGB colors for each face.
rgbNew = np.array([colourRGB*(newMin + newdiff*((shade-min)/diff)) for shade in ls.shade_normals(normalsarray, fraction=1.0)])

# Apply color to face
mesh.set_facecolor(rgbNew)

# Plot
fig = plt.figure()
ax = fig.add_subplot(0, 0, 0, projection='3d')
ax.add_collection3d(mesh)

这就是我要找的。 (请注意,这与上图不完全相同)enter image description here

关于python - 如何对 Poly3DCollection 进行光照和着色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56864378/

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