三维图像切面提取
切片(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。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
2022-07-13 Qt 路径中常用字符“./”、“../”、“/”、“*”的含义
2022-07-13 MATLAB 函数汉化方法
2022-07-13 Git 入门指南
2022-07-13 ARM、STM32之间的关系以及STM单片机介绍