5、VTK在图像处理中的应用

图像是VTK中一个非常重要的数据。数字图像广泛应用于工业生产、生物医学、媒体娱乐、地质、气象等重要领域,数字图像处理具有重要的应用价值。我们在掌握了VTK的基本知识后,这一章着重讲解数字图像处理相关技术,学完本章你会觉得原来图像处理是如此简单!
5.1 VTK图像数据结构

数字图像文件内容由两个部分组成:图像头信息和数据。图像头信息定义了图像的基本信息,主要包括起点位置(Origin),像素间隔(space)和维数(dimension)。通过这三个参数即可以决定图像空间位置和规模。图像可以看做是空间中的一个规则网格,网格中的每个最小单元称之为一个像素(二维)或者体素(三维),这样网格在每个方向上的像素或者体素个数即为图像在该方向的维数。像素索引表示每个像素在图像网格中的位置,是图像内部的网格坐标。而在医学图像中,每个图像除了内部坐标外,还存在一个世界坐标。这个世界坐标依赖于成像设备。在医学图像中起点位置(Origin),像素间隔(space)和图像维数决定了世界坐标系。这样通过起点位置,像素间隔和像素索引即可计算每个像素的世界坐标位置。

图5.1图像结构和空间表示

如图5.1所示,该图表示一个4x2x3的图像,即图像的维数,每一个小球表示一个像素;而图像的原点为(5.1,10.0,6.5),两两像素之间的间隔表示像素间隔,每个方向的像素间隔为1.5,1.5,和1.8。

图像数据即为图像像素的像素值,一般采用一维数组来表示和存储。已知像素索引和图像维数下,即可计算每个像素对应的像素值。通常图像的像素值为一个标量,例如一般灰度图像;图像像素值也可以是一个向量,例如彩色图像;另外图像像素值还可以是张量,如梯度场图像。医学图像处理中大部分的图像都是灰度图像。

这里需要注意灰度图像的灰度值的数据类型,在一般的灰度图像处理中不需要考虑,因为其范围默认为0-255,可以采用一个unsigned char类型类表示。但是在医学图像处理中,256灰度级远远不能满足要求,因此灰度范围往往大于256级。常见的医学图像的像素数据类型为unsigned short,灰度范围为0-65536。另外,有时为了精度的考虑,也会使用int、float甚至double类型,因此需要格外注意。

通过前面的章节我们已经知道,在VTK中图像数据结构由vtkImageData类表示。利用vtkImageData,我们可以方便的创建、读写、和访问图像数据。下面我们以VTK图像创建为起点,一步步走进VTK图像处理的世界中来。
5.2 VTK图像创建
5.2.1图像源(Source)

VTK中内置了多个创建图像的Source,利用这些Source可以快速的创建图像,其中以vtkImageCanvasSource2D为代表。该Source功能是创建一个画布(空白图像),并提供了多种几何图形(点、线段、圆、矩形以及图像等)的绘制填充功能。下列代码显示了该source的使用方法。

1: vtkSmartPointer canvas =

2: vtkSmartPointer::New();

3: canvas->SetScalarTypeToUnsignedChar();

4: canvas->SetNumberOfScalarComponents(1);

5: canvas->SetExtent(0, 100,0, 100, 0, 0);

6:

7: canvas->SetDrawColor(0, 0,0, 0);

8: canvas->FillBox(0,100,0,100);

9:

10: canvas->SetDrawColor(255,0, 0, 0);

11: canvas->FillBox(20,40,20,40);

12: canvas->Update();

在上面代码片段中,首先定义了一个vtkImageCanvasSource2D的指针,然后设置画布的像素数据类型,像素成分数目和画布的大小。然后,在该画布中,利用FillBox绘制两个填充矩形,并通过SetDrawColor()来设置两个矩形的颜色。

图5.2 vtkImageCanvasSource2D绘图

除了vtkImageCanvasSource2D外,VTK中还提供了其他类似的source类来快速生成特定的图像,例如vtkImageEllipsoidSource,该类根据指定的中心,各个轴的半径来生成一个前景为椭圆(球)的二值图像;vtkImageGaussianSource类生成一副像素值服从高斯分布的图像;vtkImageGridSource用于生成网格线图像;vtkImageNoiseSource生成一个像素值为随机数的噪声图像;vtkImageSinusoidSource生成的图像像素值由正弦函数决定。
5.2.2直接创建图像

利用上述图像Source可以快速的生成特定的图像,不过相对来说,在实际应用中较少用到他们。VTK中可以手动生成图像,然后根据需要进行像素赋值。下面代码演示了怎样手动创建图像。

1: vtkSmartPointer img= vtkSmartPointer::New();

2: img->SetDimensions(10,10,10);

3: img->SetScalarTypeToUnsignedChar();

4: img->SetNumberOfScalarComponents(1);

5: img->AllocateScalars();

6:

7: unsigned char ptr = (unsignedchar)img->GetScalarPointer();

8: for(int i=0; i<10*10*10; i++)

9: {

10: *ptr ++ =i%256;

11: }

首先定义vtkImageData指针,然后指定图像的维数,而图像的原点和像素间隔则都是采用默认值,因此不需要设置。SetScalarTypeToUnsignedChar指定图像的每个像素值的数据类型为unsigned char,SetNumberOfScalarComponents则指定了每个像素值的数据成分为1,每个像素值为1个标量值,参数设置完毕后,调用AllocateScalars()分配内存,生成图像数据。图像生成后,默认所有像素值为0。可以通过访问图像数据数组来设置每个像素值,GetScalarPointer()即返回图像的数据数组(图像数据数组都采用一维数组),然后根据图像的大小,访问每个像素并为其赋值。生成的图像结果如图5.3所示。

图5.3 用VTK的类直接创建图像数据
5.3 图像显示
5.3.1vtkImageViewer2

在VTK早期版本中,提供了vtkImageViewer类来显示图像。随着版本的发展,目前使用vtkImageViewer2来代替vtkImageViewer实现图像的显示。vtkImageViewer2中封装了VTK图像显示的管线,包括vtkActor,vtkRender,vtkRenderWindow,vtkInteractorStypeImage等对象,可以方便的完成图像显示和交互。该类提供的主要交互操作有:图像放缩,窗宽窗位调节,并提供切片选择,切片方向设置接口,尤其适合三维图像的显示。下面代码说明了怎样使用vtkImageViewer2显示图像。

1: vtkSmartPointerreader =

2: vtkSmartPointer::New();

3: reader->SetFileName (“…\brain.mhd” );

4: reader->Update();

5:

6: vtkSmartPointer imageViewer =

7: vtkSmartPointer::New();

8: imageViewer->SetInputConnection(reader->GetOutputPort());

9: vtkSmartPointerrenderWindowInteractor =

10: vtkSmartPointer::New();

11: imageViewer->SetupInteractor(renderWindowInteractor);

12:

13: imageViewer->SetColorLevel(500);

14: imageViewer->SetColorWindow(2000);

15: imageViewer->SetSlice(40);

16: imageViewer->SetSliceOrientationToXY();

17: imageViewer->Render();

18:

19: renderWindowInteractor->Start();

这里为了更好的说明vtkImageViewer2功能,使用一副三维医学图像为例进行说明。首先使用vtkMetaImageReader读入一个mhd图像,然后定义一个vtkImageViewer2对象显示图像。第9和10行定义了一个vtkRenderWindowInteractor对象,并传递给vtkImageViewer2对象,用于完成鼠标、键盘等消息响应,便于进行图像的交互操作。接下来分别设置了四个参数,窗位(ColorLevel)、窗宽(ColorWindow)、切片(Slice)和切片方向(Orientation)。设置完毕后,运行程序,图像显示如下。另外,按下鼠标左键拖动鼠标,可以调节图像的窗宽窗位,从而显示不同灰度范围内容;按下鼠标右键拖动鼠标可以放缩图像。当然这些交互操作可以由用户根据需要自己定义vtkInteractorStyle子类,并响应相应的操作。

窗宽是CT图像上显示的CT值范围。一般显示器的灰度范围为256级,而X光图像的灰度范围则远远大于该范围,因此通过显示器显示时不能显示所有灰度级。因此需要窗宽来定义需要显示的灰度范围。当灰度值高于该范围的最大值时,均以白影显示;而低于该范围时均显示为黑色。增大窗宽,显示具有不同灰度值的组织结构增多,但是会降低组织之间的对比度。减小窗宽,则可视的不同灰度组织结构会减少,同时增大组织结构的对比度。

窗位是窗的中心位置。窗宽只是确定了CT图像灰度范围上的可视部分范围,还需要窗位来确定可视灰度范围的具体位置。同样的窗宽,会根据窗位的位置变化来显示不同的组织结构。比如,窗宽为200时,当窗位为100时,可视灰度范围为0至200;当窗位为500时,则可视灰度范围为400至600。当窗宽窗位确定以后,显示时底层会将可视灰度范围转换到256灰度级进行显示(参考图5.4)。

图5.4医学图像窗宽窗位示意图

而显示三维图像时,需要确定当前显示切片和方向。vtkImageViewer2提供了SetSlice()函数设置切片号,SetSliceOrientationToXY()则将切片的方向设置为垂直XY平面方向。此外还可以设置为垂直YZ或者XZ平面方向,其对应函数分别为SetSliceOrientationToYZ()和SetSliceOrientationToXZ()。默认情况下切片方向为垂直于XY平面即沿着Z轴方向,根据设置的切片号获取Z轴方向的具体切片进行显示。

切片(slice)与切面是三维图像比较常用的概念。尤其是在医学图像中,不同方向的切面都有特定的名字。矢状面(sagital)是沿着身体前后径所做的与地面垂直的切面;冠状面(coronal)是沿着身体左右径所做的与地面垂直的切面;而横断面(transverse/axial)是指横断身体与地面平行的切面。(图5.5所示)

图5.5 矢状面、冠状面和横断面示意图

设置切片的方向即是通过不同的方向来观察人体内部组织结构。因此,常见的医学图像可视化软件常常提供四个视图用来显示图像:横断面视图,矢状面视图,冠状面视图和三维视图。
5.3.2vtkImageActor

vtkImageActor是一个三维图像渲染Actor,通过纹理映射将图像映射到一个多边形上进行显示。使用vtkImageActor较vtkImageViewer2要复杂一些,需要建立完整的渲染管线:包括vtkImageActor,vtkRender,vtkRenderWindow,vtkRenderWindowInteractor管线。另外,作为图像二维浏览器,不需要在三维空间中进行旋转操作,因此还需要为vtkRenderWindow定义一个vtkInteractorStyleImage对象。下面给出vtkImageActor显示图像的示例(结果如图5.6所示)。

1: vtkSmartPointer reader=

2: vtkSmartPointer::New();

3: reader->SetFileName (“…\lena.bmp” );

4: reader->Update();

5:

6: vtkSmartPointerimgActor =

7: vtkSmartPointer::New();

8: imgActor->SetInput(reader->GetOutput());

9:

10: vtkSmartPointer renderer =

11: vtkSmartPointer::New();

12: renderer->AddActor(imgActor);

13: renderer->SetBackground(.4, .5, .6);

14:

15: vtkSmartPointer renderWindow =

16: vtkSmartPointer::New();

17: renderWindow->SetSize(500, 500);

18: renderWindow->AddRenderer(renderer);

19:

20: vtkSmartPointer renderWindowInteractor=

21: vtkSmartPointer::New();

22: vtkSmartPointer style =

23: vtkSmartPointer::New();

24:

25: renderWindowInteractor->SetInteractorStyle(style);

26: renderWindowInteractor->SetRenderWindow(renderWindow);

27: renderWindowInteractor->Initialize();

28:

29: renderWindowInteractor->Start();

上面代码中在读入图像后,依次建立vtkImageActor,vtkRender,vtkRenderWindow,vtkRenderWindowInteractor,并组装为管线。为了屏蔽旋转操作,建立vtkInteractorStyleImage对象,并通过renderWindowInteractor->SetInteractorStyle(style)设置交互对象。需要注意的是,vtkImageActor接收的图像vtkImageData数据类型必须为unsigned char类型,因此在显示之前,需要利用vtkImageCast将图像数据类型转换为unsigned char。

图5.6 使用vtkImageActor显示图像数据
5.3.3图像融合

上面两种方法都是在一个窗口中显示一个图像。但是在常见的医学处理软件中,经常会遇到在一个窗口中显示多个图像,这就会用到图像融合技术。图像融合是利用图像的alpha通道和不透明度来实现。VTK中vtkImageBlend实现图像的融合。

vtkImageBlend可以接收多个图像输入,输出为融合图像。输出图像的像素间隔、原点、范围(extent)以及像素组分个数与第一个图像一致。该类提供了两种融合模式,第一种是标准模式,也是默认的融合方式。其计算公式如下:

1:output<- input[0]

2:foreachinput i {

3:foreachpixel px {

4: r <- inputi(alpha)* opacity[i]

5: f <- (255 - r)

6: output(px) <- output(px) * f + input(px) *r

7:}

8:}

第二种是混合模式(Compound)。该模式下输出结果经过alpha/opacity不透明度的和做过归一化。另外还可以设置一个阈值,当alpha*opacity小于等于该阈值时会忽略该像素。其计算公式如下:

1:output<- 0

2:foreachpixel px {

3: sum <- 0

4: foreach input i {

5: r <- inputi(alpha)* opacity(i)

6: sum <- sum + r

7: if r > threshold {

8: output(px) <- output(px) + input(px) *r

9: }

10:}

11:output(px) <- output(px) / sum

12:}

下面代码说明了怎么融合图像并显示。代码中读入了一副灰度图像,并生成了一个二值图像;然后定义了vtkImageBlend对象,函数SetInput()设置两个图像作为输入。这里设置输入图像时,由于可以输入多个图像,因此需要给定图像的id号来设置输入。SetOpacity()用于设置对应id号的图像不透明度的大小,当不透明度为1.0时,为完全不透明。程序的执行结果如图5.7所示。

1: vtkSmartPointerreader =

2: vtkSmartPointer::New();

3: reader->SetFileName (“..\lena2.jpg” );

4: reader->Update();

5:

6: vtkSmartPointer imageSource =

7: vtkSmartPointer::New();

8: imageSource->SetNumberOfScalarComponents(1);

9: imageSource->SetScalarTypeToUnsignedChar();

10: imageSource->SetExtent(0, 512, 0, 512, 0, 0);

11: imageSource->SetDrawColor(0.0);

12: imageSource->FillBox(0, 512, 0, 512);

13: imageSource->SetDrawColor(255.0);

14: imageSource->FillBox(100,400,100,400);

15: imageSource->Update();

16:

17: vtkSmartPointer imageBlend =

18: vtkSmartPointer::New();

19: imageBlend->SetInput(0, reader->GetOutput());

20: imageBlend->SetInput(1, imageSource->GetOutput());

21: imageBlend->SetOpacity(0, 0.4);

22: imageBlend->SetOpacity(1, 0.6);

23: imageBlend->Update();

图5.7 VTK图像整合效果

==========欢迎转载,转载时请保留该声明信息==========
版权归@东灵工作室所有,更多信息请访问东灵工作室

教程系列导航:http://blog.csdn.net/www_doling_net/article/details/8763686

5、VTK在图像处理中的应用相关推荐

  1. 傅里叶变换在图像处理中的应用初步学习

    1 理解傅里叶变换在图像处理中的应用 一维傅里叶变换的作用对象是信号,信号是一维连续的:随着时间不断推移,信号强度的变换情况,可称为时域. 图像处理中的傅里叶变换的作用对象是二维矩阵.随着位置的不断改 ...

  2. 傅里叶变换在图像处理中的作用

    傅立叶变换在图像处理中非常的有用.因为不仅傅立叶分析涉及图像处理的很多方面,傅立叶的改进算法, 比如离散余弦变换,gabor与小波在图像处理中也有重要的分量. 印象中,傅立叶变换在图像处理以下几个话题 ...

  3. 寻找下一款Prisma APP:深度学习在图像处理中的应用探讨

    在9月23日到9月24日的MDCC 2016年中国移动者开发大会"人工智能与机器人"专场中,阿里云技术专家周昌进行了题为<寻找下一款Prisma APP:深度学习在图像处理中 ...

  4. 中blur函数_Comonad在图像处理中的应用

    前几天我回答了一个关于comonad的问题Monad和Comonad到底是什么东西?.其中有讲到comonad的应用例子,但都还不够直观和实用.后来找到一个Comonad在图像处理中的应用的例子,觉得 ...

  5. matlab在图像处理中的应用论文,MATLAB在数字图像处理中的应用

    摘要:数字图像处理是一门新兴技术,经过计算机硬件的快速发展,数字图像的实时处理已经成为可能,由于数字图像处理的各种算法的出现,这就使得其处理速度越来越快,能更好的为人们服务.数字图像处理是一种通过计算 ...

  6. 窗函数在图像处理中的应用

    窗函数在图像处理中的应用 1. 频谱混乱的三角函数图像 下图是一个45度倾斜的单一频率的余弦函数图像,请注意图中的边界都不是均匀过渡到外界的,全是不连续的跳变. 下面来看看这幅图的频谱会是什么样? 频 ...

  7. VTK/OpenGL中球坐标转直角坐标

    在球坐标中,表示一个点的位置用(r,  θ, φ),三个参数分别代表着半径,俯仰角和方位角. 在VTK/OpenGL中,空间坐标系为右手的直角坐标系,屏幕上的左右是x轴,上下是y轴,z轴则垂直于屏幕. ...

  8. 模糊数学在计算机方面的应用,模糊数学理论在图像处理中的应用

    摘要:用计算机来处理图片已成为计算机研究的一个重要方向,基于模糊数学的图像处理技术是计算机图像处理中的重要计算.图像本质上具有模糊性,因此模糊信息处理技术在图像处理中的使用有其必然性.提出一种基于模糊 ...

  9. 【图像识别】【读论文】模式识别方法概论模式识别及其在图像处理中的应用

    <模式识别及其在图像处理中的应用> 1.模式识别基本框架 一般认为,模式识别是通过具体的事物进行观测所得到的具有时间.空间分布的信息,模式所属的类别或同一类中模式的总体成为模式类,其中个别 ...

最新文章

  1. elasticsearch简单操作(二)
  2. word技巧 输入方框中带对勾的符号的快捷方式
  3. 从Q3财报看百度营销成长
  4. saleor设置braintree支付方式
  5. jquery-autocomplete 使用手册
  6. Leetcode--304. 二维区域和检索
  7. 优秀的基数统计算法——HyperLogLog
  8. panda python_12个很棒的Pandas和NumPy函数,让分析事半功倍
  9. pytorch的4种边界Padding方法--ZeroPad2d、ConstantPad2d、ReflectionPad2d、ReplicationPad2d
  10. php返回原界面,thinkphp实现登录后返回原界面
  11. Linux内核:进程上下文切换
  12. [SQLite]www.sqlite.org官网.NET最新版本所有内容下载
  13. txt转excel 处理数据
  14. html自动计时器,html计时器
  15. vscode 设置关键字高亮显示
  16. 用 Web 技术为 Safari 编写扩展
  17. 如何用计算机算工资,个人工资计算器避税
  18. 微信扫一扫中的js安全接口域名的配置
  19. 还在用百度查找资源?不要落后啦,5款出奇好用的资源网送给你!
  20. 【JS基础】JavaScript中的void 0

热门文章

  1. 录播软件开始麦克风应该打开还是关闭
  2. 3000块你请不到一个农民工,只能请到一个大学生
  3. ARMV7,ARMV8
  4. kmp模板(HD1711)
  5. HTTP权威指南记录 ---- HTTP概述
  6. Silverlight实用窍门系列:54.详解Silverlight中的矩阵变换MatrixTransform,实现其余各种变换【附带实例源码】...
  7. 2017-08-10 前端日报
  8. 通信大数据应用未来还有很大的想象空间
  9. rhel6 上udev的绑定
  10. keil5一点project就闪退