在 Mayavi 体积可视化中使用感知均匀的颜色图
Using perceptually uniform colormaps in Mayavi volumetric visualization
AFAIK Mayavi 没有任何感知上统一的色图。我天真地试图通过它 one of Matplotlib's colormaps 但它失败了:
from mayavi import mlab
import multiprocessing
import matplotlib.pyplot as plt
plasma = plt.get_cmap('plasma')
...
mlab.pipeline.volume(..., colormap=plasma)
TraitError: Cannot set the undefined 'colormap' attribute of a 'VolumeFactory' object.
编辑:我发现 a guide 可以将 Matplotlib 颜色图转换为 Mayavi 颜色图。但是,不幸的是它不起作用,因为我正在尝试使用感知统一的颜色图来使用体积。
from matplotlib.cm import get_cmap
import numpy as np
from mayavi import mlab
values = np.linspace(0., 1., 256)
lut_dict = {}
lut_dict['plasma'] = get_cmap('plasma')(values.copy())
x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)
mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=0, vmax=0.8, colormap=lut_dict['plasma']) # still getting the same error
mlab.axes()
mlab.show()
...
与其将其设置为 colormap
参数,不如将其设置为卷的 ColorTransferFunction
,它会按预期工作。
import numpy as np
from mayavi import mlab
from tvtk.util import ctf
from matplotlib.pyplot import cm
values = np.linspace(0., 1., 256)
x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)
volume = mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=0, vmax=0.8)
# save the existing colormap
c = ctf.save_ctfs(volume._volume_property)
# change it with the colors of the new colormap
# in this case 'plasma'
c['rgb']=cm.get_cmap('plasma')(values.copy())
# load the color transfer function to the volume
ctf.load_ctfs(c, volume._volume_property)
# signal for update
volume.update_ctf = True
mlab.show()
虽然 like444 之前的回答在一定程度上帮助我解决了类似的问题,但它会导致颜色图之间的转换不正确。这是因为 matplotlib 和 tvtk 存储颜色信息的格式略有不同:Matplotlib 使用 RGBA,而 ColorTransferFunction 使用 VRGB,其中 V 是显示数据中分配给这部分颜色图的值。因此,通过进行 1 对 1 复制,绿色变为红色,蓝色变为绿色,alpha 变为蓝色。以下代码片段解决了这个问题:
def cmap_to_ctf(cmap_name):
values = list(np.linspace(0, 1, 256))
cmap = cm.get_cmap(cmap_name)(values)
transfer_function = ctf.ColorTransferFunction()
for i, v in enumerate(values):
transfer_function.add_rgb_point(v, cmap[i, 0], cmap[i, 1], cmap[i, 2])
return transfer_function
AFAIK Mayavi 没有任何感知上统一的色图。我天真地试图通过它 one of Matplotlib's colormaps 但它失败了:
from mayavi import mlab
import multiprocessing
import matplotlib.pyplot as plt
plasma = plt.get_cmap('plasma')
...
mlab.pipeline.volume(..., colormap=plasma)
TraitError: Cannot set the undefined 'colormap' attribute of a 'VolumeFactory' object.
编辑:我发现 a guide 可以将 Matplotlib 颜色图转换为 Mayavi 颜色图。但是,不幸的是它不起作用,因为我正在尝试使用感知统一的颜色图来使用体积。
from matplotlib.cm import get_cmap
import numpy as np
from mayavi import mlab
values = np.linspace(0., 1., 256)
lut_dict = {}
lut_dict['plasma'] = get_cmap('plasma')(values.copy())
x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)
mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=0, vmax=0.8, colormap=lut_dict['plasma']) # still getting the same error
mlab.axes()
mlab.show()
...
与其将其设置为 colormap
参数,不如将其设置为卷的 ColorTransferFunction
,它会按预期工作。
import numpy as np
from mayavi import mlab
from tvtk.util import ctf
from matplotlib.pyplot import cm
values = np.linspace(0., 1., 256)
x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)
volume = mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=0, vmax=0.8)
# save the existing colormap
c = ctf.save_ctfs(volume._volume_property)
# change it with the colors of the new colormap
# in this case 'plasma'
c['rgb']=cm.get_cmap('plasma')(values.copy())
# load the color transfer function to the volume
ctf.load_ctfs(c, volume._volume_property)
# signal for update
volume.update_ctf = True
mlab.show()
虽然 like444 之前的回答在一定程度上帮助我解决了类似的问题,但它会导致颜色图之间的转换不正确。这是因为 matplotlib 和 tvtk 存储颜色信息的格式略有不同:Matplotlib 使用 RGBA,而 ColorTransferFunction 使用 VRGB,其中 V 是显示数据中分配给这部分颜色图的值。因此,通过进行 1 对 1 复制,绿色变为红色,蓝色变为绿色,alpha 变为蓝色。以下代码片段解决了这个问题:
def cmap_to_ctf(cmap_name):
values = list(np.linspace(0, 1, 256))
cmap = cm.get_cmap(cmap_name)(values)
transfer_function = ctf.ColorTransferFunction()
for i, v in enumerate(values):
transfer_function.add_rgb_point(v, cmap[i, 0], cmap[i, 1], cmap[i, 2])
return transfer_function