tk基本介绍
- VTK 库的框架结构
vtkObject -> vtkSource -> vtkFilter -> vtkMapper -> vtkActor -> vtkRenderer
对象 | 介绍 |
vtkObject | vtk库的基类 |
vtkSource | vtkFilter父类,为为整个可视化流程的开始定义具体的行为和接口,比如读取数据 |
vtkFilter | 对原始数据进行滤波器处理,转化成可以直接应用算法模块的形式 |
vtkMapper | 它将 vtkFilter 处理后的应用数据映射为几何数据,相当于为原始数据和图像数据之间定义了接口 |
vtkActor | 表示渲染场景下一个特定物体(几何结构和属性) |
vtkRenderer | 为渲染器提供一种抽象规范,最终 vtkActor 通过 vtkRenderer 类将结果在窗口中显示出来 |
- vtk基本对象
基本对象 | 介绍 |
渲染控制器 | 定义与设备无关的坐标计算方法,创建渲染窗口 |
渲染窗口 | 渲染窗口管理显示设备上的窗口,绘制方法可在渲染窗口上创建一个场景;渲染窗口是用户图形界面,其中包括了设置渲染窗口的大小,产生立体显示效果等方法 |
渲染器 | 渲染器(Renderer)是管理光源照相机和绘制对象等的位置、属性等,提供了世界坐标系,观察坐标系及显示坐标系之间的转换 |
灯光 | 灯光可在场景中照亮绘制对象 |
摄像机 | 摄像机是定义观察者的位置 |
角色 | 角色代表渲染场景中的绘制对象实体,通过参数调节可以设置角色的位置、方向、渲染特性、引用、纹理映射等属性,并可对角色进行缩放。 |
特性 | 特性是说明几何物体的一些特性,实现三维图形真实感 |
映射 | 映射制定了渲染数据和图形库中基本图元之间的联系 |
变换 | 变换是一个放置 4x4 变换矩阵的堆栈,可以进行各种操作 |
在vtk中绘制或者渲染一个场景,需要以下基本对象
-
vtkRenderWindow
-
vtkRenderer
-
vtkLight
-
vtkCamera
-
vtkActor
-
vtkProperty
-
vtkMapper
# 案例
import vtk
def Create():
arrow_source = vtk.vtkArrowSource() # 数据源 箭头
mapper = vtk.vtkPolyDataMapper() # 创建映射器
mapper.SetInputConnection(arrow_source.GetOutputPort()) #映射器添加箭头的数据源
actor = vtk.vtkActor() # 创建演员
actor.SetMapper(mapper) # 给演员添加映射器
ren = vtk.vtkRenderer() #创建绘制器
ren.AddActor(actor) #绘制器加演员
renWin = vtk.vtkRenderWindow() #创建显示窗口
renWin.AddRenderer(ren) #向窗口中加入绘制器
renWin.Render() #窗口读取绘制器,并生成图形
iren = vtk.vtkRenderWindowInteractor() #窗口交互器
iren.SetRenderWindow(renWin) #交互器中加入窗口
iren.Initialize()
iren.Start()
Vtk柱体
cylinder = vtk.vtkCylinderSource()
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.SetResolution(360)
print("高:{0};半径:{1};角度:{2}".format(cylinder.GetHeight(),cylinder.GetRadius(),cylinder.GetResolution()))
# 映射,将输入的数据转换为几何图元(点、线、多边形)进行渲染
mapper =vtk.vtkPolyDataMapper()
# 设置 VTK 可视化管线的输入数据接口,对应的可视化管线输出数据的接口为 GetOutputPort()
mapper.SetInputConnection(cylinder.GetOutputPort())
actor = vtk.vtkActor()
prop = vtk.vtkProperty()
prop.SetColor(0.6,0.96,1)
bmpReader = vtk.vtkBMPReader()
bmpReader.SetFileName("sky.bmp")
texture = vtk.vtkTexture()
texture.SetInputConnection(bmpReader.GetOutputPort())
texture.InterpolateOn()
actor.SetProperty(prop)
actor.SetTexture(texture)
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
renderer.SetBackground(0.1,0.2,0.4)
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(renderer)
renWin.SetSize(1200,1200)
renWin.Render() # 绘制窗口内所有绘制器同步渲染绘制
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
iren.Initialize() #必须
iren.Start() #开始进入事件响应循环
三维空间中渲染对象最常用的是vtkProp子类是vtkActor(几何数据)和vtkVolume(体数据)
vtkProp子类负责确定渲染场景中对象的位置、大小和方向信息。
Prop依赖于两个对象(Prop一词来源于戏剧里的“道具”,在VTK里表示的是渲染场景中可以看得到的对象。)一个是Mapper(vtkMapper)对象,负责存放数据和渲染信息,另一个是属性(vtkProperty)对象,负责控制颜色、不透明度等参数。
VTK数据结构
import vtk
# *******三个点 加拓扑*******
# 创建点数据
points = vtk.vtkPoints()
# 创建顶点类型 points是坐标不是顶点
vertices = vtk.vtkCellArray()
# 创建点的坐标
points_list = [[1,0,0],[0,0,1],[0,0,0]]
for point in points_list:
# 每个点坐标加入到 vtkPoints 中,返回加入点的索引号
id = points.InsertNextPoint(point)
# 在每个坐标点上分别创建一个顶点,顶点是单元 Cell 里的一种类型
vertices.InsertNextCell(1)
vertices.InsertCellPoint(id)
line0 = vtk.vtkLine()
# 线有两个端点,连接两个point
line0.GetPointIds().SetId(0,0)
line0.GetPointIds().SetId(1,1)
line1 = vtk.vtkLine()
line1.GetPointIds().SetId(0,1)
line1.GetPointIds().SetId(1,2)
line2 = vtk.vtkLine()
line2.GetPointIds().SetId(0,2)
line2.GetPointIds().SetId(1,0)
lines = vtk.vtkCellArray()
lines.InsertNextCell(line0)
lines.InsertNextCell(line1)
lines.InsertNextCell(line2)
# 创建 vtkPolyData 对象
polydata = vtk.vtkPolyData()
# 指定数据集的几何结构(由 points 指定)
polydata.SetPoints(points)
# 指定数据集的拓扑结构(由 vertices 指定)
polydata.SetVerts(vertices)
polydata.SetLines(lines)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(polydata)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetPointSize(10)
actor.GetProperty().SetLineWidth(10)
render = vtk.vtkRenderer()
render.SetBackground(0, 0, 0)
# Renderer Window
window = vtk.vtkRenderWindow()
window.AddRenderer(render)
window.SetSize(600, 600)
# System Event
win_render = vtk.vtkRenderWindowInteractor()
win_render.SetRenderWindow(window)
# Style
win_render.SetInteractorStyle(vtk.vtkInteractorStyleMultiTouchCamera())
# Insert Actor
render.AddActor(actor)
win_render.Initialize()
win_render.Start()
可视化基础
单元 Cell 是可视化的基础,单元是一系列有序的点按指定类型连接所定义的结构。这些点的连接顺序通常被称为顶点列表(Connectivity List);所指定的类型定义了单元的拓扑结构;点的坐标定义了单元的几何结构。
单元就是有序点集
单元是由单元类型和单元顶点列表 两部分构成
单元类型:决定点集的顺序,也就是拓扑
单元顶点列表由点的索引号表示,通过索引号可以找到坐标值
线性单元和非线性单元
VTK 单元类型分为线性和非线性和其他类型。单元类型的线性和非线性划分主要是以插值函数为依据。
线性单元
线性单元采用的是线性或者常量插值函数。单元里的任意一条辨都是由两个点连接定义的。常见的有:
单元 | |
Vertex | 顶点,由一个点定义,是零维的基本类型 |
Polyvertex | 多顶点,多个顶点组合而成,是零维的组合单元,其定义不受顶点顺序的限制 |
Line | 直线,一维的基本类型,由两个点定义,方向是从第一个点指向第二个点 |
Polyline | 折线,由一条或多条直线组合而成,属于一维的类型。由n+1个有序的点连接定义的,n表示折线的线段条数,每两个点(i, i+1)定义一条线段 |
Triangle | 三角形,二维的基本类型,由三个点按逆时针的方向连接定义的,点的连接方向和表面法向量符合右手法则 |
非线性单元
数值分析领域里为了更准确、精确地表达数据,采用非线性单元作为数据的基本表达结构。线性单元可以很容易转换成线图元被图形库处理,非线性单元不被图形库直接支持,因此非线性单元必须先转换成线性单元后才能被图形库支持。
VTK除了提供一套复杂的非线性单元接口框架,另一种做法就是在非线性单元的每一条曲线增加一个关键点,或者增加一个曲面来近似模拟非线性单元。
属性数据
属性数据主要用于描述数据集的属性特征,对数据集的可视化实质上是对属性数据的可视化,例如根据温度显示不同的颜色。
vtk也有矢量数据,VTK的矢量数据也是指既有大小也有方向的量,三维方向上用三元组(Triple)表示为(u, v, w),如速度、应力、位移等。
import vtk
points = vtk.vtkPoints()
points.InsertNextPoint(0,0,0)
points.InsertNextPoint(1,0,0)
polydata = vtk.vtkPolyData()
polydata.SetPoints(points)
weights = vtk.vtkDoubleArray()
weights.SetNumberOfValues(2)
weights.SetValue(0,1)
weights.SetValue(1,2)
polydata.GetPointData().SetScalars(weights)
weight = polydata.GetPointData().GetScalars().GetValue(0)
print(weight)
数据集
数据集由组织结构(拓扑和几何)以及属性数据组成。
- vtkImageData
vtkImageData 类型的数据是按规则排列在矩形方格中的点和单元的集合,如果数据集的点和单元排列在平面(二维)上,称此数据集为像素映射(Pixmap)、位图或图像,由 vtkPixel 单元组成;如果排列在层叠面(三维)上,则称为体 (Volume),由 vtkVoxel 单元组成。数据维数用一个三元组 (nx, ny, nz) 来表示,分别表示在 X、Y 和 Z 方向上点的个数。
- vtkPolyData
多边形数据集 vtkPolyData 由顶点 (Vertex)、多顶点 (Polyvertex)、线 (Line)、折线 (Polyline) 和三角条带 (Triangle Strip) 等单元构成,多边形数据是不规则结构的,并且多边形数据集的单元在拓扑维度上有多种类型,多边形数据是数据、算法和高速计算机图像学的桥梁。
- vtkRectilinearGrid
vtkRectilinearGrid 类型(线性网格)的数据是排列在矩形方格中的点和单元的集合,线性网格的拓扑结构是规则的,但其几何结构只是部分规则,也就是说,它的点是沿着坐标轴排列的,但是两点间的间隔可能不同,与 vtkImageData 类型的数据相似,线性网格是由像素或体素等单元组成的,它的拓扑结构通过指定网格的维数来隐式表达,几何结构则通过一系列的 x, y, z 坐标来表达。
- vtkStructuredGrid
vtkStructuredGrid 是结构化网格数据,具有规则的拓扑结构和不规则的几何结构,但是单元之间没有重叠或交叉,如图(c)所示。结构化网格的单元是由四边形或六面体组成,结构化网格通常用于有限差分分析。典型的应用包括流体流动、热量传输和燃烧学等。
- vtkUnstructuredGrid
vtkUnstructuredGrid,非结构化网格是最常见的数据集类型,它的拓扑结构和几何结构都是不规则的,在此数据集中所有单元类型都可以组成任意组合,所以单元的拓扑结构从零维延伸至三维,如图(f)所示。
VTK中任一类型的数据集都可用非结构化网格来表达,vtkUnstructuredGrid 类型数据的存储需要大量的空间以及计算时需要消耗大量的资源,除非迫不得已,一般较少使用此种类型的数据集。非结构化网格主要用于有限元分析、计算几何和几何建模等领域。
- vtkUnstructuredPoints
vtkUnstructuredPoints,非结构化点集,是指不规则地分布在空间的点集。非结构化点集具有不规则的几何结构,不具有拓扑结构,非结构化点集用离散点来表达。
通常,这类数据没有固定的结构,由一些可视化程序识别和创建的,非结构化点集适合表现非结构化数据,为了实现数据的可视化,可将这种数据形式转换成其它一些结构化的数据形式
数据集的存储
- vtkDataArray 数据集的访问基于索引,从零开始
- Tuple(元组)的概念
许多可视化数据是由多个数据分量组成的,如RGB颜色数据由红、绿、蓝三个分量组成,为了在连续数组中表达这一类数据,VTK引入了元组(Tuple)的概念。元组是数据数组的子数组,用于存储数据类型相同的分量数据,元组的大小在给定后不会改变。
vtkDataArray 存储的是数值数据,如属性数据 (Attribute Data) 和点数据 (Point) 等。有些属性数据,如点、矢量、法向量和张量等,在定义时就需要指定元组的大小。例如,点、矢量和法向量等属性数据,元组的大小是3,而张量属性数据的元组大小是9 (即3×3的矩阵),标量属性数据对于元组的大小则没有任何要求,对于处理标量属性数据的算法,通常都是只处理标量每一个元组数据的第一个分量。VTK提供了将多分量的数据数组分离成单一分量的数据数组,以及将单一分量的数据数组合并成多分量的数据数组的类,即 vtkSplitField 和 vtkMergeFields。
import numpy
import vtk
from vtk.util.numpy_support import numpy_to_vtk
if __name__ == '__main__':
# 读取 txt 文档
source_data = numpy.loadtxt("bun000.txt")
# 新建 vtkPoints 实例
points = vtk.vtkPoints()
# 导入点数据
points.SetData(numpy_to_vtk(source_data))
# 新建 vtkPolyData 实例
polydata = vtk.vtkPolyData()
# 设置点坐标
polydata.SetPoints(points)
# 顶点相关的 filter
vertex = vtk.vtkVertexGlyphFilter()
vertex.SetInputData(polydata)
# mapper 实例
mapper = vtk.vtkPolyDataMapper()
# 关联 filter 输出
mapper.SetInputConnection(vertex.GetOutputPort())
# actor 实例
actor = vtk.vtkActor()
# 关联 mapper
actor.SetMapper(mapper)
# render
render = vtk.vtkRenderer()
render.SetBackground(0, 0, 0)
# Renderer Window
window = vtk.vtkRenderWindow()
window.AddRenderer(render)
window.SetSize(1200, 1200)
# System Event
win_render = vtk.vtkRenderWindowInteractor()
win_render.SetRenderWindow(window)
# Style
win_render.SetInteractorStyle(vtk.vtkInteractorStyleMultiTouchCamera())
# Insert Actor
render.AddActor(actor)
win_render.Initialize()
win_render.Start()
def data_actor_transform(source_data):
points = vtk.vtkPoints()
points.SetData(numpy_to_vtk(source_data))
polydata = vtk.vtkPolyData()
polydata.SetPoints(points)
vertex = vtk.vtkVertexGlyphFilter()
vertex.SetInputData(polydata)
# 设置变换过程
transform = vtk.vtkTransform()
transform.Translate(0,0,0)
transform.RotateY(180)
# 新建变换的 filter
transformFilter = vtk.vtkTransformPolyDataFilter()
# 将变换 filter 输入设置为点数据模型
transformFilter.SetInputConnection(vertex.GetOutputPort())
# 设置变换过程
transformFilter.SetTransform(transform)
transformFilter.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(transformFilter.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
return actor
vtk.vtkTransformPolyDataFilter()
# 将变换 filter 输入设置为点数据模型
transformFilter.SetInputConnection(vertex.GetOutputPort())
# 设置变换过程
transformFilter.SetTransform(transform)
transformFilter.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(transformFilter.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
return actor