基于VTK与Qt的体绘制程序

1       基于VTKQt的体绘制程序

1.1     体绘制介绍

体绘制(Volume Rendering)是一种从离散三维数据场获得二维投影图像的技术。体绘制在医学成像和科学可视化当中有着广泛应用。用于体绘制的数据集也称为体数据(Volume Data)。典型的三维体数据是通过 CTMRI等成像技术采集的一组二维切片图像。通常这些图像都是按照某种规则(如每毫米一个切面)采集并重建而成,并有着相同数量的像素。这种体数据是规则的立体晶格,每个体数据的元素(又称为体素,Voxel)由一个通过采样周围相邻区域的体素获得的采样值来表示。

体绘制技术可以根据是否提取曲面分为直接体绘制和间接体绘制(又称为面绘制)两大类。间接体绘制是先从体数据中提取等值面,然后绘制等值面组成的多边形网格;直接体绘制则是将体数据直接作为一个离散三维数据场来绘制。而直接体绘制则直接从体数据中通过颜色与不透明度映射来生成三维数据集的二维投影图像。相对于间接体绘制来说,直接体绘制具有更大的优势,也就是不需要生成中间图元,直接对体数据进行成像,显示出全部的数据信息并且不会造成数据的丢失,而且成像的效果好于面绘制的结果,对人体内部的组织信息能够呈现出体数据更精细的显示结果,具有高度的保真性。由于直接体绘制是目前体绘制技术的主流,以下提到的体绘制都是指直接体绘制。

体绘制的更多信息,可参考:

体绘制(Volume Rendering)概述之1:什么是体绘制

http://blog.csdn.net/liu_lin_xm/article/details/4850575

体绘制(Volume Rendering)概述之2:体数据详解

http://blog.csdn.net/liu_lin_xm/article/details/4850593

1.2     传递函数

为了绘制三维体数据的二维投影,需要为每个体素定义不透明度与颜色。这通常由称为传递函数(Transfer Function)的映射来实现。传递函数为每个可能的体素定义相应的不透明度与颜色值。在体绘制过程中,体数据首先要经过传递函数,将测量得到的灰度值映射为用于显示的不透明度值和颜色值,然后通过光线投射法或者其它体绘制算法绘制出一种根据体数据中所有体素的颜色与不透明度叠加而成的具有立体感的投影图像。

体绘制时,每个采样值都必须映射为不透明度与颜色。这种从体素到不透明度与颜色的映射是通过传递函数来实现的。传递函数可以是简单的线性函数、分段线性函数或者任意的表。

VTK中,传递函数由颜色传递函数(vtkColorTransferFunction)与不透明度传递函数(vtkPiecewiseFunction)两个类来处理。

1.3     光线投射算法

光线投射法(Volume Ray Casting)可以直接从渲染方程(RenderingEquation)得到。这种技术可以提供非常高的成像质量,通常认为这是图像质量最高的方法。但由于此算法需要需要遍历每个体素,计算复杂度较高。为了提高算法的绘制速度,研究者先后提出了很多改进技术,如采用可以减少投射光线数量的自适应图形采样技术,以及可以减少不必要采样点的空间跳跃技术。

典型的光线投射法包含四个步骤,如下图:

基于VTK与Qt的体绘制程序_第1张图片

·       投射光线。对最终图像中的每个像素,投射一束沿着视线的光线穿过体数据。在这一阶段,通过将体数据看作被一个基本几何原素(通常是立方体)包围着,并利用这个几何原素的边界来截断投射的光线。

·       采样。沿着体数据内的一段视线,等距离地采样一组点。通常体数据没有与视线对齐在一直线上,因此要对所视线经过的采样点按其周围的体素值采样。这通常需要对采样点周围的体素进行三线性插值(Trilinearly Interpolate)。 

·       着色。先对每个采样点分别计算梯度。这些梯度代表了体数据中局部表面的方向。然后根据其方向与场景中的光源对采样点着色,即加上颜色与光照。

·       混合。在所有采样点都着色之后,沿着视线混合在一起,就得到当前正在处理的像素的最终颜色值。计算混合的方法是从绘制方程推导得到的,这类似于在投影仪上将幻灯片叠加在一起的效果。混合方法包括从后向前混合与从前向后混合两种。从后向前混合是从离观察者最远的采样点开始沿着视线向前混合,这样可以保证体数据中被遮蔽的部分不会影响最终得到的像素。

 

光线投射算法的更多细节,可参考:

体绘制(Volume Rendering)概述之3:光线投射算法(Ray Casting)原理和注意要点

http://blog.csdn.net/liu_lin_xm/article/details/4850609

体绘制(Volume Rendering)概述之4:光线投射算法(Ray Casting)实现流程和代码

http://blog.csdn.net/liu_lin_xm/article/details/4850630

GPU raycasting tutorial

http://www.daimi.au.dk/~trier/?page_id=98

1.4     基于VTKQt的体绘制程序

以下是本文作者最近写的一个基于VTKQt的体绘制程序:

https://bitbucket.org/lsz/volume-renderer/

源代码在VolumeRenderer目录下。数据文件在data目录下。更多信息见readme.txt

这个程序使用了VTK的vtkMetaImageReader和vtkSmartVolumeMapper来分别读取和绘制体数据。程序中还是用了部分来自CTK (The Common Toolkit, http://www.commontk.org/)的控件。开源的体绘制软件3D Slicer (http://www.slicer.org/)中也用到了这些CTK控件。

这个程序的Qt主窗口只放了几个布局(Layout),CTK控件和VTK控件都在主窗口的构造函数中通过代码添加。下载代码之后用CMake编译生成Visual Studio项目文件,然后用Visual Studio打开。Cmake配置文件CMakeLists.txt在VolumeRenderer目录下。


以下是程序中用于读取体数据的代码。

// read Meta Image (.mhd or .mha) files

auto reader =vtkSmartPointer<vtkMetaImageReader>::New();

reader->SetFileName(filename_str);

这里采用了vtkMetaImageReader类来读取UNC Meta Image格式的体数据头文件。UNC Meta Image格式的说明,可参考vtkMetaImageReader的类描述:

http://www.vtk.org/doc/release/6.1/html/classvtkMetaImageReader.html

上面的auto关键字是C++11标准的类型推导,编译器自动根据赋值表达式的类型来确定需要声明的变量类型。

vtkSmartPointerVTK的智能指针,会自动维护所管理指针的引用计数。当智能指针析构时如果其所管理的指针的引用计数为零,则释放其管理的指针指向的内存。C++11标准的std::shared_ptr以及Qt中的QSharedPointer也是类似的智能指针。不同的是,vtkSmartPointer专门用于VTK类(继承自vtkObjectBase的类),而std::shared_ptrQSharedPointer则是通用的智能指针。

以下是程序中选择体绘制算法的代码。

// The mapper that renders the volume data.

auto volumeMapper =vtkSmartPointer<vtkSmartVolumeMapper>::New();

volumeMapper->SetRequestedRenderMode(vtkSmartVolumeMapper::GPURenderMode);

volumeMapper->SetInputConnection(shiftScale->GetOutputPort());

 

这里采用了vtkSmartVolumeMapper类,并将其绘制模式设置为vtkSmartVolumeMapper::GPURenderMode。在此GPU绘制模式下,vtkSmartVolumeMapper实际上使用vtkGPUVolumeRayCastMapper类来进行基于GPU的体绘制。

基于VTK与Qt的体绘制程序_第2张图片

基于VTK与Qt的体绘制程序_第3张图片

窗口右边的控件是CTKwww.commontk.org)库中的ctkVTKVolumePropertyWidget体数据属性控件。这个控件可用于设置VTKvtkPiecewiseFunction(对应窗口右上方的控件)与vtkColorTransferFunction(对应窗口右下方的控件)。vtkPiecewiseFunctionvtkColorTransferFunction这两个类是VTK中用于指定传递函数的类。通过ctkVTKVolumePropertyWidget控件,我们就可以手动调节传递函数,从而探究体数据中我们感兴趣的信息。

此程序在VisualStudio 2012中编写,使用了VTK 6.0Qt 4库,项目通过CMake来配置。编译方法,首先通过CMake生成Visual Studio项目文件,然后以Visual Studio打开生成的项目文件,编译并运行其中的VolumeRenderer项目。

VTKQt开发的更多信息,可参考

基于VTKQt应用程序开发

http://blog.csdn.net/www_doling_net/article/details/8668870

 

你可能感兴趣的:(基于VTK与Qt的体绘制程序)