4.1 Reader与Writer类
要将外部数据读入可视化管线,主要步骤如下:
1)实例化Reader对象; 2)指定要读取的文件名; 3)调用Update()方法促使管线执行,当管线后续的Filter有Update()请求时,如调用Render()方法管线就会读取相应的图像文件。
Writer类主要步骤:
1)实例化Writer对象; 2)输入要写盘的数据以及指定待写盘的文件名; 3)调用Write(方法促使Writer类开始写盘操作。
4.1.1 vtkImageData类
图像数据在VTK中是用vtkImageData类表示的,对于 不同的图像文件类型,VTK提供相应的类对图像文件进行读写操作。
注意:1)vtkImageReader/vtkImageWriter 用于读写RAW格式的数据(即俗称的“裸数据”)。该类型的图像没有文件信息,因此在读取此类图像时,需要指定图像各个维度的大小、字节顺序(是大端字节序还是小端字节序)、存储像素值的类型等信息,只有指定这些信息,类vtkImageReader才能正确读取图像。
2)如果要读取RAW格式的图像文件,可以用类vtkMetalmageReader,该类可以读扩展名为“*.mha”和“*.mhd”的图像。
3)类vtkDicomImageReader可用于读取DICOM图像,DICOM(*.dcm)图像是医学图像处理中使用最广泛的格式,但该类功能很不完善。该类不支持多帧DICOM图像的读取,VTK也没有实现对DICOM图像的写操作。对DICOM图像的读写支持较好的函数库主要有GDCM和DCMTK。DCMTK是目前对DICOM协议支持最全的工具包,同时也是读写DICOM图像的专业函数库。
1.读写单个图像文件
#include <vtkSmartPointer.h>
#include <vtkPNGReader.h>
#include <vtkImageViewer2.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkJPEGWriter.h>
int main() {
// 读取PNG图像
vtkSmartPointer<vtkPNGReader> reader =
vtkSmartPointer<vtkPNGReader>::New();
reader->SetFileName("D:\\1.png");
// 显示读取的单幅PNG图像
vtkSmartPointer<vtkImageViewer2> imageViewer =
vtkSmartPointer<vtkImageViewer2>::New();
imageViewer->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
imageViewer->SetupInteractor(interactor);
imageViewer->Render();
imageViewer->GetRenderer()->ResetCamera();
//imageViewer->GetRenderer()->ResetCamera();
imageViewer->Render();
// 保存成JPG
vtkSmartPointer<vtkJPEGWriter> writer =
vtkSmartPointer<vtkJPEGWriter>::New();
writer->SetFileName("VTK-logo.jpg");
writer->SetInputConnection(reader->GetOutputPort());
writer->Write();
interactor->Start();
return 0;
}
注意:1)在写文件操作时要调用Writer()才会将内存中的数据写入存储介质中;
2)VTK可视化管线相关的几个类都已经封装在vtkImageViewer2, vtkImageViewer2主要针对二维图像显示设计,实现了图像的缩放、旋转、平移、窗宽窗位调节等功能,除了用于单幅二维图像显示外,也可以用于三维图像某个切片,还可以设置不同的显示方向。
3)在读取文件时,如果不能确定所读取的图像是什么格式,可以用类vtkImageReader2Factory来读取要导入的文件,该类会试着寻求一种最合适的类对图像做读取操作。
2.读取序列图像文件
示例中使用vtkStringArray生成文件名列表,然后调用vtkJPEGReader的方法SetFileNames()设置待读取得序列图像的文件名。
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>
#include <vtkStdString.h>
#include <vtkJPEGReader.h>
#include <vtkImageViewer2.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkJPEGWriter.h>
int main() {
// 生成图像序列的文件名数组
vtkSmartPointer<vtkStringArray> fileArray =
vtkSmartPointer<vtkStringArray>::New();
char fileName[128];
for (int i = 0; i < 100; i++)
{
sprintf(fileName, "D://data//Head/head%03d.jpg", i);
vtkStdString::StdString fileStr(fileName);
fileArray->InsertNextValue(fileStr);
}
// 读取JPG序列图像
vtkSmartPointer<vtkJPEGReader> reader =
vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileNames(fileArray);
// 显示读取的单幅PNG图像
vtkSmartPointer<vtkImageViewer2> imageViewer =
vtkSmartPointer<vtkImageViewer2>::New();
imageViewer->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
imageViewer->SetSlice(50); //默认显示第50个切片(即第50层)
imageViewer->SetSliceOrientationToXY();
/*imageViewer->SetSliceOrientationToYZ();
imageViewer->SetSliceOrientationToXZ();*/
imageViewer->SetupInteractor(interactor);
imageViewer->Render();
interactor->Start();
return 0;
}
还可以使用SetFilePrefix()和SetFilePattern()获取序列图像 ,SetFilePrefix()设置文件名的相同部分,SetFilePattern()设置文件名中序列变化部分。
下面示例是一张一张地读入,然后合并成三维数据体。
4.1.2 vtkPolyData类型
4.1.3 vtkRectilinearGrid类型
4.1.4 vtkStructuredGrid类型
4.1.5 vtkUnstructuredGrid类型
4.2 场景的导入与导出
场景的导入(Import)与导出(Export)是指将渲染场景中的对象,包括光照、相机、属性、变换矩阵等信息写入文件中,或者从外部文件中将这些对象导入渲染场景中,一般所导入的文件含有多个数据集。
Import类可以生成vtkRenderWindow和 vtkRenderer实例,用户也可以另外指定 vtkRenderWindow和 vtkRenderer对象。VTK中一般以关键字Importer 和Exporter命名的类是与场景的导入与导出相关的。Importer类可以导入由其他3D模型软件(如3DS MAX)所生成的模型文件;Exporter则可以将VTK里的场景生成可被其他3D模型软件所处理的文件。
VTK支持的Import类包括vtk3DSImporter和 vtkVRMLImporter;而支持的Exporter类则相对要多一些,主要有vtkRIBExporter、vtkGL2PSExporter、vtklVExporter、vtkOBJExporer、vtkOOGLExporter、vtkVRMLExporter、vtkPOVExporter、vtkX3DExporter等。