在读取了医学图像数据后,下一步就需要将它显示出来和进行交互操作。将3D的医学图像以2D的方式呈现,同时切换切片来帮助医学分析。
vtkImageViewer2
一个方便易用的2D图像显示类,它封装了vtkRenderWindow, vtkRender, vtkImageActor和vtkImageMapToWinowLevelColors。同时,包含了一个vtkInteractorStyleImage的交互方式,使得显示和交互变得更加简单。
3D医学图像有很多,不仅只有CT,还有MRI,超声波,X-光等,各具有独特的诊断优势。下面以CT图像数据作为示例。
读取数据
DICOM图像可以使用itk读取,当然vtk也提供了读取类vtkDICOMImageReader。
1 2 3
| auto reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName(argv[1]); reader->Update();
|
设置imageViewer
可以设置slice,3维数据的方向,以及窗口大小、窗宽、窗位等等。
1 2 3 4 5 6 7 8 9 10
| auto imageViewer = vtkSmartPointer<vtkImageViewer2>::New(); imageViewer->SetInputConnection(reader->GetOutputPort());
auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); imageViewer->SetupInteractor(interactor); imageViewer->SetSize(400, 400); imageViewer->SetColorLevel(500); imageViewer->SetColorWindow(1000); imageViewer->SetSliceOrientationToXY(); imageViewer->GetRenderer()->SetBackground(1, 1, 1);
|
设置交互方式
1 2 3
| auto myStyle = vtkSmartPointer<myVtkInteractorStyleImage>::New(); myStyle->SetImageViewer(imageViewer); interactor->SetInteractorStyle(myStyle);
|
自定义交互方式
vtkInteractorStyleImage是默认方式,我们为了通过鼠标滚轮来切换slice,自定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| class myVtkInteractorStyleImage : public vtkInteractorStyleImage { public: static myVtkInteractorStyleImage* New(); vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage);
protected: vtkImageViewer2* ImageViewer; int Slice; int MinSlice; int MaxSlice;
public: void SetImageViewer(vtkImageViewer2* imageViewer) { this->ImageViewer = imageViewer; this->MinSlice = imageViewer->GetSliceMin(); this->MaxSlice = imageViewer->GetSliceMax(); this->Slice = (this->MinSlice + this->MaxSlice) / 2; this->ImageViewer->SetSlice(this->Slice); this->ImageViewer->Render(); }
protected: virtual void OnMouseWheelForward() { if (this->Slice < this->MaxSlice) { this->Slice += 1; this->ImageViewer->SetSlice(this->Slice); this->ImageViewer->Render(); } }
virtual void OnMouseWheelBackward() { if (this->Slice > this->MinSlice) { this->Slice -= 1; this->ImageViewer->SetSlice(this->Slice); this->ImageViewer->Render(); } } };
vtkStandardNewMacro(myVtkInteractorStyleImage);
|
效果
脑部CT图像
DisplayDICOMSeries. cxx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #include "vtkSmartPointer.h" #include "vtkObjectFactory.h" #include "vtkRenderWindow.h" #include "vtkGenericRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkActor.h"
#include "vtkDICOMImageReader.h" #include "vtkImageViewer2.h" #include "vtkInteractorStyleImage.h"
class myVtkInteractorStyleImage : public vtkInteractorStyleImage { public: static myVtkInteractorStyleImage* New(); vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage);
protected: vtkImageViewer2* ImageViewer; int Slice; int MinSlice; int MaxSlice;
public: void SetImageViewer(vtkImageViewer2* imageViewer) { this->ImageViewer = imageViewer; this->MinSlice = imageViewer->GetSliceMin(); this->MaxSlice = imageViewer->GetSliceMax(); this->Slice = (this->MinSlice + this->MaxSlice) / 2; this->ImageViewer->SetSlice(this->Slice); this->ImageViewer->Render(); }
protected: virtual void OnMouseWheelForward() { if (this->Slice < this->MaxSlice) { this->Slice += 1; this->ImageViewer->SetSlice(this->Slice); this->ImageViewer->Render(); } }
virtual void OnMouseWheelBackward() { if (this->Slice > this->MinSlice) { this->Slice -= 1; this->ImageViewer->SetSlice(this->Slice); this->ImageViewer->Render(); } } };
vtkStandardNewMacro(myVtkInteractorStyleImage);
int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Usage: " << argv[0] << " DicomDirectory" << std::endl; return EXIT_FAILURE; }
auto reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName(argv[1]); reader->Update();
auto imageViewer = vtkSmartPointer<vtkImageViewer2>::New(); imageViewer->SetInputConnection(reader->GetOutputPort());
auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); imageViewer->SetupInteractor(interactor); imageViewer->SetSize(400, 400); imageViewer->SetColorLevel(500); imageViewer->SetColorWindow(1000); imageViewer->SetSliceOrientationToXY(); imageViewer->GetRenderer()->SetBackground(1, 1, 1);
auto myStyle = vtkSmartPointer<myVtkInteractorStyleImage>::New(); myStyle->SetImageViewer(imageViewer); interactor->SetInteractorStyle(myStyle);
imageViewer->Render(); imageViewer->GetRenderer()->ResetCamera(); imageViewer->Render();
interactor->Start();
return EXIT_SUCCESS; }
|
Example Download
Reference
VTKExamples/Cxx/IO/ReadDICOMSeries