ActiViz.Net实现MPR功能

img


通过vtkResliceImageViewer事项MRP功能,得到的XY切面和YZ切面的图像都是反向的,而且XZ切面的图像还是反向加翻转的,这个问题怎么处理?


dicomImageReader = vtkDICOMImageReader.New();
            dicomImageReader.SetDirectoryName(DicPath);
            dicomImageReader.Update();

            resliceImageViewers = new vtkResliceImageViewer[SliceNum];
            for (int i = 0; i < SliceNum; i++)
            {
                resliceImageViewers[i] = vtkResliceImageViewer.New();
                resliceImageViewers[i].SetInputData(dicomImageReader.GetOutput());
                vtkResliceCursorLineRepresentation rep = vtkResliceCursorLineRepresentation.SafeDownCast(resliceImageViewers[i].GetResliceCursorWidget().GetRepresentation());
                for (int k = 0; k < 3; k++)
                {
                    rep.GetResliceCursorActor().GetCenterlineProperty(k).SetRepresentationToWireframe();
                    rep.GetResliceCursorActor().GetCenterlineProperty(k).RenderLinesAsTubesOn();
                    rep.GetResliceCursorActor().GetCenterlineProperty(k).SetLineWidth(2);
                    switch (k)
                    {
                        case 0:
                            ;
                            rep.GetResliceCursorActor().GetCenterlineProperty(k).SetColor(0, 0, 255);
                            break;
                        case 1:
                            rep.GetResliceCursorActor().GetCenterlineProperty(k).SetColor(0, 255, 0);
                            break;
                        case 2:
                            rep.GetResliceCursorActor().GetCenterlineProperty(k).SetColor(255, 0, 0);
                            break;
                    }
                }


                switch (i)
                {
                    case 0:
                        {
                            resliceImageViewers[i].SetRenderWindow(renderWindowControlAxial.RenderWindow);
                            resliceImageViewers[i].SetupInteractor(renderWindowControlAxial.RenderWindow.GetInteractor());
                            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToZAxis();
                            resliceImageViewers[i].SetSliceOrientationToXY();
                            break;
                        }
                    case 1:
                        {
                            resliceImageViewers[i].SetRenderWindow(renderWindowControlSagittal.RenderWindow);
                            resliceImageViewers[i].SetupInteractor(renderWindowControlSagittal.RenderWindow.GetInteractor());
                            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToXAxis();
                            resliceImageViewers[i].SetSliceOrientationToYZ();
                            break;
                        }
                    case 2:
                        {
                            resliceImageViewers[i].SetRenderWindow(renderWindowControlCoronal.RenderWindow);
                            resliceImageViewers[i].SetupInteractor(renderWindowControlCoronal.RenderWindow.GetInteractor());
                            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToYAxis();
                            resliceImageViewers[i].SetSliceOrientationToXZ();
                            break;
                        }
                }


                resliceImageViewers[i].SetResliceModeToAxisAligned();
                resliceImageViewers[i].SetLookupTable(resliceImageViewers[0].GetLookupTable());
                resliceImageViewers[i].SetColorWindow(DefaultWindowLevel[0]);
                resliceImageViewers[i].SetColorLevel(DefaultWindowLevel[1]);
                resliceImageViewers[i].SetThickMode(0);
                resliceImageViewers[i].SetResliceMode(1);
                rep.SetManipulationMode(2);
                resliceImageViewers[i].SetResliceCursor(resliceImageViewers[0].GetResliceCursor());
                //resliceImageViewers[i].GetResliceCursorWidget().SetEnabled(1);
                resliceImageViewers[i].GetResliceCursorWidget().SetManageWindowLevel(0);
                resliceImageViewers[i].SetSlice(resliceImageViewers[i].GetSliceMax() / 2);

                resliceImageViewers[i].GetRenderer().ResetCameraScreenSpace();
                resliceImageViewers[i].Render();
                resliceImageViewers[i].Reset();

            }

自己可以代码翻转吗,用类似opencv之类的

vtk源码写死了一部分东西,修改vtk源码或者加载图像后重新设置视角和平面即可

void vtkResliceCursor::Reset()
{
  this->XAxis[0] = 1.0;
  this->XAxis[1] = 0.0;
  this->XAxis[2] = 0.0;

  this->YAxis[0] = 0.0;
  this->YAxis[1] = 1.0;
  this->YAxis[2] = 0.0;

  this->ZAxis[0] = 0.0;
  this->ZAxis[1] = 0.0;
  this->ZAxis[2] = 1.0;

  this->XViewUp[0] = 0.0;
  this->XViewUp[1] = 0.0;
  this->XViewUp[2] = 1.0;

  this->YViewUp[0] = 0.0;
  this->YViewUp[1] = 0.0;
  this->YViewUp[2] = 1.0;

  this->ZViewUp[0] = 0.0;
  this->ZViewUp[1] = -1.0;
  this->ZViewUp[2] = 0.0;

  if (this->GetImage())
  {
    this->GetImage()->GetCenter(this->Center);
  }
  else
  {
    this->Center[0] = 0.0;
    this->Center[1] = 0.0;
    this->Center[2] = 0.0;
  }

  for (int i = 0; i < 3; i++)
  {
    this->GetPlane(i)->SetOrigin(this->Center);
  }

  this->ReslicePlanes->GetItem(0)->SetNormal(1, 0, 0);
  this->ReslicePlanes->GetItem(1)->SetNormal(0, -1, 0);
  this->ReslicePlanes->GetItem(2)->SetNormal(0, 0, 1);

  this->BuildCursorTopology();
  this->BuildCursorGeometry();

  this->Modified();
}

void vtkResliceImageViewer::UpdateOrientation()
{
  // Set the camera position

  vtkCamera* cam = this->Renderer ? this->Renderer->GetActiveCamera() : nullptr;
  if (cam)
  {
    switch (this->SliceOrientation)
    {
      case vtkImageViewer2::SLICE_ORIENTATION_XY:
        cam->SetFocalPoint(0, 0, 0);
        cam->SetPosition(0, 0, 1); // -1 if medical ?
        cam->SetViewUp(0, 1, 0);
        break;

      case vtkImageViewer2::SLICE_ORIENTATION_XZ:
        cam->SetFocalPoint(0, 0, 0);
        cam->SetPosition(0, -1, 0); // 1 if medical ?
        cam->SetViewUp(0, 0, 1);
        break;

      case vtkImageViewer2::SLICE_ORIENTATION_YZ:
        cam->SetFocalPoint(0, 0, 0);
        cam->SetPosition(1, 0, 0); // -1 if medical ?
        cam->SetViewUp(0, 0, 1);
        break;
    }
  }
}

vtkResliceImageViewer实现MPR,斜切模式下显示的图像不再是原始图像,而是通过三维重建得到的图像,所以想要在斜切模式下展示正确图像,只需要修改光标类下的图像视角以及切线平面即可

    public static void ResliceCursorReset(this vtkResliceCursor cursor)
        {
            if (cursor == null) return;
            cursor.SetXViewUp(0, 0, -1);
            cursor.SetYViewUp(0, 0, -1);
            cursor.SetZViewUp(0, 1, 0);
            cursor.GetPlane(1).SetNormal(0, 1, 0);
        }

想要原始图像正确展示图像,重新设置相加视角和位置即可

public static void CameraReset(this vtkCamera camera,int sliceIndex)
        {
            if (camera == null) return;
            if (sliceIndex == 0) camera.SetViewUp(0, 0, -1);
            else if (sliceIndex == 1)
            {
                camera.SetPosition(0, 1, 0);
                camera.SetViewUp(0, 0, -1);
                
            }
        }

该回答引用ChatGPT-3.5,仅供参考,不保证完全正确

要解决反向和翻转的问题,可以尝试在创建vtkResliceImageViewer对象之后添加以下代码:

resliceImageViewers[i].SetResliceAxesDirectionCosines(dicomImageReader.GetOutput().GetDirection());
resliceImageViewers[i].SetResliceAxesOrigin(dicomImageReader.GetOutput().GetOrigin());

这将使用DICOM图像的方向余弦和原点信息来设置切面的方向和位置。这样可以确保切面与图像匹配并且不会出现反向或翻转的情况。

在你的代码中,可以将上述代码添加到以下位置:

switch (i)
{
    case 0:
        {
            resliceImageViewers[i].SetRenderWindow(renderWindowControlAxial.RenderWindow);
            resliceImageViewers[i].SetupInteractor(renderWindowControlAxial.RenderWindow.GetInteractor());
            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToZAxis();
            resliceImageViewers[i].SetSliceOrientationToXY();
            break;
        }
    case 1:
        {
            resliceImageViewers[i].SetRenderWindow(renderWindowControlSagittal.RenderWindow);
            resliceImageViewers[i].SetupInteractor(renderWindowControlSagittal.RenderWindow.GetInteractor());
            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToXAxis();
            resliceImageViewers[i].SetSliceOrientationToYZ();
            break;
        }
    case 2:
        {
            resliceImageViewers[i].SetRenderWindow(renderWindowControlCoronal.RenderWindow);
            resliceImageViewers[i].SetupInteractor(renderWindowControlCoronal.RenderWindow.GetInteractor());
            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToYAxis();
            resliceImageViewers[i].SetSliceOrientationToXZ();
            break;
        }
}

// 添加以下代码
resliceImageViewers[i].SetResliceAxesDirectionCosines(dicomImageReader.GetOutput().GetDirection());
resliceImageViewers[i].SetResliceAxesOrigin(dicomImageReader.GetOutput().GetOrigin());

通过这样设置切面的方向和位置,应该能够解决反向和翻转的问题。


该回答引用NewBing,仅供参考,不保证完全正确

根据我从网络上搜索到的信息,ActiViz.Net是一个集成了VTK(可视化工具包)的.NET框架,可以用于在.NET编程语言中使用VTK的强大功能。VTK是一个用于3D图形,数据可视化,数据处理等的面向对象的软件系统。¹


您的代码看起来是使用了vtkResliceImageViewer类来实现MPR功能,这个类可以根据不同的切面方向来显示DICOM图像。²


我注意到您的代码中没有设置切面图像的方向属性,这可能导致图像显示不正确。您可以尝试在每个resliceImageViewer对象上调用SetResliceAxesDirectionCosines方法,传入一个包含三个方向余弦向量的数组,来指定切面图像的方向。³


例如,如果您想让XY切面图像与DICOM图像的方向一致,您可以这样写:

resliceImageViewers[0].SetResliceAxesDirectionCosines(new double[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 });

如果您想让YZ切面图像与DICOM图像的方向一致,您可以这样写:

resliceImageViewers[1].SetResliceAxesDirectionCosines(new double[] { 0, 1, 0, 0, 0, -1, -1, 0, 0 });

如果您想让XZ切面图像与DICOM图像的方向一致,您可以这样写:

resliceImageViewers[2].SetResliceAxesDirectionCosines(new double[] { 1, 0, 0, 0, 0, -1, 0, -1, 0 });

这些方向余弦向量是根据DICOM标准中定义的Image Position和Image Orientation计算得到的。³


源: 与必应的对话, 2023/7/18
(1) ActiViz .NET User's Guide Version 9 - Kitware Europe. https://www.kitware.eu/wp-content/uploads/2021/02/ActiViz.NET_9.0_Users_Guide.pdf.
(2) GitHub - dikubb/Activiz-Demo: MPR Demo using Activiz. https://github.com/dikubb/Activiz-Demo.
(3) How can i determine the ImagePosition of the reconstructed MPR DICOM image?. https://stackoverflow.com/questions/6846761/how-can-i-determine-the-imageposition-of-the-reconstructed-mpr-dicom-image.
(4) undefined. http://www.kitware.com/.
(5) undefined. https://training.kitware.fr/browse.
(6) undefined. https://www.kitware.eu/service/support.
(7) undefined. https://www.kitware.com/what-we-offer/#books.
(8) undefined. http://www.vtk.org/.
(9) undefined. http://www.slicer.org/.
(10) undefined. http://www.paraview.org/.

该回答引用ChatGPT-4.0,仅供参考。
要解决反向和翻转的问题,可以尝试在创建vtkResliceImageViewer对象之后添加以下代码:

resliceImageViewers[i].SetResliceAxesDirectionCosines(dicomImageReader.GetOutput().GetDirection());
resliceImageViewers[i].SetResliceAxesOrigin(dicomImageReader.GetOutput().GetOrigin());

这将使用DICOM图像的方向余弦和原点信息来设置切面的方向和位置。这样可以确保切面与图像匹配并且不会出现反向或翻转的情况。

在你的代码中,可以将上述代码添加到以下位置:

switch (i)
{
    case 0:
        {
            resliceImageViewers[i].SetRenderWindow(renderWindowControlAxial.RenderWindow);
            resliceImageViewers[i].SetupInteractor(renderWindowControlAxial.RenderWindow.GetInteractor());
            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToZAxis();
            resliceImageViewers[i].SetSliceOrientationToXY();
            break;
        }
    case 1:
        {
            resliceImageViewers[i].SetRenderWindow(renderWindowControlSagittal.RenderWindow);
            resliceImageViewers[i].SetupInteractor(renderWindowControlSagittal.RenderWindow.GetInteractor());
            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToXAxis();
            resliceImageViewers[i].SetSliceOrientationToYZ();
            break;
        }
    case 2:
        {
            resliceImageViewers[i].SetRenderWindow(renderWindowControlCoronal.RenderWindow);
            resliceImageViewers[i].SetupInteractor(renderWindowControlCoronal.RenderWindow.GetInteractor());
            rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormalToYAxis();
            resliceImageViewers[i].SetSliceOrientationToXZ();
            break;
        }
}
 
// 添加以下代码
resliceImageViewers[i].SetResliceAxesDirectionCosines(dicomImageReader.GetOutput().GetDirection());
resliceImageViewers[i].SetResliceAxesOrigin(dicomImageReader.GetOutput().GetOrigin());

C#下窗体应用程序VTK调试开发环境搭建
可以参考下


C#+PclSharp1.12.0+Activiz,开发Winform点云数据处理及可视化程序_pclcsharp_西~风的博客-CSDN博客 C#+PclSharp1.12.0+Activiz,开发Winform点云数据处理及可视化程序_pclcsharp https://blog.csdn.net/swmyaopeng/article/details/126172424