zoukankan      html  css  js  c++  java
  • VTK 图像基本操作_三维图像切片交互提取(回调函数、观察者-命令模式)

    1.鼠标滑动提取三维图像切片

    学习三维图像切面的提取后,我们可以实现一个稍微复杂的程序——通过滑动鼠标来切换三维图像切片,这也是医学图像处理软件中一个很基本的功能。实现该功能难点是怎样在VTK中控制鼠标来实时提取图像切片。我们采用观察者/命令(Observer/Command)模式机制来实现。
    VTK中鼠标消息是在交互类型对象(interactorstyle)中响应,因此通过为交互类型对象(interactorstyle)添加观察者(observer)来监听相应的消息,当消息触发时,由命令模式执行相应的回调函数。
    代码设计如下:
      1 #include <vtkAutoInit.h>
      2 VTK_MODULE_INIT(vtkRenderingOpenGL);
      3  
      4 #include <vtkSmartPointer.h>
      5 #include <vtkMetaImageReader.h>
      6 #include <vtkMatrix4x4.h>
      7 #include <vtkLookupTable.h>
      8 #include <vtkImageMapToColors.h>
      9 #include <vtkImageActor.h>
     10 #include <vtkRenderer.h>
     11 #include <vtkRenderWindow.h>
     12 #include <vtkRenderWindowInteractor.h>
     13 #include <vtkInteractorStyleImage.h>
     14  
     15 #include <vtkCommand.h> //建立“观察者/命令”模式监听鼠标消息 完成交互
     16 #include <vtkImageReslice.h>
     17 #include <vtkImageData.h>
     18 class vtkImageInteractionCallback : public vtkCommand
     19 {
     20 public:
     21     static vtkImageInteractionCallback *New() //回调函数初始化函数
     22     {
     23         return new vtkImageInteractionCallback;
     24     }
     25     vtkImageInteractionCallback()
     26     {
     27         this->Slicing = 0;
     28         this->ImageReslice = 0;
     29         this->Interactor = 0;
     30     }
     31     void SetImageReslice(vtkImageReslice *reslice)
     32     {
     33         this->ImageReslice = reslice;
     34     }
     35     vtkImageReslice *GetImageReslice()
     36     {
     37         return this->ImageReslice;
     38     }
     39     void SetInteractor(vtkRenderWindowInteractor *interactor)
     40     {
     41         this->Interactor = interactor;
     42     }
     43     vtkRenderWindowInteractor *GetInteractor()
     44     {
     45         return  this->Interactor;
     46     }
     47     virtual void Execute(vtkObject * ,unsigned long event,void *)
     48     {
     49         vtkRenderWindowInteractor *interactor = GetInteractor();
     50         int lastPos[2];
     51         interactor->GetLastEventPosition(lastPos);
     52         int currPos[2];
     53         interactor->GetEventPosition(currPos);
     54  
     55         if (event == vtkCommand::LeftButtonPressEvent)
     56         {
     57             this->Slicing = 1; //标志位 
     58         }
     59         else if (event == vtkCommand::LeftButtonReleaseEvent)
     60         {
     61             this->Slicing = 0; //标志位 
     62         }
     63         else if (event == vtkCommand::MouseMoveEvent)
     64         {
     65             if (this->Slicing)//检验鼠标左键已经按下 正在执行操作
     66             {
     67                 vtkImageReslice *reslice = this->ImageReslice;
     68                 //记下鼠标Y向变化的幅值大小
     69                 int deltaY = lastPos[1] - currPos[1];
     70  
     71                 reslice->Update();
     72                 double sliceSpacing = reslice->GetOutput()->GetSpacing()[2];
     73                 vtkMatrix4x4 *matrix = reslice->GetResliceAxes();
     74                 //重新定位切片需要经过的中心点
     75                 double point[4];
     76                 double center[4];
     77                 point[0] = 0;
     78                 point[1] = 0;
     79                 point[2] = sliceSpacing*deltaY;
     80                 point[3] = 1.0;
     81                 matrix->MultiplyPoint(point, center);
     82                 matrix->SetElement(0, 3, center[0]);
     83                 matrix->SetElement(1, 3, center[1]);
     84                 matrix->SetElement(2, 3, center[2]);
     85  
     86                 interactor->Render();
     87             }
     88             else
     89             {
     90                 vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast(
     91                     interactor->GetInteractorStyle());
     92                 if (style)
     93                 {
     94                     style->OnMouseMove();
     95                 }
     96             }
     97         }
     98     }
     99 private:
    100     int Slicing;
    101     vtkImageReslice *ImageReslice;
    102     vtkRenderWindowInteractor *Interactor;
    103 };
    104 //**********************************************************************************//
    105 int main()
    106 {
    107     vtkSmartPointer<vtkMetaImageReader> reader =
    108         vtkSmartPointer<vtkMetaImageReader>::New();
    109     reader->SetFileName("brain.mhd");
    110     reader->Update();
    111  
    112     int extent[6];
    113     double spacing[3];
    114     double origin[3];
    115  
    116     reader->GetOutput()->GetExtent(extent);
    117     reader->GetOutput()->GetSpacing(spacing);
    118     reader->GetOutput()->GetOrigin(origin);
    119  
    120     double center[3];
    121     center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
    122     center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
    123     center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);
    124  
    125     static double axialElements[16] = {
    126         1, 0, 0, 0,
    127         0, 1, 0, 0,
    128         0, 0, 1, 0,
    129         0, 0, 0, 1
    130     };
    131  
    132     vtkSmartPointer<vtkMatrix4x4> resliceAxes =
    133         vtkSmartPointer<vtkMatrix4x4>::New();
    134     resliceAxes->DeepCopy(axialElements);
    135  
    136     resliceAxes->SetElement(0, 3, center[0]);
    137     resliceAxes->SetElement(1, 3, center[1]);
    138     resliceAxes->SetElement(2, 3, center[2]);
    139  
    140     vtkSmartPointer<vtkImageReslice> reslice =
    141         vtkSmartPointer<vtkImageReslice>::New();
    142     reslice->SetInputConnection(reader->GetOutputPort());
    143     reslice->SetOutputDimensionality(2);
    144     reslice->SetResliceAxes(resliceAxes);
    145     reslice->SetInterpolationModeToLinear();
    146  
    147     vtkSmartPointer<vtkLookupTable> colorTable =
    148         vtkSmartPointer<vtkLookupTable>::New();
    149     colorTable->SetRange(0, 1000);
    150     colorTable->SetValueRange(0.0, 1.0);
    151     colorTable->SetSaturationRange(0.0, 0.0);
    152     colorTable->SetRampToLinear();
    153     colorTable->Build();
    154  
    155     vtkSmartPointer<vtkImageMapToColors> colorMap =
    156         vtkSmartPointer<vtkImageMapToColors>::New();
    157     colorMap->SetLookupTable(colorTable);
    158     colorMap->SetInputConnection(reslice->GetOutputPort());
    159  
    160     vtkSmartPointer<vtkImageActor> imgActor =
    161         vtkSmartPointer<vtkImageActor>::New();
    162     imgActor->SetInputData(colorMap->GetOutput());
    163  
    164     vtkSmartPointer<vtkRenderer> renderer =
    165         vtkSmartPointer<vtkRenderer>::New();
    166     renderer->AddActor(imgActor);
    167     renderer->SetBackground(.4, .5, .6);
    168  
    169     vtkSmartPointer<vtkRenderWindow> renderWindow =
    170         vtkSmartPointer<vtkRenderWindow>::New();
    171     renderWindow->SetSize(500, 500);
    172     renderWindow->AddRenderer(renderer);
    173  
    174     vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    175         vtkSmartPointer<vtkRenderWindowInteractor>::New();
    176     vtkSmartPointer<vtkInteractorStyleImage> imagestyle =
    177         vtkSmartPointer<vtkInteractorStyleImage>::New();
    178  
    179     renderWindowInteractor->SetInteractorStyle(imagestyle);
    180     renderWindowInteractor->SetRenderWindow(renderWindow);
    181     renderWindowInteractor->Initialize();
    182     //****************建立 观察者-命令 模式****************//
    183     vtkSmartPointer<vtkImageInteractionCallback> callback =
    184         vtkSmartPointer<vtkImageInteractionCallback>::New();
    185     callback->SetImageReslice(reslice);
    186     callback->SetInteractor(renderWindowInteractor);
    187  
    188     imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback);
    189     imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback);
    190     imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback);
    191  
    192     renderWindowInteractor->Start();
    193  
    194     return 0;
    195 }

    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添加观察者,响应鼠标消息。
    这里主要是定义了vtkImageInteractionCallback对象,并设置vtkImageSlice对象和vtkRenderWindowInteractor对象。然后为交互对象vtkInteractorStyle添加观察者来监控相应的消息,这里主要是三个消息:
    vtkCommand::LeftButtonPressEvent,
    vtkCommand::LeftButtonReleaseEvent,
    vtkCommand::MouseMoveEvent,
    当响应到这三个消息时,立即执行vtkImageInteractionCallback的Execute函数,以便实现切片的实时提取和更新。完成以后,运行程序,当鼠标在图像上移动时,会发现图像会跟着鼠标的移动而变化。
  • 相关阅读:
    P1087 FBI树 二叉树
    回顾测试和测试方法
    Postman
    执行用例的思路、批量执行(可选)、定时任务
    unittest平台分析与建表:
    HTMLTestRunner源码
    665. Non-decreasing Array
    661. Image Smoother
    643. Maximum Average Subarray I
    628. Maximum Product of Three Numbers
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14241350.html
Copyright © 2011-2022 走看看