MayaVi中指定3D点的绝对颜色

15
我正在使用MayaVi Python库绘制3D点,使用points3d类。 文档指定每个点的颜色通过第四个参数s进行指定:

此外,您可以传递一个与x、y和z形状相同的第四个数组s,为每个点提供关联的标量值,或者返回标量值的函数f(x, y, z)。该标量值可用于调制点的颜色和大小。

这为每个点指定了一个标量值,将该点映射到颜色映射中,例如copperjethsv。例如,从他们的文档中:
import numpy
from mayavi.mlab import *

def test_points3d():
    t = numpy.linspace(0, 4*numpy.pi, 20)
    cos = numpy.cos
    sin = numpy.sin

    x = sin(2*t)
    y = cos(t)
    z = cos(2*t)
    s = 2+sin(t)

    return points3d(x, y, z, s, colormap="copper", scale_factor=.25)

给出:

enter image description here

相反,我想指定每个点的实际值作为 (r, g, b) 元组。在 MayaVi 中是否可能?我已经尝试用元组数组替换 s,但是会抛出错误。

4个回答

18
在今天大部分时间里苦苦挣扎后,我找到了一种相对简单的方法来实现问题所要求的——为每个点指定一个RGB元组。关键是只需定义一个颜色映射,其条目数与要绘制的点数完全相同,然后将参数设置为索引列表。
# Imports
import numpy as np
from mayavi.mlab import quiver3d, draw

# Primitives
N = 200 # Number of points
ones = np.ones(N)
scalars = np.arange(N) # Key point: set an integer for each point

# Define color table (including alpha), which must be uint8 and [0,255]
colors = (np.random.random((N, 4))*255).astype(np.uint8)
colors[:,-1] = 255 # No transparency

# Define coordinates and points
x, y, z = colors[:,0], colors[:,1], colors[:,2] # Assign x, y, z values to match color
pts = quiver3d(x, y, z, ones, ones, ones, scalars=scalars, mode='sphere') # Create points
pts.glyph.color_mode = 'color_by_scalar' # Color by scalar

# Set look-up table and redraw
pts.module_manager.scalar_lut_manager.lut.table = colors
draw()

2
对于想在除了箭头图之外的其他类型图上执行此操作的任何人来说,重要的是倒数第二行;也就是说,您也可以执行 surf.module_manager.scalar_lut_manager.lut.table = colors - RolKau

9
我找到了一种更好的方法来直接设置颜色。
你可以很容易地创建自己的直接查找表(LUT)。假设我们想要256 ** 3的粒度:
#create direct grid as 256**3 x 4 array 
def create_8bit_rgb_lut():
    xl = numpy.mgrid[0:256, 0:256, 0:256]
    lut = numpy.vstack((xl[0].reshape(1, 256**3),
                        xl[1].reshape(1, 256**3),
                        xl[2].reshape(1, 256**3),
                        255 * numpy.ones((1, 256**3)))).T
    return lut.astype('int32')

# indexing function to above grid
def rgb_2_scalar_idx(r, g, b):
    return 256**2 *r + 256 * g + b

#N x 3 colors. <This is where you are storing your custom colors in RGB>
colors = numpy.array([_.color for _ in points])

#N scalars
scalars = numpy.zeros((colors.shape[0],))

for (kp_idx, kp_c) in enumerate(colors):
    scalars[kp_idx] = rgb_2_scalar_idx(kp_c[0], kp_c[1], kp_c[2])

rgb_lut = create_8bit_rgb_lut()

points_mlab = mayavi.mlab.points3d(x, y, z, scalars, mode='point')

#magic to modify lookup table 
points_mlab.module_manager.scalar_lut_manager.lut._vtk_obj.SetTableRange(0, rgb_lut.shape[0])
points_mlab.module_manager.scalar_lut_manager.lut.number_of_colors = rgb_lut.shape[0]
points_mlab.module_manager.scalar_lut_manager.lut.table = rgb_lut

1
非常感谢您提供这个通用的优秀答案! - Howard GENG

6
您可以使用 RGB 查找表,并使用任何逻辑将您的 RGB 值映射到它上面。以下是一个简单的示例:
import numpy, random
from mayavi.mlab import *

def cMap(x,y,z):
    #whatever logic you want for colors
    return [random.random() for i in x]

def test_points3d():
    t = numpy.linspace(0, 4*numpy.pi, 20)
    cos = numpy.cos
    sin = numpy.sin

    x = sin(2*t)
    y = cos(t)
    z = cos(2*t)
    s = cMap(x,y,z)

    return points3d(x, y, z, s, colormap="spectral", scale_factor=0.25)

test_points3d()

我不知道你想要什么颜色方案,但是你可以评估x、y、z的位置,并返回对应于所寻求的rgb值的任何标量。


有没有一种方法可以生成任意的0-255 RGB值,而不需要指定一个具有256x256x256个值的唯一颜色映射?换句话说,在您的解决方案中,是否有一种方式来表征反Spectral()函数,其中Spectral()是一个定义域为[0,1],范围为0-255、0-255、0-255的函数?这种行为一直让我感到恼火,我已经看到一些应用程序绕过了它(例如vtk程序trackvis,其所有者拒绝向我发布源代码,以便我可以看到他是如何做到的)。 - aestrivex
您可以探索 mayavi.core.lut_manager,特别是在其中的 pylab_luts,以查看它们是如何构建的(并且可能会构建自己并分配它具有所需行为)。 - Chrismit
我已经尝试过这些。使用自定义LUT来指定所需的颜色方案远不如为每个顶点指定唯一的RGB值(其中指定了标量)那么通用。从计算上讲,这并不正确,因为可以指定一个具有256x256x256个值的LUT,唯一地定义RGB颜色谱。但实际上这将是一件非常麻烦的事情。我认为这个问题的正确答案是“抱歉,没有正确的方法来解决这个问题。” - aestrivex
4
这让我有点哭。还有其他的软件包可以实现这个吗? - Andreas Mueller
1
我同意Andreas的观点,我也采取了fetas的立场,并在意识到API没有任何清晰/默认的自定义颜色方式后开始哭泣。这是我的解决方案:http://stackoverflow.com/questions/24471210/how-to-draw-a-color-image-in-mayavi-imshow - Simon Streicher
显示剩余3条评论

3
现在,只需使用color参数即可完成此操作。
from mayavi import mlab
import numpy as np

c = np.random.rand(200, 3)
r = np.random.rand(200) / 10.

mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=(0.2, 0.4, 0.5))

mlab.show()

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接