VTK医学图像处理(1)—— 创建与显示

前面的知识总结

vtkXXXSource:一组类派生自vtkPolyDataAlgorithm,它们输出的数据类型都是vtkPolyData,都些类都是VTK预定义好的图形模型。

接着,把vtkXXXSource的输出作为vtkPolyDataMapper的输入,Mapper的作用是将输入的数据转换为几何图元(点、线、多边形)进行渲染。

然后,实例化一个Actor对象。VTK渲染场景中**数据的可视化**表达是**通过vtkProp的子类负责**的。
通过Actor的方法SetMapper()可以设置对应的Mapper。

接着,实例化渲染窗口(renderWindow)、渲染器(Renderer)、交互器(Interactor)、交互类型(Style)等对象。
**渲染窗口**既是VTK窗口;可以通过渲染窗口的AddRenderer()将渲染器(Renderer)加入到渲染窗口里;
**交互器**则是用方法SetRenderWindow()给它指定交互的窗口;交互风格与交互器是用方法SetInteractorStyle()关联在一起;
若干个Actor对象可以用方法AddActor()加入到渲染器里渲染。
可以发现:这些对象之间头、尾相接,可以连成一条线结构,这就是VTK里非常重要的概念:VTK管线结构。

1. VTK图像数据结构
图像可以看做是空间中的一个规则网格,在医学图像中,每个图像有内部坐标和世界坐标(?)。

**内部坐标**:像素索引(每个像素在图像网格中的位置);
**世界坐标系三元素**:原点(Origin),像素间隔(space)和图像维数(dimension),如下图

在这里插入图片描述

**图像数据**:图像像素的像素值,由像素索引和图像维数计算可得
**像素值类别**:标量(e.g. 一般灰度图像),向量(e.g. 彩色图像),张量(e.g.梯度场图像)

医学图像处理中大部分的图像都是灰度图像,需要注意,在医学图像处理中,一般的unsigned char类型,256灰度级远远不能满足要求,常见的医学图像的像素数据类型为unsigned short,灰度范围为0-65536。

2. VTK图像创建
2.1 Source创建源图像
TK中内置了多个创建图像的Source,其中以vtkImageCanvasSource2D为代表,该Source功能是创建一个画布(空白图像),并提供了多种几何图形(点、线段、圆、矩形以及图像等)的绘制填充功能。

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include<vtkSmartPointer.h>
#include<vtkImageCanvasSource2D.h>
#include<vtkImageData.h>
#include<vtkImageActor.h>
#include<vtkRenderer.h>
#include<vtkRenderWindow.h>
#include<vtkRenderWindowInteractor.h>
#include<vtkInteractorStyleImage.h>
//#include < >引用的是编译器类库路径里面的头文件
//#include" " 引用的是程序目录的相对路径中的头文件
int main()
{
	vtkSmartPointer<vtkImageCanvasSource2D> canvas =
		vtkSmartPointer<vtkImageCanvasSource2D>::New();
	canvas->SetScalarTypeToUnsignedChar(); //设置画布的像素数据类型
	//SetNumberOfScalarComponents则指定了每个像素值的数据成分为1,每个像素值为1个标量值,
	canvas->SetNumberOfScalarComponents(1);
	canvas->SetExtent(0, 100, 0, 100, 0, 0);
	//利用FillBox绘制两个填充矩形,SetDrawColor()来设置两个矩形的颜色。
	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();  //这一步还必不可少! why? 数据流?
	
	//Mapper的作用是将输入的数据转换为几何图元(点、线、多边形)进行渲染。
	//创建演员  
	vtkSmartPointer<vtkImageActor> actor =
		vtkSmartPointer<vtkImageActor>::New();
	actor->SetInputData(canvas->GetOutput());
	//定义视窗
	double viewport[4] = { 0,0,1,1 }; //?
	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	//renderer->SetViewport(viewport); //?
	renderer->AddActor(actor);
	//renderer->ResetCamera();//?
	renderer->SetBackground(1.0, 1.0, 1.0);

	//设置渲染窗口(搬上舞台)
	vtkSmartPointer<vtkRenderWindow> renderwindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderwindow->AddRenderer(renderer);
	renderwindow->SetSize(640, 480);
	renderwindow->Render();//ask each renderer render its images
	renderwindow->SetWindowName("ImageCanvasSource2D");

	//设置窗口交互(演员-观众)
	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetInteractorStyle(style);
	rwi->SetRenderWindow(renderwindow);

	rwi->Initialize();
	rwi->Start();//循环前,必须先初始化	rwi->Initialize();

	return 0;
}

运行结果如下
在这里插入图片描述
2.2直接创建图像

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyle.h>

#include <vtkInformation.h>

int main()
{
	//vtk的新版本在vtkImageData类中取消了SetScalarTypeToUnsignedChar()方法;
	//现在仅能用如下方法设置:
	//static void SetScalarType(int, vtkInformation* meta_data);
	vtkSmartPointer<vtkImageData> img =
		vtkSmartPointer<vtkImageData>::New();
	vtkSmartPointer<vtkInformation> info =
		vtkSmartPointer<vtkInformation>::New();
	img->SetDimensions(16, 16, 1); //指定图像的维数,图像的原点和像素间隔都采用默认值
	//指定图像的每个像素值的数据类型为unsigned char
	img->SetScalarType(VTK_UNSIGNED_CHAR, info); //img->SetScalarTypeToUnsignedChar();
	//指定图像像素为标量
	img->SetNumberOfScalarComponents(1, info);//每个像素需要表示的组份 =1是指标量图
	//分配内存,生成图像数据
	img->AllocateScalars(info);//很重要
	//图像生成后,默认所有像素值为0,可以通过访问图像数据数组来设置每个像素值

	unsigned char* ptr = NULL;
	ptr = (unsigned char*)img->GetScalarPointer();
	//GetScalarPointer()即返回图像的数据数组(图像数据数组都采用一维数组)
	//然后根据图像的大小,访问每个像素并为其赋值:0-256
	for (int i = 0; i < 16 * 16 * 1; i++)
	{
		*ptr++ = (i+1000) % 256; //*ptr++ = i % 256; 
	}


	//创建演员
	vtkSmartPointer<vtkImageActor> actor =
		vtkSmartPointer<vtkImageActor>::New();
	actor->SetInputData(img); //actor->SetInputData(canvas->GetOutput());啥区别?

	//启动渲染引擎
	double viewport[4] = { 0,0,1,1 };
	vtkSmartPointer<vtkRenderer> render =
		vtkSmartPointer<vtkRenderer>::New();
	render->SetViewport(viewport);
	render->AddActor(actor);
	render->ResetCamera();
	render->SetBackground(1, 1, 1);

	//VTK窗口
	vtkSmartPointer<vtkRenderWindow> window =
		vtkSmartPointer<vtkRenderWindow>::New();
	window->AddRenderer(render);
	window->SetSize(640, 480);
	window->Render();
	window->SetWindowName("CreateVTKImageData");

	//交互
	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyle> style =
		vtkSmartPointer<vtkInteractorStyle>::New(); //??不可以直接设置为默认吗
	rwi->SetInteractorStyle(style);
	rwi->SetRenderWindow(window);

	rwi->Initialize();
	rwi->Start();

	return 0;
}


在这里插入图片描述
3 图像显示
3.1单幅图像的读写
外部存储介质里导入相关的数据文件,(如vtkBMPReader读取 BMP图像,vtkDicomImageReader可用于读取DICOM图像,vtkPNGReader 读取 PNG图像 )
在外部存储介质中存如入以下图片,图片名为 logo.png在这里插入图片描述
读取代码:

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkSmartPointer.h>
#include <vtkPNGReader.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkJPEGWriter.h>
#include <vtkRenderer.h> //定义了Camera

int main()
{
	//读取PNG图像
	vtkSmartPointer<vtkPNGReader> pngread =
		vtkSmartPointer<vtkPNGReader>::New();
	pngread->SetFileName("../logo.png"); //相对路径
	//显示该幅图像
	vtkSmartPointer<vtkImageViewer2> ImageViewer =
		vtkSmartPointer<vtkImageViewer2>::New();
	ImageViewer->SetInputConnection(pngread->GetOutputPort());

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInter =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	ImageViewer->SetupInteractor(renderWindowInter);
	ImageViewer->Render();
	ImageViewer->GetRenderer()->ResetCamera();
	ImageViewer->Render();

	renderWindowInter->Start();
}

读取成功后,如下:
在这里插入图片描述
如果要对图片进行写操作,使用 Writer类 进行以下步骤

  • 实例化 Writer对象;
  • 输入要写盘的数据以及指定待写盘的文件名;
  • 调用 Write()方法促使 Writer类开始写盘操作。
    在上面的代码 renderWindowInter->Start()之前加入以 下代码:
	//写图像
   vtkSmartPointer<vtkJPEGWriter> writer =
	vtkSmartPointer<vtkJPEGWriter>::New();
	writer->SetFileName("VTK-logo.jpg");
	writer->SetInputConnection(pngread->GetOutputPort());
	writer->Write();
	
	renderWindowInter->Start();

3.2 vtkImageViewer2
vtkImageViewer2中封装了VTK图像显示的管线,包括vtkActor,vtkRender,vtkRenderWindow,vtkInteractorStypeImage等对象,可以方便的完成图像显示和交互。
该类提供的主要交互操作有:图像放缩,窗宽窗位调节,并提供切片选择,切片方向设置接口,尤其适合三维图像的显示。

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);


#include <vtkSmartPointer.h>
#include <vtkMetaImageReader.h>
#include <vtkImageViewer2.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

int main(int argc, char* argv[])
{
	vtkSmartPointer<vtkMetaImageReader> reader =
		vtkSmartPointer<vtkMetaImageReader>::New();
	reader->SetFileName("../brain.mhd");
	reader->Update();

	vtkSmartPointer<vtkImageViewer2> viewer =
		vtkSmartPointer<vtkImageViewer2>::New();
	viewer->SetInputConnection(reader->GetOutputPort());

	//设置基本属性
	viewer->SetSize(640, 480);
	viewer->SetColorLevel(500);
	viewer->SetColorWindow(2000);
	viewer->SetSlice(40);
	viewer->SetSliceOrientationToXZ();//viewer->SetSliceOrientationToYZ();//viewer->SetSliceOrientationToXY();横断面
	viewer->Render();
	viewer->GetRenderer()->SetBackground(1, 1, 1);
	viewer->GetRenderWindow()->SetWindowName("ImageViewer2D");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();

	//设置交互属性
	viewer->SetupInteractor(rwi);

	rwi->Start();


}

其中也设置了四个参数,窗位(ColorLevel)、窗宽(ColorWindow)、切片(Slice)和切片方向(Orientation)。了解磁共振图像的窗宽窗位按下鼠标左键拖动鼠标,可以调节图像的窗宽窗位,从而显示不同灰度范围内容;
:有一点,在教材中没有强调,要生成.mhd 还需要有一个 .raw文件,这个数据可以在
brain.mhd 付积分下载

在这里插入图片描述
显示三维图像时,需要确定当前显示切片和方向, 形象的说,修改上面的viewer->SetSliceOrientationToXY();为viewer->SetSliceOrientationToYZ();和 viewer->SetSliceOrientationToXZ();可以分别获得大脑的失状面、冠状面,如下:
在这里插入图片描述
在这里插入图片描述
参考文献:
VTK修炼之道14:图像处理_创建
VTK修炼之道15:图像处理_显示(vtkImageViewer2 & vtkImageActor)
05-VTK在图像处理中的应用(1)

发布了17 篇原创文章 · 获赞 5 · 访问量 5160

猜你喜欢

转载自blog.csdn.net/Emily_Buffy/article/details/96459125
今日推荐