5、VTK在图像处理中的应用
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在图像处理中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C 中的static关键字
- 下一篇: vtkImageData基本操作