RescaleReverseLUT 演示和比较颜色查找表的重标定和反转

一:主要的知识点

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()
相关推荐
耶夫斯计3 分钟前
【SQL_agent】基于LLM实现sql助理
数据库·python·sql·语言模型
vibag4 分钟前
RAG向量数据库
python·语言模型·langchain·大模型
kisshuan123965 分钟前
基于YOLO11改进的C3k2-AdditiveBlock实现命中检测与双重命中事件识别_1
python
mg6686 分钟前
0基础开发学习python工具_____用 Python + Pygame 打造绚丽烟花秀 轻松上手体验
开发语言·python·学习·pygame
nervermore99016 分钟前
2.6 测试
python
EZ_Python23 分钟前
告别WPS会员!用Python自制电子发票批量打印排版工具
python·自动化
写文章的大米25 分钟前
1 分钟读懂:Python 装饰器
python
2501_9216494931 分钟前
股指期货 API 入门指南:如何获取实时行情与构建交易系统
python·websocket·金融·区块链·restful
Full Stack Developme1 小时前
Spring Security 与 Apache Shiro 两大安全框架比较
spring boot·python·安全
杰瑞哥哥1 小时前
快速搭建Web前端(streamlit使用指南)
python·信息可视化·web·模型部署