由于CUDA版本过高、某些依赖无法安装等种种原因,本人在Ubuntu16.04系统中Python环境下只能使用VTK库进行点云的实时显示。无奈在网上很少看到有Python版本的VTK教学内容,只能耐心阅读官方文档教程进行学习。官方教程共有六个内容,只是一个入门级别的简介,但其中很多内容还需自己查找理解,现将内容进行记录,希望对各位像我一样的新手有所帮助。
官方文档链接如下:
在官方文档中,除该教程外,还有textbook(557页PDF版本教科书,可以加强理解)、各种类的调用介绍以及一些例子,但是多数为C++版本,如果在Python模块中没有找到,还是参考着C++版本的例子进行编程。
Tutorial Step1:
教程描述:
创建一个多边形棱锥显示在屏幕中,并使相机围绕棱锥进行360°旋转,随后退出窗口。
前情提要:
VTK可视化机制采用Pipeline的方式。说个题外话,对于Pipeline这个词本人一直无法准确翻译,包括realsense中也有Pipeline。通道?管线?大概就是通道的理解方式吧,类似生产线,按照固定的顺序执行完操作后成品。这个Pipeline包括代表数据的数据对象、处理数据的处理对象以及指示方向的数据流(对象之间的连接箭头)。数据对象表示信息,它提供创建、访问和删除此信息的方法(没细了解)。处理对象对输入的数据进行操作以生成输出数据,要么从它的输入中派生出新数据,要么将输入数据转换成新的格式。例如处理对象可以从压力场或将压力场转换为恒值压力等值线以生成压力梯度数据。处理对象可以分为source对象,filter对象,mapper对象等等。Source对象接口外部数据源或者通过本地参数生成数据。它还可以连接到外部数据通信端口和设备,包括模拟、建模或用于测温、测压等其它物理属性数据采集系统。Filter对象需要一个或多个输入数据对象生成一个或多个输出数据对象,它对数据进行各种类似滤波器的算法处理。典型示例使计算每周股票市场平均值,将数据值表示为缩放图标或对两个输入数据源执行合并操作。Mapper对象对应于功能模型中的槽,它用于终止pipeline数据流,通常mapper对象将数据转换为基本图形层,即映射的过程。
VTK程序的典型特征是Source→Mapper→Actor→Renderer→Renderwindow的配置顺序。
Actor策划mapper图形层的渲染,一个actor(角色?演员?)实例代表了一个渲染场景中的一个对象(几何图形及属性)。Renderer类似一个视窗,程序将actor分配到每个视窗中最后在Renderwindow中显示。其中Renderer是Renderwindow中一个或部分窗口,即同一个渲染窗口中可以显示多个视窗,每个视窗中可以承载多个actor,最终实现场景的显示。
按照这个顺序,教程中给出了第一个段代码,我对需要注意的地方增加了注释并翻译了原始注释:
代码:
#!/usr/bin/env python
# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersSources import vtkConeSource
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderer
)
def main(argv):
#
# 创建vtkNamedColors实例,用于选择对象和背景的颜色
#
colors = vtkNamedColors()
#
# 创建vtkConeSource实例并设定一些属性,
# 该source实例通过本地参数生成棱锥模型数据。
# VtkConeSource实例“cone”是可视化pipeline的一部分。
# 它生成一些其它filter也许会处理的数据(输出vtkPolyData类型数据)。
#
cone = vtkConeSource()
cone.SetHeight(3.0)
cone.SetRadius(1.0)
cone.SetResolution(10)
#
# 在示例中,我们使用mapper进程对象来结束pipeline。
# (中间的filter比如vtkShrinkPolyData也许会被插入到source和mapper之间)
# 我们创建一个实例化的vtkPolyDataMapper去将多边形数据映射到基本图形层中。
# 我们将cone source连接到这个mapper的输入
#
coneMapper = vtkPolyDataMapper() #vtkPolyDataMapper将多边形数据比如vtkPolyData映射到基本图形层中。
coneMapper.SetInputConnection(cone.GetOutputPort()) #SetInputConnection为给定的输入端口索引设置连接,其输入是另一个filter的输出端口,通过GetOutputPort获得。
#
# 创建一个actor代表cone。actor策划mapper基本图形层的渲染。
# 一个actor也通过vtkProperty实例化来改变属性,并包括了一个内部变换矩阵。我们设定之前创建的这个actor的mapper为“coneMapper”。
#
coneActor = vtkActor() # 代表了一个渲染场景中的一个对象(几何图形及属性),vtkActor用于表示渲染场景中的实体,它继承了vtkProp的actors位姿相关函数。
coneActor.SetMapper(coneMapper) # 连接一个actor到一个可视化pipeline的结尾(比如mapper)
coneActor.GetProperty().SetColor(colors.GetColor3d('MistyRose'))
#
# 创建一个Renderer并将actors分配进去。一个renderer就像一个视窗,是屏幕中的一个或者部分窗口,用于绘制它拥有的actors。我们也在这里设定背景色。
#
ren1 = vtkRenderer()
ren1.AddActor(coneActor)
ren1.SetBackground(colors.GetColor3d('MidnightBlue'))
# 最终我们创建render窗口,它将显示在屏幕中。我们使用AddRenderer将renderer放在render窗口中。我们也将尺寸设定在300*300像素大小。
#
renWin = vtkRenderWindow()
renWin.AddRenderer(ren1)
renWin.SetSize(300, 300)
renWin.SetWindowName('Tutorial_Step1')
#
# 现在我们循环360°,并在每一刻渲染cone。
#
for i in range(0, 360):
# 渲染图像
renWin.Render()
# 旋转相机1°,注意:Azimuth是旋转相机的操作,
# 它将使相机绕着以焦点为中心,view up方向的轴进行角度旋转,而模型不动。
# 其中view up方向是人为设定的,在世界坐标系下的相机坐标系的Y轴方向(在官方文档中vtkcamera类中的函数中有说明)。
# 关于这部分我也许会在后续相机部分进行介绍(如果有需要的话)。
ren1.GetActiveCamera().Azimuth(1)
if __name__ == '__main__':
import sys
main(sys.argv)