【问题标题】:Displaying true-colour 2D RGB textures in a 3D plot?在 3D 图中显示真彩色 2D RGB 纹理?
【发布时间】:2013-10-21 09:48:38
【问题描述】:

我正在尝试制作一个 3D 图,该图由一系列通过 RGB 堆栈的 2D 平面组成,如下所示:

我知道可以通过将每个像素的 x、y、z 坐标和 RGB(A) 颜色传递给plot_surface 来使用mpl_toolkits.mplot3d 来做到这一点:

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) 元组或预定义的颜色图。

有人知道在 3D 图中显示真彩色 2D RGB 纹理的更好方法吗?

如果有足够的时间,我可能会弄清楚如何在 Vtk 甚至纯 OpenGL 中做到这一点(如果需要),但我真的希望有现有的库可以完成这项工作。

【问题讨论】:

  • @cgohlke 谢谢,我去看看
  • @cgohlke 哇,这看起来确实很有前途!
  • 您是否尝试过使用.pcolor 绘制它们?请参阅:stackoverflow.com/questions/14355876/… 不过你需要大量内存!
  • @RutgerKassies 实际上是否可以使用pcolor() 为每个像素指定 RGB(A) 值?我尝试将一组数组作为C 传递,并将RGB 值的元组作为facecolors= 传递,但没有运气。甚至绘制单个平面也非常很慢,所以我怀疑 OpenGL 后端是要走的路,很容易看到。

标签: python 3d matplotlib textures mayavi


【解决方案1】:

非常感谢 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)

【讨论】:

    【解决方案2】:

    我不知道其他库——volshow 看起来很整洁,但我没有测试过——但你可以在 vtk 中做到这一点。

    我一直致力于在 mayavi 中执行此操作(请参阅 How to directly set RGB/RGBA colors in mayavi),但对于某些图像源,mayavi 以一种根本不适合处理此问题的方式构建 vtk 管道。我从 mlab.imshow 开始将 2D vtk.ImageData 转换为真彩色的努力在每一步都遇到了阻力,但我做到了。

    首先,这是我在 mayavi 中使用 mlab 实现的方法。即使按照我的标准,这也太 hacky 和“魔术”了:

    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 以正确处理此问题,但正如您从我的 sn-p 中看到的那样,这并不简单,可能需要一段时间。

    【讨论】:

    • 非常感谢您提供的信息。最后我接受了@cgohlke 的建议,结果证明它实现起来要简单得多,但是知道如何直接使用 Mayavi/VTK 设置 RGBA 颜色非常有用——我很可能需要它来完成更复杂的工作未来。
    猜你喜欢
    • 2015-09-26
    • 1970-01-01
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 2011-07-10
    • 1970-01-01
    • 2012-09-28
    相关资源
    最近更新 更多