5.7 区域提取
来源:互联网 发布:欧洲难民知乎 编辑:程序博客网 时间:2024/06/05 17:19
5.7 区域提取
5.7.1 提取感兴趣区域
感兴趣区域(Volum of Interest)是指图像内部的一个子区域。在VTK中vtkExtractVOI类实现由用户指定的区域范围提取图像的子图像。该Filter的输入和输出都是一个vtkImageData,因此其结果可以直接作为图像保存。
1: vtkSmartPointer<vtkBMPReader> reader = 2: vtkSmartPointer<vtkBMPReader>::New(); 3: reader->SetFileName ( "lena.bmp" ); 4: reader->Update(); 5: 6: int dims[3]; 7: reader->GetOutput()->GetDimensions(dims); 8: 9: vtkSmartPointer<vtkExtractVOI> extractVOI = 10: vtkSmartPointer<vtkExtractVOI>::New(); 11: extractVOI->SetInputConnection(reader->GetOutputPort()); 12: extractVOI->SetVOI(dims[0]/4.,3.*dims[0]/4.,dims[1]/4.,3.*dims[1]/4., 0, 0); 13: extractVOI->Update();
上例代码实现了提取一副图像的子区域。首先读取一个图像,并获取图像的维数。然后定义vtkExtractVOI对象,该对象接收两个输入一个是图像数据,第二个是区域大小。设置区域大小的函数原型:
void SetVOI(int _arg1, int _arg2, int _arg3, int _arg4, int _arg5, int _arg6)void SetVOI(int _arg[])
其参数是提取的区域各个方向的大小,共6个参数,依次表示x方向最小值,x方向最大值,y方向最小值,y方向最大值,z方向最小值和z方向最大值。上例中由于读取的是二维图像,因此z方向的区域为[0,0],而在x方向范围为[ dims[0]/4 , 3*dims[0]/4 ],y方向范围为[ dims[1]/4 , 3*dims[1]/4 ],即提取图像原图中间1/4图像。执行结果如下:
图5.18 提取感兴趣区域
5.7.2 三维图像切片提取
切片是指三维图像中的一个切面对应的图像。切面可以是过图像内部一点且平行于XY、YZ、XZ平面的平面,也可以是任意的过三维图像内部一点任意方向的平面。通过提取切片可以方便的浏览和分析图像内部组织结构,是医学图像浏览软件中的一个重要的功能。在VTK中vtkImageReslice类实现图像切片提取功能。下面首先看一段切片提取的代码。
1: vtkSmartPointer<vtkMetaImageReader> reader = 2: vtkSmartPointer<vtkMetaImageReader>::New(); 3: reader->SetFileName ( " brain.mhd" ); 4: reader->Update(); 5: 6: int extent[6]; 7: double spacing[3]; 8: double origin[3]; 9: 10: reader->GetOutput()->GetExtent(extent); 11: reader->GetOutput()->GetSpacing(spacing); 12: reader->GetOutput()->GetOrigin(origin); 13: 14: double center[3]; 15: center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]); 16: center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]); 17: center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]); 18: 19: static double axialElements[16] = { 20: 1, 0, 0, 0, 21: 0, 1, 0, 0, 22: 0, 0, 1, 0, 23: 0, 0, 0, 1 }; 24: 25: vtkSmartPointer<vtkMatrix4x4> resliceAxes = 26: vtkSmartPointer<vtkMatrix4x4>::New(); 27: resliceAxes->DeepCopy(axialElements); 28: 29: resliceAxes->SetElement(0, 3, center[0]); 30: resliceAxes->SetElement(1, 3, center[1]); 31: resliceAxes->SetElement(2, 3, center[2]); 32: 33: 34: vtkSmartPointer<vtkImageReslice> reslice = 35: vtkSmartPointer<vtkImageReslice>::New(); 36: reslice->SetInputConnection(reader->GetOutputPort()); 37: reslice->SetOutputDimensionality(2); 38: reslice->SetResliceAxes(resliceAxes); 39: reslice->SetInterpolationModeToLinear(); 40: 41: vtkSmartPointer<vtkLookupTable> colorTable = 42: vtkSmartPointer<vtkLookupTable>::New(); 43: colorTable->SetRange(0, 1000); 44: colorTable->SetValueRange(0.0, 1.0); 45: colorTable->SetSaturationRange(0.0, 0.0); 46: colorTable->SetRampToLinear(); 47: colorTable->Build(); 48: 49: vtkSmartPointer<vtkImageMapToColors> colorMap = 50: vtkSmartPointer<vtkImageMapToColors>::New(); 51: colorMap->SetLookupTable(colorTable); 52: colorMap->SetInputConnection(reslice->GetOutputPort()); 53: 54: vtkSmartPointer<vtkImageActor> imgActor = 55: vtkSmartPointer<vtkImageActor>::New(); 56: imgActor->SetInput(colorMap->GetOutput()); 57: 58: vtkSmartPointer<vtkRenderer> renderer = 59: vtkSmartPointer<vtkRenderer>::New(); 60: renderer->AddActor(imgActor); 61: renderer->SetBackground(.4, .5, .6); 62: 63: vtkSmartPointer<vtkRenderWindow> renderWindow = 64: vtkSmartPointer<vtkRenderWindow>::New(); 65: renderWindow->SetSize(500, 500); 66: renderWindow->AddRenderer(renderer); 67: 68: vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = 69: vtkSmartPointer<vtkRenderWindowInteractor>::New(); 70: vtkSmartPointer<vtkInteractorStyleImage> imagestyle = 71: vtkSmartPointer<vtkInteractorStyleImage>::New(); 72: 73: renderWindowInteractor->SetInteractorStyle(imagestyle); 74: renderWindowInteractor->SetRenderWindow(renderWindow); 75: renderWindowInteractor->Initialize(); 76: 77: renderWindowInteractor->Start();
首先通过vtkMetaImageReader读取一副医学三维图像,并获取得到图像范围(extent),原点和像素间隔;由这三个参数可以计算图像的中心位置center;接下来定义了切面的变换矩阵axialElements,该矩阵的前三列分别表示x、y和z方向向量,第四列为中心点坐标;代码中的axialElements表示切面变换矩阵与当前坐标系一致,且切面为过中心点center,并平行于XY平面的平面。当前,定义该切面时,也可以是其他平面,甚至是任意平面,但是必须要过图像内部点。下面给出了一个常用的变换矩阵:
static double coronalElements[16] = { 1, 0, 0, 0, 0, 0, 1, 0,0,-1, 0, 0, 0, 0, 0, 1 }; 提取平行于XZ平面的切片static double sagittalElements[16] = { 0, 0,-1, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 1 }; 提取平行于YZ平面的切片static double obliqueElements[16] = { 1, 0, 0, 0, 0, 0.866025, -0.5, 0, 0, 0.5, 0.866025, 0, 0, 0, 0, 1 }; 提取斜切切片
注意使用这些变换矩阵的时候,需要将第四列替换为切片经过图像的一个点坐标,上例中将图像的中心添加到axialElements矩阵,并通过函数SetResliceAxes设置变换矩阵,SetOutputDimensionality(2)指定输出的图像为一个二维图像;而函数SetInterpolationModeToLinear()则指定了切面提取中的差值方式为线性差值,另外该类中还提供了其他的差值方式:
SetInterpolationModeToNearestNeighbor():最近邻方式
SetInterpolationModeToCubic():三次线性差值
设置完毕后,执行Update()即可完成切面计算。运行结果如下图:
图5.19 切片提取
5.7.3 扩展
学习三维图像切面的提取后,我们在上节的程序上做一个扩展,实现一个稍微复杂的程序——通过滑动鼠标来切换三维图像切片,这也是医学图像处理软件中一个很基本的功能。实现该功能难点是怎样在VTK中控制鼠标来实时提取图像切片。在前面的章节中已经介绍观察者/命令(Observer/Command)模式,我们也采用这种机制来实现。VTK中鼠标消息是在交互类型对象(interactorstyle)中响应,因此通过为交互类型对象(interactorstyle)添加观察者(observer)来监听相应的消息,当消息触发时,由命令模式执行相应的回调函数。闲话少说,放代码。
1: class vtkImageInteractionCallback : public vtkCommand 2: { 3: public: 4: 5: static vtkImageInteractionCallback *New() 6: { 7: return new vtkImageInteractionCallback; 8: } 9: 10: vtkImageInteractionCallback() 11: { 12: this->Slicing = 0; 13: this->ImageReslice = 0; 14: this->Interactor = 0; 15: } 16: 17: void SetImageReslice(vtkImageReslice *reslice) 18: { 19: this->ImageReslice = reslice; 20: } 21: 22: vtkImageReslice *GetImageReslice() 23: { 24: return this->ImageReslice; 25: } 26: 27: void SetInteractor(vtkRenderWindowInteractor *interactor) 28: { 29: this->Interactor = interactor; 30: } 31: 32: vtkRenderWindowInteractor *GetInteractor() 33: { 34: return this->Interactor; 35: } 36: 37: virtual void Execute(vtkObject *, unsigned long event, void *) 38: { 39: vtkRenderWindowInteractor *interactor = this->GetInteractor(); 40: 41: int lastPos[2]; 42: interactor->GetLastEventPosition(lastPos); 43: int currPos[2]; 44: interactor->GetEventPosition(currPos); 45: 46: if (event == vtkCommand::LeftButtonPressEvent) 47: { 48: this->Slicing = 1; 49: } 50: else if (event == vtkCommand::LeftButtonReleaseEvent) 51: { 52: this->Slicing = 0; 53: } 54: else if (event == vtkCommand::MouseMoveEvent) 55: { 56: if (this->Slicing) 57: { 58: vtkImageReslice *reslice = this->ImageReslice; 59: 60: // Increment slice position by deltaY of mouse 61: int deltaY = lastPos[1] - currPos[1]; 62: 63: reslice->Update(); 64: double sliceSpacing = reslice->GetOutput()->GetSpacing()[2]; 65: vtkMatrix4x4 *matrix = reslice->GetResliceAxes(); 66: // move the center point that we are slicing through 67: double point[4]; 68: double center[4]; 69: point[0] = 0.0; 70: point[1] = 0.0; 71: point[2] = sliceSpacing * deltaY; 72: point[3] = 1.0; 73: matrix->MultiplyPoint(point, center); 74: matrix->SetElement(0, 3, center[0]); 75: matrix->SetElement(1, 3, center[1]); 76: matrix->SetElement(2, 3, center[2]); 77: interactor->Render(); 78: } 79: else 80: { 81: vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast( 82: interactor->GetInteractorStyle()); 83: if (style) 84: { 85: style->OnMouseMove(); 86: } 87: } 88: } 89: } 90: 91: private: 92: int Slicing; 93: vtkImageReslice *ImageReslice; 94: vtkRenderWindowInteractor *Interactor; 95: };
vtkImageInteractionCallback继承自vtkCommand类,并覆盖父类函数Execute()。该类提供了两个接口:SetImageReslice和SetInteractor。SetImageReslice用以设置vtkImageSlice对象,vtkImageSlice根据设置的变换矩阵提取三维图像切片。SetInteractor用以设置vtkRenderWindowInteractor,vtkRenderWindowInteractor类对象负责每次提取切片后刷新视图。
下面我们重点来看一下Execute函数,该函数提供了具体的切片提取功能。在该函数里面,主要监听了三个消息:
vtkCommand::LeftButtonPressEvent,vtkCommand::LeftButtonReleaseEvent,vtkCommand::MouseMoveEvent,
前两个消息分别是鼠标左键的按下和弹起消息。当鼠标左键按下时,就设置切片提取标志为1,而当弹起时,将标志置为0。这样在鼠标移动时,只有在确定切片提取标志为1时,执行切片提取功能。
vtkCommand::MouseMoveEvent即为鼠标移动消息。当检测到该消息时,首先检查切片提取标志,当为1时提取切片。提取切片时,需要为vtkImageSlice对象设置变换矩阵。这里在函数开始时,首先获取了鼠标滑动的前后两次点的位置lastPos和currPos。然后根据两点的Y坐标差deltaY,计算新的中心点center并变换至vtkImageSlice当前变换矩阵中,得到变换中心点,将其设置到原来的变换矩阵matrix中,并设置到vtkImageSlice中,最后执行interactor->Render()即可不断的根据鼠标移动刷新图像。
Command对象定义完毕后,即可为交互对象InteractorStyle添加观察者,响应鼠标消息。这里可以在上节的程序上进行修改,前面代码一致,只需要在最后添加如下代码:
1: vtkSmartPointer<vtkImageInteractionCallback> callback = 2: vtkSmartPointer<vtkImageInteractionCallback>::New(); 3: callback->SetImageReslice(reslice); 4: callback->SetInteractor(renderWindowInteractor); 5: 6: imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback); 7: imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback); 8: imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback); 9: 10: renderWindowInteractor->Start();
这里主要是定义了vtkImageInteractionCallback对象,并设置vtkImageSlice对象和vtkRenderWindowInteractor对象。然后为交互对象vtkInteractorStyle添加观察者来监控相应的消息,这里主要是三个消息:
vtkCommand::LeftButtonPressEvent,vtkCommand::LeftButtonReleaseEvent,vtkCommand::MouseMoveEvent,
当响应到这三个消息时,立即执行vtkImageInteractionCallback的Execute函数,以便实现切片的实时提取和更新。完成以后,运行程序,当鼠标在图像上移动时,会发现图像会跟着鼠标的移动而变化,神奇吧?有兴趣的话,还可以实现YZ平面、XZ平面切片提取,甚至是任意方向的切面提取。
==========欢迎转载,转载时请保留该声明信息==========
版权归@东灵工作室所有,更多信息请访问东灵工作室
教程系列导航:http://blog.csdn.net/www_doling_net/article/details/8763686
- 5.7 区域提取
- 区域提取
- opencv提取ROI区域
- opencv-车牌区域提取
- 眼睛区域提取研究
- 文字区域的提取
- Halcon 提取ROI区域
- MATLAB提取区域特征
- MATLAB区域标记提取指定编号区域
- OpenCV区域提取之使用鼠标进行区域提取!
- 提取遥感影像有效区域
- 提取遥感影像有效区域
- opencv2中MSER区域提取
- 提取合适连通区域轮廓
- OpenCV 文字区域的提取
- OpenCV 文字区域的提取
- 区域生长算法提取鱼眼有效区域
- 图像显著性区域提取[2]-特征提取
- 【AssetManager】
- 更改 windows 下 cmd(dos) 编码方式
- 【网络安全】工控安全研究入门
- 最长回文子串
- 【win7系统常用网络命令】
- 5.7 区域提取
- AndroidManifest解析
- 【如何装出64位win7系统】
- Leetcode-- Majority Elemeny
- Linux显示指定区块大小为1048576字节
- 第二周工作周报-刘婉
- spring之Aop面向切面
- C 矩阵变化
- 限制玻尔兹曼机(Restricted Boltzmann Machine)学习笔记(二)