1.vtkVolume
vtkVolume類似於幾何渲染中的vtkActor,用於表示渲染場景中的對象。除了存儲基本變換信息(平移、旋轉、縮放等),其內部還存儲了兩個重要對象。這兩個對象分別是vtkAbstractVolumeMapper對象和vtkVolumeProperty對象。
1.1 void SetMapper(vtkAbstractVolumeMapper* mapper);
該函數用於連接vtkAbstractVolumeMapper對象,並根據不同的體繪製算法獲取其內部生成的圖元數據。具體的體繪製Mapper如下所示:
1.2 void SetProperty(vtkVolumeProperty* property)
該函數用於設置VTKVolumeProperty對象。其中vtkVolumeProperty用來設置體繪製的顏色、不透明度函數、陰影等信息。在體繪製中,顏色和不透明度設置至關重要,決定了最終的顯示結果。
2.VTKVolumeProperty——不透明度傳輸函數
不透明度傳輸函數是一個分段線性標量映射函數,利用該函數可將光線投影過程中的採樣點灰度值映射爲不同的不透明度值,已決定最終顏色值。一個標準的不透明度設置代碼如下:
//添加灰度不透明度屬性 vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity->AddPoint(70, 0.0); compositeOpacity->AddPoint(90, 0.4); compositeOpacity->AddPoint(180, 0.6); volumeProperty->SetScalarOpacity(compositeOpacity);
VTKVolumeProperty類中通過如下函數設置和獲取不透明度函數:
void SetScalarOpacity(vtkPiecewiseFuntion* function); vtkPiecewiseFunction* GetScalarOpacity(int Index);
vtkPiecewiseFunction類定義標量線性分段函數,其支持兩種設置方式,第一種方式是直接添加斷點;第二種是直接添加一條線段,即添加兩個斷點。
2.1 直接添加斷點
該函數驅動如下:
int AddPoint(double x,double y);
第一個參數x爲自變量,這裏是指灰度值;y則是映射值,這裏指不同明度。執行成功後,返回當前添加的斷點的index索引值(從0開始),否則返回-1.
2.2 直接添加一條線段
其核心就是添加兩個斷點。其函數設置如下:
void AddSegment(double x1,double y1,double x2, double y2);
添加兩個斷點(x1,y1)/(x2,y2),組成一條線段。注意添加一條線段時,如果改線段內已經存在斷點,則該斷點會被清除。如果採用這種方式設置不透明度傳輸函數,則上面代碼要重寫爲:
compositeOpacity->AddSegment(70, 0, 90, 0.4); compositeOpacity->AddSegment(90, 0.4, 180, 0.6); compositeOpacity->AddSegment(180, 0.6, 255, 1.0); volumeProperty->SetScalarOpacity(compositeOpacity)
2.3 刪除斷點操作
vtkPiecewiseFunction類中也包括了刪除斷點函數。具體如下:
int RemovePoint(double x); //將自變量值爲x的斷點刪除;
void RemoveAllPoints(); //刪除所有斷點;
2.4 實際意義
上面代碼中設置了三個不透明度斷點(70,0.00)、(90,0.40)、(180,0.60)。其意義是,當灰度值小於70時,不透明導讀應設置爲0;當灰度值介於70~90時,通過線性映射到0.0~0.40之間;當灰度值介於90~180時,現行映射至0.40~0.60;當灰度值大於180度時,不透明度映射到0.60~1.00的一個值。如果圖像的灰度範圍爲0~255,那麼上述代碼利用三個斷點將整個灰度範圍分爲四段處理。
2.5 Clamping標誌vtkPiecewiseFunction中有個Clamping標誌,當Clamping標誌爲真時,對於小於所有斷點最小灰度值的灰度值,其映射爲最小灰度值斷點對應的映射值;對於大於所有斷點最大灰度值的灰度值,其映射值爲最大灰度值斷點對應的映射值。如下圖所示:
當Clamping標誌爲假時,所有位於斷點灰度值範圍之外的灰度對應映射值都爲零。如下圖所示:
3.不同不透明度傳輸函數對應的體繪製實驗
代碼如下:
#include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL); VTK_MODULE_INIT(vtkRenderingVolumeOpenGL); VTK_MODULE_INIT(vtkRenderingFreeType); VTK_MODULE_INIT(vtkInteractionStyle); #include <vtkSmartPointer.h> #include <vtkStructuredPointsReader.h> #include <vtkStructuredPoints.h> #include <vtkGPUVolumeRayCastMapper.h> #include <vtkVolumeProperty.h> #include <vtkPiecewiseFunction.h> #include <vtkColorTransferFunction.h> #include <vtkVolume.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkCamera.h> int main() { vtkSmartPointer<vtkStructuredPointsReader> reader = vtkSmartPointer<vtkStructuredPointsReader>::New(); reader->SetFileName("mummy.128.vtk"); reader->Update(); vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper1 = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New(); volumeMapper1->SetInputData(reader->GetOutput()); vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper2 = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New(); volumeMapper2->SetInputData(reader->GetOutput()); /****************************************************************/ vtkSmartPointer<vtkVolumeProperty> volumeProperty1 = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty1->SetInterpolationTypeToLinear(); //設置線性插值 volumeProperty1->ShadeOn();//開啓陰影功能 volumeProperty1->SetAmbient(0.4);//設置環境溫度係數 volumeProperty1->SetDiffuse(0.6);//設置漫反射係數 volumeProperty1->SetSpecular(0.2);//設置鏡面反射係數 vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity1 = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity1->AddPoint(70, 0.0); compositeOpacity1->AddPoint(90, 0.4); compositeOpacity1->AddPoint(180, 0.6); volumeProperty1->SetScalarOpacity(compositeOpacity1); //////////////////////// vtkSmartPointer<vtkVolumeProperty> volumeProperty2 = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty2->SetInterpolationTypeToLinear(); //設置線性插值 volumeProperty2->ShadeOn();//開啓陰影功能 volumeProperty2->SetAmbient(0.4);//設置環境溫度係數 volumeProperty2->SetDiffuse(0.6);//設置漫反射係數 volumeProperty2->SetSpecular(0.2);//設置鏡面反射係數 vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity2 = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity2->AddPoint(100, 0.0); compositeOpacity2->AddPoint(140, 0.4); compositeOpacity2->AddPoint(180, 0.6); volumeProperty2->SetScalarOpacity(compositeOpacity2); ///////////////////////////// vtkSmartPointer<vtkPiecewiseFunction> gradientOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New(); gradientOpacity->AddPoint(10, 0.0); gradientOpacity->AddPoint(90, 0.5); gradientOpacity->AddPoint(100, 1.0); volumeProperty1->SetGradientOpacity(gradientOpacity); volumeProperty2->SetGradientOpacity(gradientOpacity); vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New(); color->AddRGBPoint(0, 0, 0, 0); color->AddRGBPoint(64, 1.0, 0.52, 0.3); color->AddRGBPoint(190.0, 1.00, 1.00, 1.00); color->AddRGBPoint(220.0, 0.20, 0.20, 0.20); volumeProperty1->SetColor(color); volumeProperty2->SetColor(color); /****************************************************************/ vtkSmartPointer<vtkVolume> volume1 = vtkSmartPointer<vtkVolume>::New(); volume1->SetMapper(volumeMapper1); volume1->SetProperty(volumeProperty1); vtkSmartPointer<vtkVolume> volume2 = vtkSmartPointer<vtkVolume>::New(); volume2->SetMapper(volumeMapper2); volume2->SetProperty(volumeProperty2); ////////////// double View1[4] = { 0, 0, 0.5, 1 }; double View2[4] = { 0.5, 0, 1, 1 }; vtkSmartPointer<vtkRenderer> render1 = vtkSmartPointer<vtkRenderer>::New(); render1->AddVolume(volume1); render1->SetViewport(View1); render1->SetBackground(1, 1, 0); vtkSmartPointer<vtkRenderer> render2 = vtkSmartPointer<vtkRenderer>::New(); render2->AddVolume(volume2); render2->SetViewport(View2); render2->SetBackground(0, 1, 0); vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New(); rw->AddRenderer(render1); rw->AddRenderer(render2); rw->SetSize(640, 320); rw->SetWindowName("Differ Gray Opacity Function"); vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New(); rwi->SetRenderWindow(rw); render1->GetActiveCamera()->SetPosition(0, -1, 0); render1->GetActiveCamera()->SetFocalPoint(0, 0, 0); render1->GetActiveCamera()->SetViewUp(0, 0, 1); render1->GetActiveCamera()->Azimuth(30); render1->GetActiveCamera()->Elevation(30); render1->ResetCamera(); render2->SetActiveCamera(render1->GetActiveCamera()); rw->Render(); rwi->Start(); return 0; }
利用不透明度傳輸函數,可以有選擇的對圖像中的對象進行顯示。對於不想看到的圖像部分,只需將其對應的灰度範圍的不透明度映射爲0即可。下圖即爲該程序的輸出成果:
左視圖採用的不透明度設置參數如下:
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity1 = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity1->AddPoint(70, 0.0); compositeOpacity1->AddPoint(90, 0.4); compositeOpacity1->AddPoint(180, 0.6); volumeProperty1->SetScalarOpacity(compositeOpacity1);
右視圖採用的不透明度設置參數如下:
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity2 = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity2->AddPoint(100, 0.0); compositeOpacity2->AddPoint(140, 0.4); compositeOpacity2->AddPoint(180, 0.6); volumeProperty2->SetScalarOpacity(compositeOpacity2);