VTKWithNumpy使用 NumPy 数组来创建3D体渲染所需要的数据

一:主要的知识点

1、说明

本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程------逐行解析官网所有Python示例-CSDN博客

2、知识点纪要

本段代码主要涉及的有①vtk与numpy数组的联动,②vtkImageImport的使用

二:代码及注释

python 复制代码
import vtkmodules.vtkRenderingVolumeOpenGL2
import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkIOImage import vtkImageImport
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkRenderingCore import vtkColorTransferFunction, vtkRenderWindow, vtkRenderWindowInteractor, \
    vtkRenderer, vtkVolume, vtkVolumeProperty
import numpy as np
from vtkmodules.vtkCommonDataModel import vtkPiecewiseFunction
from vtkmodules.vtkRenderingVolume import vtkFixedPointVolumeRayCastMapper


def main():
    colors = vtkNamedColors()

    data_matrix = np.zeros([75, 75, 75], dtype=np.uint8)
    data_matrix[0:35, 0:35, 0:35] = 50
    data_matrix[25:55, 25:55, 25:55] = 100
    data_matrix[45:74, 45:74, 45:74] = 150

    """
    vtkImageImport 将外部的原始图像数据(Raw data)导入到 VTK 的图像管线中,从而变成一个 vtkImageData 对象,供后续处理或渲染使用
    这个类允许你把Python/Numpy 数组  C/C++ 原始内存数据(unsigned char*, float*, etc.)
    或者是外部图像格式(比如医学影像、数值模拟输出等)
    """
    dataImporter = vtkImageImport()
    # 会把整个数组的原始内存内容转换成 连续的字节流(bytes) 结果类似于:b'\x01\x02\x03\x04\x05\x06'
    # 因为 vtkImageImport 期望接收 原始字节数据指针,而不是 NumPy 对象
    data_string = data_matrix.tobytes()
    # CopyImportVoidPointer 复制一份数据到vtk内部
    dataImporter.CopyImportVoidPointer(data_string, len(data_string))
    dataImporter.SetDataScalarTypeToUnsignedChar()  # 将输入的数据转换为无符号8位证书类型
    dataImporter.SetNumberOfScalarComponents(1)
    """
    SetDataExtent 告诉vtkImageImport 原始数据体素在x,y,z三个方向上的索引范围
    这里的意思是
    x方向:从 0 到 74,共 75 个体素
    y方向:从 0 到 74,共 75 个体素
    z方向:从 0 到 74,共 75 个体素
    """
    dataImporter.SetDataExtent(0, 74, 0, 74, 0, 74)
    """
    SetWholeExtent 这行代码看似重复,实则是在指定整个图像(数据集)在 VTK 管线中表示的范围
    SetDataExtent(...) 是描述当前导入数据的内存范围
    SetWholeExtent(...) 是描述VTK 内部整个图像数据的逻辑范围
    """
    dataImporter.SetWholeExtent(0, 74, 0, 74, 0, 74)

    """
    如果数据是由多块volume数据拼接的
    WholeExtent 可以大于 DataExtent,用于表示你导入的是其中的一部分
    importer1 = vtkImageImport()
    importer1.CopyImportVoidPointer(block1_data, len(block1_data))
    importer1.SetDataScalarTypeToUnsignedChar()
    importer1.SetNumberOfScalarComponents(1)
    importer1.SetDataExtent(0, 511, 0, 511, 0, 511)
    importer1.SetWholeExtent(0, 1023, 0, 1023, 0, 1023)
    
    importer2 = vtkImageImport()
    importer2.CopyImportVoidPointer(block2_data, len(block2_data))
    importer2.SetDataScalarTypeToUnsignedChar()
    importer2.SetNumberOfScalarComponents(1)
    importer2.SetDataExtent(512, 1023, 0, 511, 0, 511)
    importer2.SetWholeExtent(0, 1023, 0, 1023, 0, 1023)
    
    # 然后拼接起来
    append = vtkAppendFilter()
    append.AddInputConnection(importer1.GetOutputPort())
    append.AddInputConnection(importer2.GetOutputPort())
    append.AddInputConnection(importer3.GetOutputPort())
    append.Update()
    """

    # 定义标量与颜色的对应关系
    colorFunc = vtkColorTransferFunction()
    colorFunc.AddRGBPoint(50, 1.0, 0.0, 0.0)
    colorFunc.AddRGBPoint(100, 0.0, 1.0, 0.0)
    colorFunc.AddRGBPoint(150, 0.0, 0.0, 1.0)

    alphaChannelFunc = vtkPiecewiseFunction()  # piecewise function 百度翻译 分段函数
    alphaChannelFunc.AddPoint(0, 0.0)
    alphaChannelFunc.AddPoint(50, 0.05)
    alphaChannelFunc.AddPoint(100, 0.1)
    alphaChannelFunc.AddPoint(150, 0.2)

    volumeProperty = vtkVolumeProperty()
    volumeProperty.SetColor(colorFunc)
    volumeProperty.SetScalarOpacity(alphaChannelFunc)

    volumeMapper = vtkFixedPointVolumeRayCastMapper()
    volumeMapper.SetInputConnection(dataImporter.GetOutputPort())

    volume = vtkVolume()
    volume.SetMapper(volumeMapper)
    volume.SetProperty(volumeProperty)

    renderer = vtkRenderer()
    renderer.AddVolume(volume)
    renderer.SetBackground(colors.GetColor3d("MistyRose"))

    renderWin = vtkRenderWindow()
    renderWin.AddRenderer(renderer)
    renderInteractor = vtkRenderWindowInteractor()
    renderInteractor.SetRenderWindow(renderWin)

    renderWin.SetSize(400, 400)
    renderWin.SetWindowName('VTKWithNumpy')

    """
    用于实现渲染过程的中断检查,目的是提高应用程序的响应速度
    """
    def exitCheck(obj, event):
        # 检查 VTK 渲染窗口的事件队列中是否还有未处理的操作系统或用户输入事件(比如窗口移动、鼠标点击、键盘输入等)
        if obj.GetEventPending() != 0:
            obj.SetAbortRender(1)

    renderWin.AddObserver("AbortCheckEvent", exitCheck)

    renderInteractor.Initialize()
    renderWin.Render()
    renderInteractor.Start()


if __name__ == '__main__':
    main()
相关推荐
代码山河3 小时前
Python就业方向全解析:后端、爬虫、数据分析、AI你选哪个?
python·学习·架构·教程·面向对象·项目
在世修行4 小时前
智学文枢:题目流水线
python·多线程·状态机·pyside
梯度下降者4 小时前
零基础入门Python 爬虫
爬虫·python·数据分析·入门指南·webcrawler
“AI国潮设计-小江”6 小时前
【AIGC实战】Python+Stable Diffusion打造“英歌舞财神”IP,解锁“马到成功”等爆款情绪营销文案设计
开发语言·人工智能·python·prompt·aigc
benchmark_cc7 小时前
用 Python 拉 A 股全市场实时快照:Notebook 请求、结果校验与易错点
python·数据分析·pandas·量化交易·股票数据·quantdash
伞伞悦读7 小时前
【第70期】Adam二阶矩不是方差:偏差校正、动量与AdamW完整实验
python
外收内放7 小时前
Python基础语法练习题(73)
java·前端·python
锋行天下8 小时前
Langgraph HITL 中断运行,用户输入后输出打字效果
人工智能·python
时早玖沐8 小时前
给 AstrBot 写一个天气推送插件:12 次提交、6 个坑
python·开源·ai编程
触底反弹8 小时前
🚀 FastAPI 五大重难点深度剖析:从 500 报错到彻底搞懂 Depends、Pydantic 与 SQLAlchemy
python·fastapi