前言
“VTK图形图像开发进阶_张晓东_罗火灵”的学习笔记。
东灵工作室 教程系列导航:http://blog.csdn.net/www_doling_net/article/details/8763686
学习资料
VTK官网学习地址:https://vtk.org/doc/nightly/html/
学习笔记
VTK图像数据结构
数字图像文件内容由两个部分组成:图像头信息和数据。图像头信息定义了图像的基本 信息,主要包括起点位置、像素间隔和维数。通过这三个 参数即可确定图像空间位置和大小。在医学图像中,起点位置、像素间隔和图像维数决定了世界坐标系。这样通过起点位 置、像素间隔和像素索引可以算出每个像素的世界空间坐标系。
VTK图像创建
图像源Source
除了 vtkImageCanvasSource2D外,VTK还提供了其他类似的Source类来快速生成特定 的图像,例如vtklmageEllipsoidSource,该类根据指定的中心以及各个轴的半径来生成一个前景为椭圆(球)的二值图像;vtklmageGaussianSource类生成一幅像素值服从高斯分布的图像; vtklmageGridSource用于生成网格线图像:vtklmageNoiseSource生成一个像素值为随机数的噪 声图像;vtklmageSinusoidSource生成的图像像素值由正弦函数决定。
程序源码 绘制两个矩形
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
int main()
{
vtkSmartPointer<vtkImageCanvasSource2D> canvas =
vtkSmartPointer<vtkImageCanvasSource2D>::New();
canvas->SetScalarTypeToUnsignedChar();
canvas->SetNumberOfScalarComponents(1);
canvas->SetExtent(0, 100, 0, 100, 0, 0);
canvas->SetDrawColor(0, 0, 0, 0);
canvas->FillBox(0,100,0,100);
canvas->SetDrawColor(255, 0, 0, 0);
canvas->FillBox(20,40,20,40);
canvas->Update();
// Create actors
vtkSmartPointer<vtkImageActor> redActor =
vtkSmartPointer<vtkImageActor>::New();
redActor->SetInputData(canvas->GetOutput());
// Define viewport ranges
// (xmin, ymin, xmax, ymax)
double redViewport[4] = {0.0, 0.0, 1.0, 1.0};
// Setup renderers
vtkSmartPointer<vtkRenderer> redRenderer =
vtkSmartPointer<vtkRenderer>::New();
redRenderer->SetViewport(redViewport);
redRenderer->AddActor(redActor);
redRenderer->ResetCamera();
redRenderer->SetBackground(1.0, 1.0, 1.0);
// Setup render window
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(redRenderer);
renderWindow->SetSize( 640, 480 );
renderWindow->Render();
renderWindow->SetWindowName("ImageCanvasSource2D");
// Setup render window interactor
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style =
vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
// Render and start interaction
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
直接创建图像
在程序中对像素赋值
程序源码 设置一个渐变色灰度图像
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderWindow.h>
int main()
{
vtkSmartPointer<vtkImageData> img = vtkSmartPointer<vtkImageData>::New();
img->SetDimensions(16,16,1);
// img->SetScalarTypeToUnsignedChar();
// img->SetNumberOfScalarComponents(1);
// img->AllocateScalars();
//分配内存,第一个参数设置像素数据类型,第二个参数设置每个像素值的组分数。
//图像生成后,默认所有像素值为零
img->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
//调用AllocateScalars分配内存,生成图像数据。图像生成后,默认所 有像素值为0
//可以通过访问图像数据数组来设置每个像素值,vtklmageData:: GetScalarPointer() 即返回图像的数据数组
unsigned char *ptr = (unsigned char*)img->GetScalarPointer();
for(int i=0; i<16*16*1; i++)
{
*ptr ++ =i%256;
}
vtkSmartPointer<vtkImageActor> redActor =
vtkSmartPointer<vtkImageActor>::New();
redActor->SetInputData(img);
double redViewport[4] = {0.0, 0.0, 1.0, 1.0};
vtkSmartPointer<vtkRenderer> redRenderer =
vtkSmartPointer<vtkRenderer>::New();
redRenderer->SetViewport(redViewport);
redRenderer->AddActor(redActor);
redRenderer->ResetCamera();
redRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(redRenderer);
renderWindow->SetSize( 640, 480 );
renderWindow->Render();
renderWindow->SetWindowName("CreateVTKImageData");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style =
vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
VTK图像显示
窗宽/窗位的概念
窗宽是图像显示的灰度范围。
一般显示器的灰度范围为256级,而医学图像的灰度范围则远远大于该范围,因此通过显示器显示时不能显示所有灰度级,需要使用窗宽来定义欲显 示的灰度范围。当灰度值高于该范围的最大值时,均以白影显示:当低于该范围时,均以黑 色显示。若增大窗宽,则显示具有不同灰度值的组织结构增多,但是会降低组织之间的对比 度,若减小窗宽,则可视的不同灰度组织结构会减少,同时增大组织结构的对比度。
窗位是窗宽的中心位置。
比如,窗宽为200,当窗位为100时,可视灰度范围为。0〜200;当窗位为500时,可视灰度范围为400〜600。当窗宽窗位确定以后,显示时底层会将可视灰度范围 转换到256灰度级进行显示。
医学图像二维视图
切片(Slice)或切面是三维图像比较常用的概念,尤其在医学图像中,不同方向的切面 都有特定的名字(见图5-6),分别是:
矢状面(Sagital Plane),沿着身体前后径所做的与地 面垂直的切面;
冠状面(Coronal Plane),沿着身体左右径所做的与地面垂直的切面:
横断面 (Transverse/Axial Plane),是指横断身体与地面平行的切面。
设置切片的方向即是通过不同的 方向来观察人体内部组织结构。
vtkImageViewer2 显示二维图像
vtkImageViewer2 中封装了 VTK 图像 显示的可视化渲染引擎,包括 vtkActor、vtkRender, vtkRenderWindow> vtklnteractorStypelmage 等对象,可以方便地完成图像显示和交互。该类提供的主要交互操作有图像放缩、窗宽窗位调节,并提供切片选择及切片方向设置接口,尤其是三维图像的切片显示。
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkMetaImageReader.h>
//测试图像:../data/brain.mhd
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkMetaImageReader> reader =
vtkSmartPointer<vtkMetaImageReader>::New();
reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/brain.mhd");
reader->Update();
vtkSmartPointer<vtkImageViewer2> imageViewer =
vtkSmartPointer<vtkImageViewer2>::New();
imageViewer->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
imageViewer->SetupInteractor(renderWindowInteractor);
imageViewer->SetColorLevel(500); //设置窗位
imageViewer->SetColorWindow(2000); //设置窗宽
imageViewer->SetSlice(40); //切片索引
imageViewer->SetSliceOrientationToXY(); //切片方向垂直于XY平面:沿着Z轴方向,也是默认情况
imageViewer->Render();
imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
imageViewer->SetSize(640, 480);
imageViewer->GetRenderWindow()->SetWindowName("DisplayImageExample");
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
在渲染窗口中,按下鼠标左键拖动鼠标,可以调节图像的窗宽窗位,从而显示不同灰度 范围内容;按下鼠标右键拖动鼠标可以缩放图像。当然,这些交互操作可以由用户根据需要 自己定义vtklnteractorStyle子类,并响应相应的操作。
vtklmageActor
vtklmageActor是一个三维图像渲染Actor.通过纹理映射将图像映射到一个多边形上进行显示。
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkBMPReader.h>
#include <vtkImageActor.h>
//测试图像:../data/lena.bmp
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkBMPReader> reader =
vtkSmartPointer<vtkBMPReader>::New();
reader->SetFileName ( "C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena.bmp" );
reader->Update();
vtkSmartPointer<vtkImageActor> imgActor =
vtkSmartPointer<vtkImageActor>::New();
imgActor->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(imgActor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize( 640, 480 );
renderWindow->Render();
renderWindow->SetWindowName("DisplayImageExample2");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style =
vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
该例中使用 vtkBMPReader 读入图像后,依次建立 vtkImageActor、 vtkRender、vtkRenderWindow 和 vtkRenderWindowInteractor,并组装为渲染管线。然后建立 vtklnteractorStylelmage 对象,一通过renderWindowInteractor->SetInteractcrStyle(style)设置交互类型对象。需要注意vtklmageActor接收的图像数据vtklmageData像素类型必须为unsigned char,如果类型不符合要求,在显示图像前需要先将图像数据类型转换为unsigned char。
图像融合
图像融合是利用图像的不透明度来合成图像。在VTK中,用类vtklmageBlend实现图像的融合。
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageBlend.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkJPEGReader.h>
#include <vtkImageActor.h>
#include <vtkImageCast.h>
//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName ( "C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena-gray.jpg" );
reader->Update();
vtkSmartPointer<vtkImageCanvasSource2D> imageSource = vtkSmartPointer<vtkImageCanvasSource2D>::New();
imageSource->SetNumberOfScalarComponents(1);
imageSource->SetScalarTypeToUnsignedChar();
imageSource->SetExtent(0, 512, 0, 512, 0, 0);
imageSource->SetDrawColor(0.0);
imageSource->FillBox(0, 512, 0, 512);
imageSource->SetDrawColor(255.0);
imageSource->FillBox(100,400,100,400);
imageSource->Update();
vtkSmartPointer<vtkImageBlend> imageBlend = vtkSmartPointer<vtkImageBlend>::New();
imageBlend->AddInputData(reader->GetOutput());
imageBlend->AddInputData(imageSource->GetOutput());
imageBlend->SetOpacity(0, 0.4);
imageBlend->SetOpacity(1, 0.6); //1不透明
imageBlend->Update();
// Create actors
vtkSmartPointer<vtkImageActor> originalActor1 = vtkSmartPointer<vtkImageActor>::New();
originalActor1->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkImageActor> originalActor2 = vtkSmartPointer<vtkImageActor>::New();
originalActor2->SetInputData(imageSource->GetOutput());
vtkSmartPointer<vtkImageActor> blendActor = vtkSmartPointer<vtkImageActor>::New();
blendActor->SetInputData(imageBlend->GetOutput());
// Define viewport ranges
// (xmin, ymin, xmax, ymax)
double leftViewport[4] = {0.0, 0.0, 0.33, 1.0};
double midViewport[4] = {0.33, 0.0, 0.66, 1.0};
double rightViewport[4] = {0.66, 0.0, 1.0, 1.0};
// Setup renderers
vtkSmartPointer<vtkRenderer> originalRenderer1 = vtkSmartPointer<vtkRenderer>::New();
originalRenderer1->SetViewport(leftViewport);
originalRenderer1->AddActor(originalActor1);
originalRenderer1->ResetCamera();
originalRenderer1->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> originalRenderer2 = vtkSmartPointer<vtkRenderer>::New();
originalRenderer2->SetViewport(midViewport);
originalRenderer2->AddActor(originalActor2);
originalRenderer2->ResetCamera();
originalRenderer2->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> blendRenderer = vtkSmartPointer<vtkRenderer>::New();
blendRenderer->SetViewport(rightViewport);
blendRenderer->AddActor(blendActor);
blendRenderer->ResetCamera();
blendRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(originalRenderer1);
renderWindow->AddRenderer(originalRenderer2);
renderWindow->AddRenderer(blendRenderer);
renderWindow->SetSize( 640, 320 );
renderWindow->Render();
renderWindow->SetWindowName("ImageBlendExample");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}