医站点医维基

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 331|回复: 9

vtkResliceCursorWidget实现多平面重建效果

[复制链接]

109

主题

23

回帖

3550

积分

管理员

积分
3550
发表于 2024-1-2 20:34:24 | 显示全部楼层 |阅读模式
vtkResliceCursorWidget和vtkResliceCursor类实现交互式图像切分,vtkResliceCursorWidget对象中需要定义相对应的vtkResliceCursor对象。vtkResliceCursorWidget定义十字坐标轴为用户提供便捷的切分和交互方式,支持坐标轴的旋转和平移;当坐标轴发生改变时,调用vtkResliceCursor来进行图像切分并更新到vtkRenderer对象中。

屏幕截图 2024-01-02 202221.png


屏幕截图 2024-01-02 203304.png

调整层厚的效果


  1. // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill
  2. // Lorensen SPDX-License-Identifier: BSD-3-Clause
  3. #include "vtkRegressionTestImage.h"
  4. #include "vtkSmartPointer.h"

  5. #include "vtkActor.h"
  6. #include "vtkBiDimensionalWidget.h"
  7. #include "vtkCamera.h"
  8. #include "vtkCellPicker.h"
  9. #include "vtkCommand.h"
  10. #include "vtkDICOMImageReader.h"
  11. #include "vtkImageActor.h"
  12. #include "vtkImageData.h"
  13. #include "vtkImageMapToColors.h"
  14. #include "vtkImagePlaneWidget.h"
  15. #include "vtkImageReader.h"
  16. #include "vtkImageReslice.h"
  17. #include "vtkInteractorEventRecorder.h"
  18. #include "vtkInteractorStyleImage.h"
  19. #include "vtkLookupTable.h"
  20. #include "vtkOutlineFilter.h"
  21. #include "vtkPlane.h"
  22. #include "vtkPlaneSource.h"
  23. #include "vtkPointData.h"
  24. #include "vtkPolyDataMapper.h"
  25. #include "vtkProperty.h"
  26. #include "vtkRenderWindow.h"
  27. #include "vtkRenderWindowInteractor.h"
  28. #include "vtkRenderer.h"
  29. #include "vtkResliceCursor.h"
  30. #include "vtkResliceCursorActor.h"
  31. #include "vtkResliceCursorLineRepresentation.h"
  32. #include "vtkResliceCursorPolyDataAlgorithm.h"
  33. #include "vtkResliceCursorThickLineRepresentation.h"
  34. #include "vtkResliceCursorWidget.h"
  35. #include "vtkVolume16Reader.h"

  36. #include "vtkTestUtilities.h"

  37. //------------------------------------------------------------------------------
  38. class vtkResliceCursorCallback3 : public vtkCommand
  39. {
  40. public:
  41.   static vtkResliceCursorCallback3* New()
  42.   {
  43.     return new vtkResliceCursorCallback3;
  44.   }

  45.   void Execute(vtkObject* caller, unsigned long /*ev*/, void* callData) override
  46.   {
  47.     vtkImagePlaneWidget* ipw = dynamic_cast<vtkImagePlaneWidget*>(caller);
  48.     if (ipw)
  49.     {
  50.       double* wl = static_cast<double*>(callData);

  51.       if (ipw == this->IPW[0])
  52.       {
  53.         this->IPW[1]->SetWindowLevel(wl[0], wl[1], 1);
  54.         this->IPW[2]->SetWindowLevel(wl[0], wl[1], 1);
  55.       }
  56.       else if (ipw == this->IPW[1])
  57.       {
  58.         this->IPW[0]->SetWindowLevel(wl[0], wl[1], 1);
  59.         this->IPW[2]->SetWindowLevel(wl[0], wl[1], 1);
  60.       }
  61.       else if (ipw == this->IPW[2])
  62.       {
  63.         this->IPW[0]->SetWindowLevel(wl[0], wl[1], 1);
  64.         this->IPW[1]->SetWindowLevel(wl[0], wl[1], 1);
  65.       }
  66.     }

  67.     vtkResliceCursorWidget* rcw = dynamic_cast<vtkResliceCursorWidget*>(caller);
  68.     if (rcw)
  69.     {
  70.       vtkResliceCursorLineRepresentation* rep =
  71.           dynamic_cast<vtkResliceCursorLineRepresentation*>(
  72.               rcw->GetRepresentation());
  73.       vtkResliceCursor* rc = rep->GetResliceCursorActor()
  74.                                  ->GetCursorAlgorithm()
  75.                                  ->GetResliceCursor();
  76.       for (int i = 0; i < 3; i++)
  77.       {
  78.         vtkPlaneSource* ps =
  79.             static_cast<vtkPlaneSource*>(this->IPW[i]->GetPolyDataAlgorithm());
  80.         ps->SetNormal(rc->GetPlane(i)->GetNormal());
  81.         ps->SetCenter(rc->GetPlane(i)->GetOrigin());

  82.         // If the reslice plane has modified, update it on the 3D widget
  83.         this->IPW[i]->UpdatePlacement();

  84.         // std::cout << "Updating placement of plane: " << i << " " <<
  85.         //  rc->GetPlane(i)->GetNormal()[0] << " " <<
  86.         //  rc->GetPlane(i)->GetNormal()[1] << " " <<
  87.         //  rc->GetPlane(i)->GetNormal()[2] << std::endl;
  88.         // this->IPW[i]->GetReslice()->Print(cout);
  89.         // rep->GetReslice()->Print(cout);
  90.         // std::cout << "---------------------" << std::endl;
  91.       }
  92.     }

  93.     // Render everything
  94.     this->RCW[0]->Render();
  95.   }

  96.   vtkResliceCursorCallback3() = default;
  97.   vtkImagePlaneWidget* IPW[3];
  98.   vtkResliceCursorWidget* RCW[3];
  99. };

  100. //------------------------------------------------------------------------------
  101. int main(int argc, char* argv[])
  102. {
  103.     vtkSmartPointer<vtkDICOMImageReader> reader =
  104.       vtkSmartPointer<vtkDICOMImageReader>::New();
  105.   reader->SetDirectoryName("D:/Data/two/SE1");
  106.   reader->Update();

  107.   vtkSmartPointer<vtkOutlineFilter> outline =
  108.       vtkSmartPointer<vtkOutlineFilter>::New();
  109.   outline->SetInputConnection(reader->GetOutputPort());

  110.   vtkSmartPointer<vtkPolyDataMapper> outlineMapper =
  111.       vtkSmartPointer<vtkPolyDataMapper>::New();
  112.   outlineMapper->SetInputConnection(outline->GetOutputPort());

  113.   vtkSmartPointer<vtkActor> outlineActor = vtkSmartPointer<vtkActor>::New();
  114.   outlineActor->SetMapper(outlineMapper);

  115.   vtkSmartPointer<vtkRenderer> ren[4];

  116.   vtkSmartPointer<vtkRenderWindow> renWin =
  117.       vtkSmartPointer<vtkRenderWindow>::New();
  118.   renWin->SetMultiSamples(0);

  119.   for (int i = 0; i < 4; i++)
  120.   {
  121.     ren[i] = vtkSmartPointer<vtkRenderer>::New();
  122.     renWin->AddRenderer(ren[i]);
  123.   }

  124.   vtkSmartPointer<vtkRenderWindowInteractor> iren =
  125.       vtkSmartPointer<vtkRenderWindowInteractor>::New();
  126.   iren->SetRenderWindow(renWin);

  127.   vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
  128.   picker->SetTolerance(0.005);

  129.   vtkSmartPointer<vtkProperty> ipwProp = vtkSmartPointer<vtkProperty>::New();

  130.   // assign default props to the ipw's texture plane actor
  131.   vtkSmartPointer<vtkImagePlaneWidget> planeWidget[3];
  132.   int imageDims[3];
  133.   reader->GetOutput()->GetDimensions(imageDims);

  134.   for (int i = 0; i < 3; i++)
  135.   {
  136.     planeWidget[i] = vtkSmartPointer<vtkImagePlaneWidget>::New();
  137.     planeWidget[i]->SetInteractor(iren);
  138.     planeWidget[i]->SetPicker(picker);
  139.     planeWidget[i]->RestrictPlaneToVolumeOn();
  140.     double color[3] = {0, 0, 0};
  141.     color[i] = 1;
  142.     planeWidget[i]->GetPlaneProperty()->SetColor(color);
  143.     planeWidget[i]->SetTexturePlaneProperty(ipwProp);
  144.     planeWidget[i]->TextureInterpolateOff();
  145.     planeWidget[i]->SetResliceInterpolateToLinear();
  146.     planeWidget[i]->SetInputConnection(reader->GetOutputPort());
  147.     planeWidget[i]->SetPlaneOrientation(i);
  148.     planeWidget[i]->SetSliceIndex(imageDims[i] / 2);
  149.     planeWidget[i]->DisplayTextOn();
  150.     planeWidget[i]->SetDefaultRenderer(ren[3]);
  151.     planeWidget[i]->SetWindowLevel(1358, -27);
  152.     planeWidget[i]->On();
  153.     planeWidget[i]->InteractionOn();
  154.   }

  155.   planeWidget[1]->SetLookupTable(planeWidget[0]->GetLookupTable());
  156.   planeWidget[2]->SetLookupTable(planeWidget[0]->GetLookupTable());

  157.   vtkSmartPointer<vtkResliceCursorCallback3> cbk =
  158.       vtkSmartPointer<vtkResliceCursorCallback3>::New();

  159.   // Create the reslice cursor, widget and rep

  160.   vtkSmartPointer<vtkResliceCursor> resliceCursor =
  161.       vtkSmartPointer<vtkResliceCursor>::New();
  162.   resliceCursor->SetCenter(reader->GetOutput()->GetCenter());
  163.   resliceCursor->SetThickMode(1);
  164.   resliceCursor->SetThickness(10, 10, 10);
  165.   resliceCursor->SetImage(reader->GetOutput());

  166.   vtkSmartPointer<vtkResliceCursorWidget> resliceCursorWidget[3];
  167.   vtkSmartPointer<vtkResliceCursorThickLineRepresentation> resliceCursorRep[3];

  168.   double viewUp[3][3] = {{0, 0, -1}, {0, 0, 1}, {0, 1, 0}};
  169.   for (int i = 0; i < 3; i++)
  170.   {
  171.     resliceCursorWidget[i] = vtkSmartPointer<vtkResliceCursorWidget>::New();
  172.     resliceCursorWidget[i]->SetInteractor(iren);

  173.     resliceCursorRep[i] =
  174.         vtkSmartPointer<vtkResliceCursorThickLineRepresentation>::New();
  175.     resliceCursorWidget[i]->SetRepresentation(resliceCursorRep[i]);
  176.     resliceCursorRep[i]
  177.         ->GetResliceCursorActor()
  178.         ->GetCursorAlgorithm()
  179.         ->SetResliceCursor(resliceCursor);
  180.     resliceCursorRep[i]
  181.         ->GetResliceCursorActor()
  182.         ->GetCursorAlgorithm()
  183.         ->SetReslicePlaneNormal(i);

  184.     const double minVal = reader->GetOutput()->GetScalarRange()[0];
  185.     if (vtkImageReslice* reslice =
  186.             vtkImageReslice::SafeDownCast(resliceCursorRep[i]->GetReslice()))
  187.     {
  188.       reslice->SetBackgroundColor(minVal, minVal, minVal, minVal);
  189.     }

  190.     resliceCursorWidget[i]->SetDefaultRenderer(ren[i]);
  191.     resliceCursorWidget[i]->SetEnabled(1);

  192.     ren[i]->GetActiveCamera()->SetFocalPoint(0, 0, 0);
  193.     double camPos[3] = {0, 0, 0};
  194.     camPos[i] = 1;
  195.     ren[i]->GetActiveCamera()->SetPosition(camPos);

  196.     ren[i]->GetActiveCamera()->ParallelProjectionOn();
  197.     ren[i]->GetActiveCamera()->SetViewUp(viewUp[i]);
  198.     ren[i]->ResetCamera();
  199.     // ren[i]->ResetCameraClippingRange();

  200.     // Tie the Image plane widget and the reslice cursor widget together
  201.     cbk->IPW[i] = planeWidget[i];
  202.     cbk->RCW[i] = resliceCursorWidget[i];
  203.     resliceCursorWidget[i]->AddObserver(
  204.         vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk);

  205.     // Initialize the window level to a sensible value
  206.     double range[2];
  207.     reader->GetOutput()->GetScalarRange(range);
  208.     resliceCursorRep[i]->SetWindowLevel(range[1] - range[0],
  209.                                         (range[0] + range[1]) / 2.0);
  210.     planeWidget[i]->SetWindowLevel(range[1] - range[0],
  211.                                    (range[0] + range[1]) / 2.0);

  212.     // Make them all share the same color map.
  213.     resliceCursorRep[i]->SetLookupTable(resliceCursorRep[0]->GetLookupTable());
  214.     planeWidget[i]->GetColorMap()->SetLookupTable(
  215.         resliceCursorRep[0]->GetLookupTable());

  216.     // clang-format off
  217.     // Workaround VTK issue #18441
  218.     // Make sure vtkResliceCursorActor is visible by forcing its representation to wireframe.
  219.     // vtkResliceCursorActor is a quad with a normal parallel to the camera view up vector.
  220.     // When represented as a surface, it has a thickness of 0 pixels. The class internally turns
  221.     // edge visibility on to workaround the problem, which does not seem to be enough.
  222.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->SetRepresentationToWireframe();
  223.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->SetRepresentationToWireframe();
  224.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->SetRepresentationToWireframe();
  225.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(0)->SetRepresentationToWireframe();
  226.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(1)->SetRepresentationToWireframe();
  227.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(2)->SetRepresentationToWireframe();
  228.     // Workaround rendering artefacts with Intel chipsets and osmesa, where lines are rendered
  229.     // black if perfectly aligned with the camera viewup (see #18453)
  230.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->RenderLinesAsTubesOn();
  231.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->RenderLinesAsTubesOn();
  232.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->RenderLinesAsTubesOn();
  233.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->SetLineWidth(2);
  234.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->SetLineWidth(2);
  235.     resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->SetLineWidth(2);
  236.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(0)->RenderLinesAsTubesOn();
  237.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(1)->RenderLinesAsTubesOn();
  238.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(2)->RenderLinesAsTubesOn();
  239.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(0)->SetLineWidth(2);
  240.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(1)->SetLineWidth(2);
  241.     resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(2)->SetLineWidth(2);
  242.     // clang-format on
  243.   }

  244.   // Add the actors
  245.   //
  246.   ren[0]->SetBackground(0.3, 0.1, 0.1);
  247.   ren[1]->SetBackground(0.1, 0.3, 0.1);
  248.   ren[2]->SetBackground(0.1, 0.1, 0.3);
  249.   ren[3]->AddActor(outlineActor);
  250.   ren[3]->SetBackground(0.1, 0.1, 0.1);
  251.   renWin->SetSize(600, 600);
  252.   // renWin->SetFullScreen(1);

  253.   ren[0]->SetViewport(0, 0, 0.5, 0.5);
  254.   ren[1]->SetViewport(0.5, 0, 1, 0.5);
  255.   ren[2]->SetViewport(0, 0.5, 0.5, 1);
  256.   ren[3]->SetViewport(0.5, 0.5, 1, 1);

  257.   // Set the actors' positions
  258.   //
  259.   renWin->Render();

  260.   ren[3]->GetActiveCamera()->Elevation(110);
  261.   ren[3]->GetActiveCamera()->SetViewUp(0, 0, -1);
  262.   ren[3]->GetActiveCamera()->Azimuth(45);
  263.   ren[3]->GetActiveCamera()->Dolly(1.15);
  264.   ren[3]->ResetCameraClippingRange();

  265.   vtkSmartPointer<vtkInteractorStyleImage> style =
  266.       vtkSmartPointer<vtkInteractorStyleImage>::New();
  267.   iren->SetInteractorStyle(style);
  268.   iren->Initialize();
  269.   iren->Start();

  270.   return 1;
  271. }
复制代码


回复

使用道具 举报

161

主题

409

回帖

1519

积分

版主

积分
1519

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-1-10 19:32:26 | 显示全部楼层
先看看先。。。
回复

使用道具 举报

178

主题

438

回帖

1713

积分

金牌会员

积分
1713

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-1-16 14:26:03 | 显示全部楼层
谢谢你的辛苦劳动了!!!
回复

使用道具 举报

1

主题

412

回帖

843

积分

高级会员

积分
843

最佳新人

发表于 2024-1-18 21:59:26 | 显示全部楼层
先学习一下,以留备用
回复

使用道具 举报

1

主题

441

回帖

1100

积分

版主

积分
1100

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-2-14 15:28:30 | 显示全部楼层
大哥谢了
回复

使用道具 举报

4

主题

415

回帖

1084

积分

版主

积分
1084

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-2-16 23:02:09 | 显示全部楼层
厉害
回复

使用道具 举报

161

主题

409

回帖

1519

积分

版主

积分
1519

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-3-12 06:24:28 | 显示全部楼层
次贴无用,检定完毕!
回复

使用道具 举报

149

主题

462

回帖

1611

积分

版主

积分
1611

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-3-13 10:11:11 | 显示全部楼层
有吸引力,回复看看
回复

使用道具 举报

47

主题

416

回帖

1214

积分

版主

积分
1214

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-4-24 02:15:23 | 显示全部楼层
人生真是寂寞如雪啊。
回复

使用道具 举报

26

主题

419

回帖

1128

积分

版主

积分
1128

热心会员推广达人优秀版主荣誉管理论坛元老

发表于 2024-4-25 06:02:12 | 显示全部楼层
先看看在说
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|关于我们|医维基|网站地图|Archiver|手机版|医疗之家 ( 沪ICP备2023001278号-1 )  

GMT+8, 2024-5-4 05:12 , Processed in 0.146129 second(s), 27 queries .

Designed by Medical BBS

快速回复 返回顶部 返回列表