1.前言
VTK應用程序所需的數據可以通過兩種途徑獲取: 第一種是生成模型 ;第二種是從外部存儲介質里導入相關的數據文件,(如vtkBMPReader讀取 BMP圖像) 。VTK 也可以將程序中處理完成的數據寫入單個文件中, 或者將所渲染的場景導出。從可視化管線的角度來看,一般以數據的讀取 (或由模型創建數據)開始,而以數據的寫盤操作(或 Mapper)結束。
前面我們已經接觸到了 VTK的 Reader類,將數據導入可視化管道的流程:
- 實例化 Reader對象;
- 指定所要讀取的文件名;
- 調用 Update()方法促使管線執行。當管線后續的 Fiter有 Update0請求時,如調用Render()方法管線就會讀取相應的圖像文件, 所以這一步可省略 。
類似地, 使用 Writer類的主要步驟如下:
- 實例化 Writer對象;
- 輸入要寫盤的數據以及指定待寫盤的文件名;
- 調用 Write()方法促使 Writer類開始寫盤操作。
2.vtkImageData類
圖像數據在 VTK 中是用vtkImageData類表示的,對於不同的圖像文件類型, VTK提供相對應的類對圖像文件進行讀寫操作。比如,前面章節中所提的vtkBMPReader是用於讀取 BMP圖像, vtkJPEGReader用於讀取 JPG圖像。 VTK除了支持 BMP、 JPG圖像格式之外,還支持其他多種圖像格式的讀寫。例如:
注意:1.值得注意的是vtkImageReader/vtkImageWriter用於讀寫RAW格式的數據(即俗稱的“裸數據”) ,該類型的圖像沒有文件信息,因此在讀取此類圖像時,需要指定圖像各個維度的大小、字節順序(是大端字節序還是小端字節序)、存儲像素値的類型等信息,只有指定這些信息、,類vtkImageReader才能正確讀取圖像。2.類vtkDicomImageReader可用於讀取DICOM圖像,但該類的功能很不完善,雖然VTK 最初是因醫學圖像可視化而誕生。但VTK對DICOM圖像的讀寫操作卻很不支持,比如該類不支持多幀DICOM圖像的讀取,而且VTK 也沒有實現對 DICOM圖像的寫操作, 即沒有提供類vlkDlCOMlmageWriter。對 DICOM圖像支持較好的函數庫主要有 GDCM和 DCMTK。著名的醫學圖像分割與配准工具包 ITK 就是封裝了 GDCM函數庫進行 DICOM圖像的讀寫。
3.單幅圖像的讀寫
1 #include <vtkAutoInit.h>
2 VTK_MODULE_INIT(vtkRenderingOpenGL); 3
4 #include <vtkSmartPointer.h>
5 #include <vtkPNGReader.h>
6 #include <vtkImageViewer2.h>
7 #include <vtkRenderWindowInteractor.h>
8 #include <vtkJPEGWriter.h>
9 #include <vtkRenderer.h> //定義了Camera
10
11 int main() 12 { 13 //讀取PNG圖像
14 vtkSmartPointer<vtkPNGReader> pngread =
15 vtkSmartPointer<vtkPNGReader>::New(); 16 pngread->SetFileName("logo.png"); 17 //顯示該幅圖像
18 vtkSmartPointer<vtkImageViewer2> ImageViewer =
19 vtkSmartPointer<vtkImageViewer2>::New(); 20 ImageViewer->SetInputConnection(pngread->GetOutputPort()); 21
22 vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInter =
23 vtkSmartPointer<vtkRenderWindowInteractor>::New(); 24 ImageViewer->SetupInteractor(renderWindowInter); 25 ImageViewer->Render(); 26 ImageViewer->GetRenderer()->ResetCamera(); 27 ImageViewer->Render(); 28
29 //寫圖像
30 vtkSmartPointer<vtkJPEGWriter> writer =
31 vtkSmartPointer<vtkJPEGWriter>::New(); 32 writer->SetFileName("VTK-logo.jpg"); 33 writer->SetInputConnection(pngread->GetOutputPort()); 34 writer->Write(); 35
36 renderWindowInter->Start(); 37 }
該段代碼先使用vtkPNGReader讀入 PNG圖像,然后用VTK 窗口顯示讀取的 PNG圖像,最后使用類vtkJPEGWriter將讀入的文件寫成JPG圖像。程序中使用 SetFileName方法設置要讀寫的圖像名, 在寫文件操作時要調用方法 Write方法才會將內存中的數據寫入到存儲介質中。
可能我們會感覺到很奇怪,數據管線已經鋪設好了,可是我們是怎么樣實現引擎渲染的呢?已到最后完成了與Windows操作系統完成了交互?在顯示圖像時並沒有用到,vtkRenderWindow、 vtkRenderer、 vtkActor等類,而只是使用了vtkImageViewer2以及設置了交互樣式。其實, VTK 可視化管線相關的幾個類都已經封裝在vtkImageViewer2 里。vtkImageViewer2主要是針對二維圖像(特別是醫學圖像)顯示設計的,實現了圖像縮放、轉、平移、窗寬窗位調節等功能: 除了可以用於單幅二維圖像的顯示之外, 也可以顯示三維圖像的某個切片, 還可以設置不同的顯示方向。
4.讀取序列圖像文件
醫學圖像應用程序中常常會處理序列的圖像文件,比如計算機斷層成像或者磁共振成像所成圖像一般都是由多個有順序的二維圖像組成, 應用程序需要一次性導入一個序列的二維圖像。VTK沒有提供專門的類讀取序列圖像文件,但是VTK的圖像Reader類都有提供方法SetFileNames()來設置多個圖像文件名,利用該方法可以實現序列圖像的讀取。
1 #include <vtkAutoInit.h>
2 VTK_MODULE_INIT(vtkRenderingOpenGL); 3
4 #include <stdio.h>
5 #include <vtkSmartPointer.h>
6 #include <vtkStringArray.h>
7 #include <vtkJPEGReader.h>
8 #include <vtkImageViewer2.h>
9 #include <vtkRenderWindowInteractor.h>
10 #include <vtkRenderer.h>
11
12 int main() 13 { 14 //生成文件序列組名
15 vtkSmartPointer <vtkStringArray> fileArray =
16 vtkSmartPointer <vtkStringArray>::New(); 17 char fileName[128]; 18 for(int i=1; i<100; i++) 19 { 20 sprintf(fileName,"Head/head%03d.jpg",i); 21 vtkstd::string fileStr(fileName); 22 fileArray->InsertNextValue(fileStr); 23 } 24 //讀取JPG序列圖像
25 vtkSmartPointer <vtkJPEGReader> reader =
26 vtkSmartPointer <vtkJPEGReader>::New(); 27 reader->SetFileNames(fileArray); 28
29 //顯示
30 vtkSmartPointer<vtkImageViewer2> viewer =
31 vtkSmartPointer<vtkImageViewer2>::New(); 32 viewer->SetInputConnection(reader->GetOutputPort()); 33 vtkSmartPointer<vtkRenderWindowInteractor> interact =
34 vtkSmartPointer<vtkRenderWindowInteractor>::New(); 35 //默認選擇第50張切片
36 viewer->SetSlice(50); 37 //viewer->SetSliceOrientationToXY();
38 viewer->SetSliceOrientationToXZ(); 39 //viewer->SetSliceOrientationToYZ();
40 viewer->SetupInteractor(interact); 41 viewer->Render(); 42
43 interact->Start(); 44 return 0; 45 }
程序中使用 vtkStringArray生成文件名列表, 然后調用 vtkJPEGReader的方法。SetFileNames()設置符讀取的序列圖像的文件名 。初始顯示該序列圖像的第50個切片,顯示的方向為 SetSliceOrientationToXY()。
還可以使用 Reader類里的 SetFilePrefix()和 SetFilePattem()等方法讀取序列圖像。