TVTK三维可视化笔记1(VTK的流水线&数据集)

由于TVTK库十分庞大,为了方便用户查询文档,TVTK库提供了一个显示TVTK文档
的工具。可以通过下面的语句运行它:

from tvtk.tools import tvtk_doc
tvtk_doc.main()

在这里插入图片描述
Tvtk库的基本三维对象
在这里插入图片描述

1.VTK的流水线

VTK是一个十分复杂的系统,为了方便用户使用,它使用流水线技术将VTK中的各
个对象串联起来。每个对象只需要实现相对简单的任务,整个流水线则能够根据用户的需
求实现十分复杂的数据可视化处理。
创建

1.1 显示圆锥

本人用ipython运行下面的程序。

#coding=utf-8
from tvtk.api import tvtk#1

#创建一个圆锥数据源对象,并且同时设置其高度、底面半径和底面圆的分辨率(底面边数)(用36边形近似)
cs=tvtk.ConeSource(height=3.0,radius=1.0,resolution=36)#2
#图像对象:使用PolyDataMapper将数据转换为图形数据
m=tvtk.PolyDataMapper(input_connection=cs.output_port)#3
#创建一个Actor场景的实体,实体中是图像对象
a=tvtk.Actor(mapper=m)#4
#创建一个Renderer三维场景,将Actor(实体)添加进去
ren=tvtk.Renderer(background=(1,1,1))#5
ren.add_actor(a)
#创建一个RenderWindow窗口,将Renderer添加进去(可以装很多场景)
rw=tvtk.RenderWindow(size=(300,300))#6
rw.add_renderer(ren)
#创建一个RenderWindowInteractor(窗口交互工具)
rwi=tvtk.RenderWindowInteractor(render_window=rw)#7
rwi.initialize()
rwi.start()

点击图像,会改变位置
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019081014485353.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU4NTcxMg==,size_16,color_FFFFFF,t_70
在这里插入图片描述在这里插入图片描述程序解析:
1.首先载入tvtk对象,它帮助我们创建TVTK库中的各种对象。我们载入的tvtk并不是一个模块,而是某个类的实例。之所以如此设计,是因为VTK库有近千个类,而TVTK对所有这些类都进行了包装。如果一次性载入这么多类,会极大地影响库的载入速度。
2.创建了一个ConeSource对象,它是计算圆锥形状的数据源对象。在TVTK中,所有类都从HasTraits继承,因此可以在创建对象的同时,使用关键字参数直接设置Trait属性的值。在这个例子中,同时设置了圆锥的高度、底面半径和底面圆的边数等属性。
下面查看ConeSource对象的所有Traits属性名,并显示height、radius和resolution等属
性的值:cs.trait_names()
在这里插入图片描述 在这里插入图片描述
重点来了!核心思想:
为了将原始数据转换为屏幕上的一幅图像,需要经过许多处理步骤。这些步骤由众多的VTK对象分步实现,就好像生产线上加工零件一样,每位工人都负责一部分工作,整条生产线就能将原材料制作成产品。在VTK中,这种在各个对象之间协调完成工作的过程被称作流水线(Pipeline)。
原始数据被加工成图像要经过两条流水线:
可视化流水线(Visualization Pipeline):它的工作是将原始数据加工成图形数据。一般来说,我们需要进行可视化展示的数据本身并不是图形数据,例如可能是某个零件内部各个部分的温度,或是流体中各个坐标点上的速度等。
图形流水线(Graphics Pipeline):它的工作是将图形数据加工为我们所看到的图像。可视化流水线所产生的图形数据通常是三维空间的数据,图形流水线将这些三维数据加工成能在二维屏幕上显示的图像。
3.映射器(Mapper)是可视化流水线的终点、图形流水线的起点,它的各种派生类能将众多的数据映射为图形数据以供图形流水线加工。
在本例中,ConeSource对象输出一个描述圆锥的顶点和面的PolyData对象,然后PolyData对象通过PolyDataMapper映射器转换为图形数据。因此在本例中,可视化流水线由ConeSource和PolyDataMapper对象组成。
4.Actor对象代表场景中的一个实体,它的mapper属性是表示图形数据的PolyDataMapper对象,Actor对象还有许多属性可以控制实体的位置、方向、大小等。
5.Renderer对象表示三维场景,它可以包含多个Actor对象,这些Actor对象都保存在actors列表属性中。
在本例中,它只包含一个显示圆锥的Actor对象。
6.RenderWindow对象表示包含场景的窗口,它可以同时包含多个场景。在本例中,它只有一个Renderer对象。
7.RenderWindowInteractor对象为图形窗口提供一些用户交互功能,例如平移、旋转和缩放。这些交互式操作并不改变场景中的各个实体(Actor对象),也不改变图形数据的属性,它们只是修改场景中照相机(Camera)的设置,从不同的角度和距离观察场景中的实体。

2.数据集

数据可视化的第一步是用合适的数据结构表示数据,VTK提供了多种表示不同种类数据的数据集(Dataset)。数据集包括点(Point)和数据(Data)两部分。点之间可以是连接的或非连接的,多个相关的点组成单元(Cell),而点之间的连接可以是显式或隐式的。数据可以是标量或矢量,数据可以属于点或单元。

2.1ImageData数据集

ImageData可以理解为二维或三维数组。数组中存放的是数据,由于点位于正交且等间距的网格之上,因此不需要给出点的坐标,而点之间的连接关系也由它们在数组中的位置决定,因此连接也是隐式的。
ImageData–>PointData–>DoubleArray和scalar

import numpy as np
from tvtk.api import tvtk
#origin属性为三维网格数据的起点坐标,spacing属性为三维网格在X、Y和Z轴上的间距,dimensions属性为X、Y和Z轴上的网格数
img = tvtk.ImageData(spacing=(0.1,0.1,0.1), origin=(0.1,0.2,0.3), dimensions=(2,4,5))

# img输出:<tvtk.tvtk_classes.image_data.ImageData at 0x1e1d07096d0>
#与每个点对应的数据都保存在point_data属性中,它是一个PointData对象

for n in range(6):#点的序号依次沿着X、Y和Z轴递增
    print("%.1f,%.2f,%.1f"%img.get_point(n))
    
#输出
#0.1,0.20,0.3
#0.2,0.20,0.3
#0.1,0.30,0.3
#0.2,0.30,0.3
#0.1,0.40,0.3
#0.2,0.40,0.3

img.point_data

#输出:<tvtk.tvtk_classes.point_data.PointData at 0x1e1d072e830>

print(img.point_data.scalars)#没有数据
img.point_data.scalars=np.arange(0.0,img.number_of_points)
print(type(img.point_data.scalars))
img.point_data.scalars

#None
#<class 'tvtk.tvtk_classes.double_array.DoubleArray'>
#[0.0, ..., 39.0], length = 40

a = img.point_data.scalars.to_array()
#DoubleArray数组只能以整数为下标,不支持切片以及其他高级下标运算。可以通过它的to_array()方法获得与其共享数据存储空间的NumPy数组,通过此NumPy数组可以进行更高级的数据存取操作
img.point_data.scalars.print_traits()#显示属性信息
img.point_data.scalars.number_of_tuples#40

"""
直接使用DoubleArray对象的方法或属性对其进行操作比较烦琐,因此建议读者仍然使用to_array()方法将其转换为NumPy数组之后再进行操作。对PointData对象中的多个数组进行管理PointData对象可以保存多个DoubleArray数组,它所包含的数组的个数可以通过number_of_arrays属性获得,可以通过add_array()方法添加新的数组对象,remove_array()方法用于删除数组对象,get_array()和get_array_name()分别用于获得数组对象及其名字。
"""
#一开始img.point_data有一个数组img.get_point(n)40个点,在加进来一个全零数组
data = tvtk.DoubleArray() # 创建一个空的DoubleArray数组
data.from_array(np.zeros(img.number_of_points))#并调用其from_array()方法通过NumPy数组设置其内容,数组的长度为ImageData对象的点数
data.name = "zerodata"
print (img.point_data.add_array(data))
print (repr(img.point_data.get_array(1))) # 获得第1个数组
print (img.point_data.get_array_name(1) )# 获得第1个数组的名字
print (repr(img.point_data.get_array(0)) )# 获得第0个数组
print (img.point_data.get_array_name(0)) # 获得第0个数组的名字
img.point_data.remove_array("zerodata")# 删除名为"zerodata"的数组
print(img.point_data.number_of_arrays) # 获取PointData包含数组的个数
#1
#[0.0, ..., 0.0], length = 40
#zerodata
#[0.0, ..., 39.0], length = 40
#None
#1

与每个点所对应的值除了标量之外,还可以是矢量或张量(矩阵),矢量数组可以使用vectors属性保存,而张量数组可以使用tensors属性保存。

#每个序号对应的是空间中一点
vectors = np.arange(0.0, img.number_of_points*3).reshape(-1, 3)#40X3矩阵
img.point_data.vectors = vectors
print (repr(img.point_data.vectors))
print (type(img.point_data.vectors))
print (img.point_data.vectors[0])
#[(0.0, 1.0, 2.0), ..., (117.0, 118.0, 119.0)], length = 40
#<class 'tvtk.tvtk_classes.double_array.DoubleArray'>
#(0.0, 1.0, 2.0)
img.point_data.vectors.number_of_tuples#40
img.point_data.vectors.number_of_components#3

在这里插入图片描述
通过get_cell()方法可以获得表示单元的Voxel(体素)对象,它的number_of_points、number_of_edges和number_of_faces等属性分别是构成体素对象的点数、边数以及面数。

cell=img.get_cell(0)
print(repr(cell))
print(cell.number_of_points,cell.number_of_edges,cell.number_of_faces)
#<tvtk.tvtk_classes.voxel.Voxel object at 0x000001E1D072EF10>
#8  12   6
print (repr(cell.point_ids))
#[0, 1, 2, 3, 8, 9, 10, 11]#第0个单元对应的八个顶点的序号
cell.points.to_array()#输出八个顶点
img.number_of_cells#ImageData对象的number_of_cells属性是数据集中的单元数12=(2-1)X(3-1)X(4-1)

2.2RectilinearGrid

ImageData是最简单的数据集,它的所有点都在一个等间距的三维网格之上,因此只需要起始坐标、网格大小以及网格间距等信息就可以计算出网格上所有点的坐标。如果要表示间距不均匀的网格,

在这里插入图片描述

from tvtk.api import tvtk
import numpy as np  
x = np.array([0,3,9,15])
y = np.array([0,1,5])
z = np.array([0,2,3])
r = tvtk.RectilinearGrid()
#RectilinearGrid对象的x_coordinates、y_coordinates和z_coordinates等属性,分别设置网格中与X轴、Y轴和Z轴垂直的平面的位置。
#RectilinearGrid对象中的点就是所有这些平面的交点
r.x_coordinates = x 
r.y_coordinates = y
r.z_coordinates = z
#由于RectilinearGrid对象不会根据这三个数组的长度自动调整dimensions属性,因此需要根据数组的长度设置dimensions属性
r.dimensions = len(x), len(y), len(z) 
#最后通过point_data属性设置每个点所对应的数据。  
r.point_data.scalars = np.arange(0.0,r.number_of_points) 
r.point_data.scalars.name = 'scalars'

做出的图如上所示

2.3StructuredGrid

比RectilinearGrid更进一步,StructuredGrid需要我们指定每个点的坐标。而点和单元之间的关系仍然由点在网格中的位置决定(和前两者一样)

在这里插入图片描述

2.4PolyData

PolyData数据集由一系列的点、点之间的连线以及由点构成的多边形面组成。这些信息都需要用户进行设置,因此用程序创建PolyData对象比较烦琐。
在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值