三维图像切面提取
切片(Slice)或切面是三维图像比较常用的概念,尤其在医学图像中。通过提取切面可以方便地浏览和分析图像内部组织结构。VTK中vtkImageReSlice类可以实现图像切面的提取。在实际开发中,四视图中冠状视面、矢状面和横断面(显示过图像内部一点且平行于XY、YZ、XZ平面的平面),需要用到此类。
示例说明
CMakeLists.txt文件代码如下:
1 CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 PROJECT(ImageResliceExample) 3 FIND_PACKAGE(VTK REQUIRED) 4 INCLUDE(${VTK_USE_FILE}) 5 ADD_EXECUTABLE(ImageResliceExample ImageResliceExample.cpp) 6 TARGET_LINK_LIBRARIES(ImageResliceExample ${VTK_LIBRARIES})
ImageResliceExample.cpp文件代码如下:
1 #include <vtkSmartPointer.h> 2 #include <vtkImageReader2.h> 3 #include <vtkMatrix4x4.h> 4 #include <vtkImageReslice.h> 5 #include <vtkLookupTable.h> 6 #include <vtkImageMapToColors.h> 7 #include <vtkImageActor.h> 8 #include <vtkRenderer.h> 9 #include <vtkRenderWindow.h> 10 #include <vtkRenderWindowInteractor.h> 11 #include <vtkInteractorStyleImage.h> 12 #include <vtkCommand.h> 13 #include <vtkImageData.h> 14 #include <vtkMetaImageReader.h> 15 #include <vtkImageCast.h> 16 17 class vtkImageInteractionCallback : public vtkCommand 18 { 19 public: 20 static vtkImageInteractionCallback *New() 21 { 22 return new vtkImageInteractionCallback; 23 } 24 25 vtkImageInteractionCallback() 26 { 27 this->Slicing = 0; 28 this->ImageReslice = 0; 29 this->Interactor = 0; 30 } 31 32 void SetImageReslice(vtkImageReslice *reslice) 33 { 34 this->ImageReslice = reslice; 35 } 36 37 void SetImageMapToColors(vtkImageMapToColors *mapToColors) 38 { 39 this->mapToColors = mapToColors; 40 } 41 42 vtkImageReslice *GetImageReslice() 43 { 44 return this->ImageReslice; 45 } 46 47 void SetInteractor(vtkRenderWindowInteractor *interactor) 48 { 49 this->Interactor = interactor; 50 } 51 52 vtkRenderWindowInteractor *GetInteractor() 53 { 54 return this->Interactor; 55 } 56 57 virtual void Execute(vtkObject *, unsigned long event, void *) 58 { 59 vtkRenderWindowInteractor *interactor = this->GetInteractor(); 60 61 int lastPos[2]; 62 interactor->GetLastEventPosition(lastPos); 63 int currPos[2]; 64 interactor->GetEventPosition(currPos); 65 66 if (event == vtkCommand::LeftButtonPressEvent) 67 { 68 this->Slicing = 1; 69 } 70 else if (event == vtkCommand::LeftButtonReleaseEvent) 71 { 72 this->Slicing = 0; 73 } 74 else if (event == vtkCommand::MouseMoveEvent) 75 { 76 if (this->Slicing) 77 { 78 vtkImageReslice *reslice = this->ImageReslice; 79 80 // Increment slice position by deltaY of mouse 81 int deltaY = lastPos[1] - currPos[1]; 82 83 reslice->Update(); 84 double sliceSpacing = reslice->GetOutput()->GetSpacing()[2]; 85 vtkMatrix4x4 *matrix = reslice->GetResliceAxes(); 86 // move the center point that we are slicing through 87 double point[4]; 88 double center[4]; 89 point[0] = 0.0; 90 point[1] = 0.0; 91 point[2] = sliceSpacing * deltaY; 92 point[3] = 1.0; 93 matrix->MultiplyPoint(point, center); 94 matrix->SetElement(0, 3, center[0]); 95 matrix->SetElement(1, 3, center[1]); 96 matrix->SetElement(2, 3, center[2]); 97 mapToColors->Update(); 98 interactor->Render(); 99 } 100 else 101 { 102 vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast( 103 interactor->GetInteractorStyle()); 104 if (style) 105 { 106 style->OnMouseMove(); 107 } 108 } 109 } 110 } 111 112 private: 113 int Slicing; 114 vtkImageReslice *ImageReslice; 115 vtkRenderWindowInteractor *Interactor; 116 vtkImageMapToColors *mapToColors; 117 }; 118 119 int main() 120 { 121 vtkSmartPointer<vtkMetaImageReader> reader = 122 vtkSmartPointer<vtkMetaImageReader>::New(); 123 reader->SetFileName ( "E:\\TestData\\brain.mhd" ); 124 reader->Update(); 125 126 int extent[6]; 127 double spacing[3]; 128 double origin[3]; 129 130 reader->GetOutput()->GetExtent(extent); 131 reader->GetOutput()->GetSpacing(spacing); 132 reader->GetOutput()->GetOrigin(origin); 133 134 double center[3]; 135 center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]); 136 center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]); 137 center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]); 138 139 static double axialElements[16] = { 140 1, 0, 0, 0, 141 0, 1, 0, 0, 142 0, 0, 1, 0, 143 0, 0, 0, 1 144 }; 145 146 vtkSmartPointer<vtkMatrix4x4> resliceAxes = 147 vtkSmartPointer<vtkMatrix4x4>::New(); 148 resliceAxes->DeepCopy(axialElements); 149 150 resliceAxes->SetElement(0, 3, center[0]); 151 resliceAxes->SetElement(1, 3, center[1]); 152 resliceAxes->SetElement(2, 3, center[2]); 153 154 vtkSmartPointer<vtkImageReslice> reslice = 155 vtkSmartPointer<vtkImageReslice>::New(); 156 reslice->SetInputConnection(reader->GetOutputPort()); 157 reslice->SetOutputDimensionality(2); 158 reslice->SetResliceAxes(resliceAxes); 159 reslice->SetInterpolationModeToLinear(); 160 161 vtkSmartPointer<vtkLookupTable> colorTable = 162 vtkSmartPointer<vtkLookupTable>::New(); 163 colorTable->SetRange(0, 1000); 164 colorTable->SetValueRange(0.0, 1.0); 165 colorTable->SetSaturationRange(0.0, 0.0); 166 colorTable->SetRampToLinear(); 167 colorTable->Build(); 168 169 vtkSmartPointer<vtkImageMapToColors> colorMap = 170 vtkSmartPointer<vtkImageMapToColors>::New(); 171 colorMap->SetLookupTable(colorTable); 172 colorMap->SetInputConnection(reslice->GetOutputPort()); 173 colorMap->Update(); 174 175 vtkSmartPointer<vtkImageActor> imgActor = 176 vtkSmartPointer<vtkImageActor>::New(); 177 imgActor->SetInputData(colorMap->GetOutput()); 178 179 vtkSmartPointer<vtkRenderer> renderer = 180 vtkSmartPointer<vtkRenderer>::New(); 181 renderer->AddActor(imgActor); 182 renderer->SetBackground(1, 1, 1); 183 184 vtkSmartPointer<vtkRenderWindow> renderWindow = 185 vtkSmartPointer<vtkRenderWindow>::New(); 186 renderWindow->SetSize(500, 500); 187 renderWindow->AddRenderer(renderer); 188 189 vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = 190 vtkSmartPointer<vtkRenderWindowInteractor>::New(); 191 vtkSmartPointer<vtkInteractorStyleImage> imagestyle = 192 vtkSmartPointer<vtkInteractorStyleImage>::New(); 193 194 renderWindowInteractor->SetInteractorStyle(imagestyle); 195 renderWindowInteractor->SetRenderWindow(renderWindow); 196 renderWindowInteractor->Initialize(); 197 198 vtkSmartPointer<vtkImageInteractionCallback> callback = 199 vtkSmartPointer<vtkImageInteractionCallback>::New(); 200 callback->SetImageReslice(reslice); 201 callback->SetInteractor(renderWindowInteractor); 202 callback->SetImageMapToColors(colorMap); 203 204 imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback); 205 imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback); 206 imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback); 207 208 renderWindowInteractor->Start(); 209 return EXIT_SUCCESS; 210 }
运行结果:
按下鼠标左键,移动鼠标时的gif图片:
代码解释:
先通过vtkMetaImageReader读取一副三维图像,获取图像范围、原点和像素间隔,由这三个参数可以计算图像的中心位置。
接下来定义了切面的变换矩阵axialElements,该矩阵的前三列分别表示X、Y和Z方向矢量,第四列为切面坐标系原点。通过修改切面坐标系原点,可以得到不同位置的切面图像。
然后将读取的图像作为vtkImageReslice的输入,通过函数SetResliceAxes()设置变换矩阵resliceAxis。