一:主要的知识点
1、说明
本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程------逐行解析官网所有Python示例-CSDN博客
2、知识点纪要
本段代码主要涉及的有①vtkDiscretizableColorTransferFunction既可以连续颜色映射也可以离散颜色映射
二:代码及注释
python
import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkRenderingCore import vtkActor, vtkActor2D, vtkDiscretizableColorTransferFunction, vtkTextProperty, \
vtkPolyDataMapper, vtkTextMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersSources import vtkCylinderSource
from vtkmodules.vtkFiltersCore import vtkElevationFilter
from vtkmodules.vtkRenderingAnnotation import vtkScalarBarActor
def get_ctf(modern):
"""
vtkDiscretizableColorTransferFunction 与vtkColorTransferFunction一样,用于将 标量值映射为颜色
不过是vtkColorTransferFunction的增强版,可以理解为可选择离散化(discretizable)的颜色传递函数
支持将颜色映射离散化成固定数量的颜色级别,并且能自动生成对应的 vtkLookupTable,方便在渲染器或 mapper 中直接使用
类的功能概览
连续颜色映射: 像 vtkColorTransferFunction 一样,支持通过插值生成连续颜色梯度
离散颜色映射: 可以指定"分几级颜色",自动将颜色区间离散化
可生成 LookupTable:可直接输出一个 vtkLookupTable,供 mapper 使用
支持透明度(Alpha): 可以在颜色之外控制透明度函数。
支持直接输入 RGB/HSV 空间颜色节点: 可选择在不同颜色空间中插值
"""
ctf = vtkDiscretizableColorTransferFunction()
ctf.SetColorSpaceToRGB()
ctf.SetScaleToLinear() # 设置颜色映射为线性比例
ctf.SetNanColor(0.5, 0.5, 0.5) # 设置当遇到无效数据(NaN)时使用的颜色
ctf.SetBelowRangeColor(0.0, 0.0, 0.0, ) # 设置低于 CTF 定义的最小标量值的数据点所使用的颜色
ctf.UseBelowRangeColorOn() # 启用上述设置的"低于范围颜色,如果不开启这个选项,于范围的数据通常会沿用颜色条最底端的颜色。开启后,它们将使用明确设置的黑色
ctf.SetAboveRangeColor(1.0, 1.0, 1.0)
ctf.UseAboveRangeColorOn()
if modern:
ctf.AddRGBPoint(-1.0, 1.0, 0.0, 0.0) # Red
ctf.AddRGBPoint(-2.0 / 3.0, 1.0, 128.0 / 255.0, 0.0) # Orange #ff8000
ctf.AddRGBPoint(-1.0 / 3.0, 1.0, 1.0, 0.0) # Yellow
ctf.AddRGBPoint(0.0, 0.0, 1.0, 0.0) # Green #00ff00
ctf.AddRGBPoint(1.0 / 3.0, 0.0, 1.0, 1.0) # Cyan
ctf.AddRGBPoint(2.0 / 3.0, 0.0, 0.0, 1.0) # Blue
ctf.AddRGBPoint(1.0, 128.0 / 255.0, 0.0, 1.0) # Violet #8000ff
else:
ctf.AddRGBPoint(-1.0, 1.0, 0.0, 0.0) # Red
ctf.AddRGBPoint(-2.0 / 3.0, 1.0, 165.0 / 255.0, 0.0) # Orange #00a500
ctf.AddRGBPoint(-1.0 / 3.0, 1.0, 1.0, 0.0) # Yellow
ctf.AddRGBPoint(0.0, 0.0, 125.0 / 255.0, 0.0) # Green #008000
ctf.AddRGBPoint(1.0 / 3.0, 0.0, 153.0 / 255.0, 1.0) # Blue #0099ff
ctf.AddRGBPoint(2.0 / 3.0, 68.0 / 255.0, 0, 153.0 / 255.0) # Indigo #4400ff
ctf.AddRGBPoint(1.0, 153.0 / 255.0, 0.0, 1.0) # Violet #9900ff
ctf.SetNumberOfValues(7)
ctf.DiscretizeOn() # 颜色离散化
return ctf
def rescale(values, new_min, new_max):
# 将一组原始数值从它们当前的范围,线性地转换(映射)到用户指定的新范围内
res = list()
old_min, old_max = min(values), max(values)
for v in values:
new_v = (new_max - new_min) / (old_max - old_min) * (v - old_min) + new_min
res.append(new_v)
return res
def rescale_ctf(ctf, new_min, new_max, reverse):
if new_min > new_max:
r0 = new_max
r1 = new_min
else:
r0 = new_min
r1 = new_max
xv = []
rgbv = []
nv = [0] * 6
"""
为什么nv是一个长度为6的列表?
因为ctf.GetNodeValue(i, nv)返回的列表包含一个颜色节点(color node)的全部信息,而这个颜色节点在
vtk中包含的信息有[X,R,G,B,MidPoint,Sharpness]
其中X是对应的标量数据值,R,G,B是对应的颜色
MidPoint是中点参数,控制颜色过渡的非线性成都。0表示线性插值,1表示中点在两个颜色之间距离100%的位置
Sharpness是尖锐度参数,控制插值曲线的陡峭程度,通常用于创建更锐利或更平滑的过渡效果
"""
for i in range(0, ctf.GetNumberOfValues()):
ctf.GetNodeValue(i, nv)
x = nv[0]
rgb = nv[1:4]
xv.append(x)
rgbv.append(rgb)
xvr = rescale(xv, r0, r1)
return generate_new_ctf(ctf, xvr, rgbv, reverse=reverse)
def generate_new_ctf(old_ctf, new_x, new_rgb, reverse):
new_ctf = vtkDiscretizableColorTransferFunction()
# 获取标量数据值如何沿着颜色条进行映射和差值,得到的结果要么是线性要么是对数,对数适合数据范围跨国多个量级
new_ctf.SetScale(old_ctf.GetScale())
new_ctf.SetColorSpace(old_ctf.GetColorSpace())
new_ctf.SetNanColor(old_ctf.GetNanColor())
if not reverse:
new_ctf.SetBelowRangeColor(old_ctf.GetBelowRangeColor())
new_ctf.SetUseBelowRangeColor(old_ctf.GetUseBelowRangeColor())
new_ctf.SetAboveRangeColor(old_ctf.GetAboveRangeColor())
new_ctf.SetUseAboveRangeColor(old_ctf.GetUseAboveRangeColor())
else:
new_ctf.SetBelowRangeColor(old_ctf.GetAboveRangeColor())
new_ctf.SetUseBelowRangeColor(old_ctf.GetUseAboveRangeColor())
new_ctf.SetAboveRangeColor(old_ctf.GetBelowRangeColor())
new_ctf.SetUseAboveRangeColor(old_ctf.GetUseBelowRangeColor())
new_ctf.SetNumberOfValues(len(new_x))
new_ctf.SetDiscretize(old_ctf.GetDiscretize())
if not reverse:
for i in range(0, len(new_x)):
new_ctf.AddRGBPoint(new_x[i], *new_rgb[i])
else:
sz = len(new_x)
for i in range(0, sz):
j = sz - (i + 1)
new_ctf.AddRGBPoint(new_x[i], *new_rgb[j])
new_ctf.Build()
return new_ctf
def main():
colors = vtkNamedColors()
colors.SetColor("ParaViewBkg", (82, 87, 110, 255))
# 负责创建和配置四个不同的颜色传递函数变体,以便在四个不同的3D视图中进行比较
ctf = []
ctf.append(get_ctf(False))
ctf.append(rescale_ctf(ctf[0], 0, 1, False))
ctf.append(rescale_ctf(ctf[0], *ctf[0].GetRange(), True))
ctf.append(rescale_ctf(ctf[0], 0, 1, True))
# 定义viewport
xmins = [0.0, 0.0, 0.5, 0.5]
xmaxs = [0.5, 0.5, 1.0, 1.0]
ymins = [0.5, 0.0, 0.5, 0.0]
ymaxs = [1.0, 0.5, 1.0, 0.5]
titles = ['Original', 'Rescaled', 'Reversed', 'Rescaled and Reversed']
text_property = vtkTextProperty()
text_property.SetFontSize(36)
text_property.SetJustificationToCentered()
text_property.SetColor(colors.GetColor3d('LightGoldenrodYellow'))
ren_win = vtkRenderWindow()
ren_win.SetSize(640 * 2, 480 * 2)
ren_win.SetWindowName('RescaleReverseLUT')
iren = vtkRenderWindowInteractor()
iren.SetRenderWindow(ren_win)
# style = vtkInteractorStyleTrackballCamera()
# iren.SetInteractorStyle(style)
sources = list()
elevation_filters = list()
mappers = list()
actors = list()
scalar_bars = list()
renderers = list()
text_mappers = list()
text_actors = list()
for i in range(0, 4):
cylinder = vtkCylinderSource()
cylinder.SetCenter(0.0, 0.0, 0.0)
cylinder.SetResolution(6)
cylinder.Update()
bounds = cylinder.GetOutput().GetBounds()
sources.append(cylinder)
"""
vtkElevationFilter 根据点在空间中的位置(通常是高度/方向)来为每个点生成一个标量值(即"标高"或"海拔")
"""
elevation_filter = vtkElevationFilter()
elevation_filter.SetScalarRange(0, 1)
elevation_filter.SetLowPoint(0, bounds[2], 0)
elevation_filter.SetHighPoint(0, bounds[3], 0)
elevation_filter.SetInputConnection(sources[i].GetOutputPort())
elevation_filters.append(elevation_filter)
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(elevation_filters[i].GetOutputPort())
mapper.SetLookupTable(ctf[i])
mapper.SetColorModeToMapScalars()
mapper.InterpolateScalarsBeforeMappingOn()
mappers.append(mapper)
actor = vtkActor()
actor.SetMapper(mappers[i])
actors.append(actor)
# Add a scalar bar.
"""
创建和显示一个颜色标尺
"""
scalar_bar = vtkScalarBarActor()
scalar_bar.SetLookupTable(ctf[i])
scalar_bars.append(scalar_bar)
text_mappers.append(vtkTextMapper())
text_mappers[i].SetInput(titles[i])
text_mappers[i].SetTextProperty(text_property)
text_actors.append(vtkActor2D())
text_actors[i].SetMapper(text_mappers[i])
# Note: The position of an Actor2D is specified in display coordinates.
text_actors[i].SetPosition(300, 16)
ren = vtkRenderer()
ren.SetBackground(colors.GetColor3d('ParaViewBkg'))
ren.AddActor(actors[i])
ren.AddActor(scalar_bars[i])
ren.AddActor(text_actors[i])
ren.SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i])
renderers.append(ren)
ren_win.AddRenderer(renderers[i])
ren_win.Render()
iren.Start()
if __name__ == '__main__':
main()