我正在尝试通过RGB堆栈制作由一系列2D平面组成的3D绘图,如下所示:
我知道可以使用mpl_toolkits.mplot3d
通过将每个像素的x,y,z坐标和RGB(A)颜色传递给plot_surface
来执行此操作:
import numpy as np
from matplotlib import pyplot as pp
from mpl_toolkits.mplot3d.axes3d import Axes3D
def plot_stack_slices(rgbstack, scale=(1., 1., 1.), z_interval=10.):
fig, ax = pp.subplots(1,1,subplot_kw={'projection':'3d'})
ax.invert_zaxis()
ax.hold(True)
sx, sy, sz = scale
nz, ny, nx, nc = rgbstack.shape
stack_xyz = np.mgrid[:nx*sx:nx*1j, :ny*sy:ny*1j, :nz*sz:nz*1j]
slices = rgbstack[::-z_interval]
slice_xyz = np.rollaxis(stack_xyz, 3, 0)[::-z_interval]
surflist = []
for (img,xyz) in zip(slices, slice_xyz):
x, y, z = xyz
s = ax.plot_surface(x, y, z, facecolors=img**0.75,
rstride=50, cstride=50)
surflist.append(s)
return fig, ax, surflist
不幸的是,如果我设置rstride=1, cstride=1
以便以全分辨率显示纹理,这会变得非常慢。
我也知道Mayavi可以轻松处理以全分辨率显示多个2D纹理:
from mayavi import mlab
def plot_stack_slices2(stack, scale=(1., 1., 20.), z_interval=10.):
mfig = mlab.figure(bgcolor=(1,)*3)
sx, sy, sz = scale
nz, ny, nx = stack.shape
slices = stack[::-z_interval]
slice_z = np.linspace(0,nz*sz,nz)[::z_interval]
surflist = []
for (img,z) in zip(slices, slice_z):
im = mlab.imshow(img.T, colormap='gray', figure=mfig)
im.actor.scale = [sx,sy,sz]
im.actor.position = [0, 0, z]
surflist.append(z)
return fig, surflist
然而,现在的问题是似乎没有任何方法可以使用Mayavi显示真彩色RGB纹理 - according to the docs我只能指定单个(R, G, B)
元组或前一个-defined colourmap。
是否有人知道在3D绘图中显示真彩色2D RGB纹理的更好方法?
如果有足够的时间我可以弄清楚如何在Vtk或甚至纯OpenGL中做到这一点,但是我真的希望有现有的库来完成这项工作。
答案 0 :(得分:5)
非常感谢aestrivex使用Mayavi / VTK提供工作解决方案 - 这是我将来可能需要做的更有用的信息。
最后,我实际上选择了cgohlke使用visvis的建议,结果实现起来要简单得多:
import visvis as vv
vv.use('wx')
import numpy as np
from matplotlib.image import imread
from matplotlib.cbook import get_sample_data
imgdata = imread(get_sample_data('lena.png'))
nr, nc = imgdata.shape[:2]
x,y = np.mgrid[:nr, :nc]
z = np.ones((nr, nc))
for ii in xrange(5):
vv.functions.surf(x, y, z*ii*100, imgdata, aa=3)
答案 1 :(得分:4)
我不了解其他图书馆 - volshow看起来整洁但我没有测试过 - 但你可以在vtk中做到这一点。
我一直在mayavi(参见How to directly set RGB/RGBA colors in mayavi)一直在努力这样做但是对于某些图像源mayavi以一种根本不是为处理这个问题的方式构建vtk管道。我从mlab.imshow开始将2D vtk.ImageData转换为真彩色的努力在每一步都遇到了阻力,但我设法了。
首先,我是如何使用mlab在mayavi中设法完成的。即使对我的标准来说,这太过于苛刻了,也很不可思议。
from mayavi import mlab
import numpy as np
from tvtk.api import tvtk
k=mlab.imshow(np.random.random((10,10)),colormap='bone')
colors=tvtk.UnsignedCharArray()
colors.from_array(np.random.randint(256,size=(100,3)))
k.mlab_source.dataset.point_data.scalars=colors
k.actor.input.point_data.scalars=colors
#the latter set of scalars is what is actually used in the VTK pipeline in this
#case, but if they don't play nice with the mayavi source then tvtk will
#complain because we are circumventing the structure it expects
k.actor.input.scalar_type='unsigned_char'
k.actor.input.number_of_scalar_components=3
k.image_map_to_color.lookup_table=None
k.actor.input.modified()
mlab.draw()
#this draw fails. As it fails, there is an interaction here, somewhere deep in
#tvtk, causing the ImageData to partially reset.. I have not been able to track
#it down yet. ignore the error output
k.actor.input.scalar_type='unsigned_char'
k.actor.input.number_of_scalar_components=3
#now after we reset these back to what they should be, it works
mlab.draw()
mlab.show()
但在纯粹的tvtk中,它并不是那么糟糕:
import numpy as np
from tvtk.api import tvtk
colors=np.random.randint(256,size=(100,3))
an_image=tvtk.ImageData()
an_image.number_of_scalar_components=3
an_image.scalar_type='unsigned_char'
an_image.point_data.scalars=tvtk.UnsignedCharArray()
an_image.point_data.scalars.from_array(colors)
an_image.dimensions=np.array((10,10,1))
an_actor=tvtk.ImageActor()
an_actor.input=an_image
an_actor.interpolate=False
ren=tvtk.Renderer()
renWin=tvtk.RenderWindow()
renWin.add_renderer(ren)
ren.add_actor2d(an_actor)
iren=tvtk.RenderWindowInteractor()
iren.render_window=renWin
iren.interactor_style=tvtk.InteractorStyleTrackballCamera()
renWin.render()
iren.start()
当然,在vtk中完成这项工作更有意义。你甚至可以很好地包装它,这样它非常合理。
我想修复mayavi来正确处理这个问题,但正如你从我的代码片段中看到的那样,它并不简单,可能需要一段时间。