VTK加载DICOM图像并加载RTSTRUCT文件的ContourData

1、使用其他方式读取DICOM RTSTRUCT文件的坐标信息。

2、按照坐标从小到大的顺序将每一个ROI在每一层上面的坐标生成一个vtkPolyData,然后将所有的vtkPolyData组成一个vtkAppendPolyData(如果不按照从小到大的顺序,会影响后面的三维重建)。

3、vtkVoxelContoursToSurfaceFilter对上面得到的vtkAppendPolyData进行三维重建。(设置vtkVoxelContoursToSurfaceFilter的坐标点必须是整数)。

4、vtkTransformPolyDataFilter和vtkTransform对三维模型缩放和平移。

5、将所有的ROI重建的三维模型通过着色,再添加到同一个vtkAppendPolyData中。

6、通过vtkPlaneCutter和vtkPlane切三维模型,就可以得到想要的平面轮廓曲线。

三维重建代码:

 void GetRoiSequences(string path)
 {
     if (string.IsNullOrEmpty(path) || !File.Exists(path)) return;
     DicomDataset dicomDataSet = DicomFile.Open(path).Dataset;
     if (dicomDataSet == null || !dicomDataSet.Contains(DicomTag.StructureSetROISequence) || !dicomDataSet.Contains(DicomTag.ROIContourSequence)) return;
     foreach (DicomDataset roiDataSet in dicomDataSet.GetSequence(DicomTag.StructureSetROISequence))
     {
         if (roiDataSet == null || !roiDataSet.Contains(DicomTag.ROINumber) || !roiDataSet.Contains(DicomTag.ROIName)) continue;
         RoiSequence roiSequence = new RoiSequence();
         roiSequence.RoiNumber = roiDataSet.GetValue<int>(DicomTag.ROINumber, 0);
         roiSequence.RoiName = roiDataSet.GetString(DicomTag.ROIName);
         roiSequences.Add(roiSequence);
     }
     foreach (DicomDataset roiContourDataSet in dicomDataSet.GetSequence(DicomTag.ROIContourSequence))
     {
         if (roiContourDataSet == null || !roiContourDataSet.Contains(DicomTag.ROIDisplayColor)
             || !roiContourDataSet.Contains(DicomTag.ReferencedROINumber) || !roiContourDataSet.Contains(DicomTag.ContourSequence))
             continue;
         RoiSequence? roiSequence = roiSequences.Find(p => p.RoiNumber == roiContourDataSet.GetValue<int>(DicomTag.ReferencedROINumber, 0));
         if (roiSequence == null) continue;
         roiSequence.RoiColor = roiContourDataSet.GetValues<int>(DicomTag.ROIDisplayColor);
         roiSequence.roiContourDatas = new List<RoiContourData>();
         foreach (DicomDataset contour in roiContourDataSet.GetSequence(DicomTag.ContourSequence))
         {
             if (contour == null || !contour.Contains(DicomTag.ContourGeometricType) || !contour.Contains(DicomTag.ContourImageSequence)
            || !contour.Contains(DicomTag.NumberOfContourPoints) || !contour.Contains(DicomTag.ContourData))
                 continue;
             RoiContourData roiContourData = new RoiContourData();
             roiContourData.ContourType = contour.GetString(DicomTag.ContourGeometricType);
             roiContourData.ContourPoints = contour.GetValue<int>(DicomTag.NumberOfContourPoints, 0);
             roiContourData.ContourData = contour.GetValues<double>(DicomTag.ContourData);
             foreach (DicomDataset ContourImage in contour.GetSequence(DicomTag.ContourImageSequence))
             {
                 if (ContourImage == null || !ContourImage.Contains(DicomTag.ReferencedSOPInstanceUID)) continue;
                 roiContourData.RefeRenceSopUId = ContourImage.GetString(DicomTag.ReferencedSOPInstanceUID);
             }
             roiSequence.roiContourDatas.Add(roiContourData);
         }
     }

     double[] orderIndex = new double[2] { -(imagePositionPatient[2] + extent[5] * spacing[2]), -imagePositionPatient[2] };
     foreach (RoiSequence roiSequence in roiSequences)
     {
         if (roiSequence == null || roiSequence.RoiColor == null || roiSequence.roiContourDatas == null) continue;
         vtkAppendPolyData appendFilter = vtkAppendPolyData.New();
         for (double i = orderIndex[0]; i <= orderIndex[1]; i += (float)spacing[2])
         {
             foreach (RoiContourData roiContour in roiSequence.roiContourDatas)
             {
                 if (roiContour == null || roiContour.ContourData == null || roiContour.ContourData.Length == 0) continue;
                 if (-roiContour.ContourData[2] != i) continue;
                 vtkPolyData circle = vtkPolyData.New();
                 CreateCircle(roiContour, circle);
                 appendFilter.AddInputData(circle);
                 circle.Dispose();
             }
         }
         if (appendFilter.GetNumberOfInputConnections(0) == 0)
         {
             return;
         }
         appendFilter.Update();
         vtkPolyData contours = appendFilter.GetOutput();
         roiSequence.roiBounds = contours.GetBounds();
         roiSequence.roiOrigin = new double[3] { roiSequence.roiBounds[0], roiSequence.roiBounds[2], roiSequence.roiBounds[4] };
         roiSequence.roiCenter = contours.GetCenter();
         vtkPolyData poly = vtkPolyData.New();
         vtkPoints points = vtkPoints.New();
         long numPoints = contours.GetPoints().GetNumberOfPoints();
         points.SetNumberOfPoints(numPoints);
         for (int i = 0; i < numPoints; ++i)
         {
             double[] pt = new double[3];
             pt = contours.GetPoints().GetPoint(i);
             pt[0] = (int)((pt[0] - roiSequence.roiOrigin[0]) / spacing[0] + 0.5);
             pt[1] = (int)((pt[1] - roiSequence.roiOrigin[1]) / spacing[1] + 0.5);
             pt[2] = (int)((pt[2] - roiSequence.roiOrigin[2]) / spacing[2] + 0.5);
             points.SetPoint(i, pt[0], pt[1], pt[2]);
         }
         poly.SetPolys(contours.GetPolys());
         poly.SetPoints(points);
         vtkVoxelContoursToSurfaceFilter contoursToSurface = vtkVoxelContoursToSurfaceFilter.New();
         contoursToSurface.SetInputData(poly);
         contoursToSurface.SetSpacing(spacing[0], spacing[1], spacing[2]);
         contoursToSurface.Update();

         roiSequence.scaleCenter = contoursToSurface.GetOutput().GetCenter();
         roiSequence.scaleBounds = contoursToSurface.GetOutput().GetBounds();

         vtkTransformPolyDataFilter transformFilter = vtkTransformPolyDataFilter.New();
         transformFilter.SetInputData(contoursToSurface.GetOutput());
         vtkTransform transform = vtkTransform.New();
         transformFilter.SetTransform(transform);
         transform.Translate(-roiSequence.scaleCenter[0], -roiSequence.scaleCenter[1], -roiSequence.scaleCenter[2]);
         transform.Scale((roiSequence.roiBounds[1] - roiSequence.roiBounds[0]) / (roiSequence.scaleBounds[1] - roiSequence.scaleBounds[0]),
                          (roiSequence.roiBounds[3] - roiSequence.roiBounds[2]) / (roiSequence.scaleBounds[3] - roiSequence.scaleBounds[2]),
                          (roiSequence.roiBounds[5] - roiSequence.roiBounds[4]) / (roiSequence.scaleBounds[5] - roiSequence.scaleBounds[4]));
         transform.Translate(roiSequence.roiCenter[0], roiSequence.roiCenter[1], roiSequence.roiCenter[2]);
         transformFilter.Update();

         roiSequence.roiPolyData = vtkPolyData.New();
         roiSequence.roiPolyData.DeepCopy(transformFilter.GetOutput());
         appendFilter.Dispose();
         contours.Dispose();
         poly.Dispose();
         points.Dispose();
         contoursToSurface.Dispose();
         transformFilter.Dispose();
         transform.Dispose();
     }
     foreach (RoiSequence roiSequence in roiSequences)
     {
         if (roiSequence == null || roiSequence.RoiColor == null || roiSequence.roiContourDatas == null || roiSequence.roiPolyData == null ||
             roiSequence.roiBounds == null || roiSequence.roiOrigin == null || roiSequence.scaleCenter == null || roiSequence.scaleBounds == null ||
             roiSequence.roiCenter == null) continue;
         vtkUnsignedCharArray scalars = vtkUnsignedCharArray.New();
         scalars.SetNumberOfComponents(3);
         for (int i = 0; i < roiSequence.roiPolyData.GetNumberOfPoints(); i++)
         {
             scalars.InsertNextTuple3(roiSequence.RoiColor[0], roiSequence.RoiColor[1], roiSequence.RoiColor[2]); //set color index to 1
         }
         roiSequence.roiPolyData.GetPointData().SetScalars(scalars);
         appendFilter.AddInputData(roiSequence.roiPolyData);
     }
     appendFilter.Update();
 }

void CreateCircle(RoiContourData roiContour, vtkPolyData polyData)
{
    if (roiContour == null || roiContour.ContourData == null || roiContour.ContourData.Length == 0) return;
    vtkPoints points = vtkPoints.New();
    vtkCellArray cells = vtkCellArray.New();

    points.SetNumberOfPoints((long)roiContour.ContourData.Length / 3);
    cells.Allocate(1, (long)roiContour.ContourData.Length / 3);
    cells.InsertNextCell(roiContour.ContourData.Length / 3);
    int index = 0;
    for (int i = 0; i < roiContour.ContourData.Length; i += 3)
    {
        points.SetPoint(index, roiContour.ContourData[i], -roiContour.ContourData[i + 1], -roiContour.ContourData[i + 2]);
        cells.InsertCellPoint(index);
        index += 1;
    }
    polyData.Initialize();
    polyData.SetPolys(cells);
    polyData.SetPoints(points);
    points.Dispose();
    cells.Dispose();
}

切面代码:
 

  dicomCenter = imageResliceAxial.GetResliceAxesOrigin();
  roiImageActorAxial.Clear();
  planeAxial.SetOrigin(dicomCenter[0], dicomCenter[1], dicomCenter[2]);
  planeAxial.SetNormal(0, 0, 1);
 
  cutterAxial.SetInputData(appendFilter.GetOutput());
  cutterAxial.SetPlane(planeAxial);
  cutterAxial.BuildTreeOff();
  cutterAxial.Update();

  vtkCompositeDataGeometryFilter geometryFilter = vtkCompositeDataGeometryFilter.New();
  geometryFilter.SetInputData(cutterAxial.GetOutput());

  vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
  mapper.SetInputConnection(geometryFilter.GetOutputPort());

  vtkTransform transform = vtkTransform.New();
  transform.Translate(-IsocenterPosition[0], -IsocenterPosition[1], 0);

  // 创建一个vtkActor对象,用于表示vtkPolyDataMapper对象的输出
  vtkActor actor = vtkActor.New();
  actor.SetMapper(mapper);
  actor.SetPosition(-dicomCenter[0], -dicomCenter[1], -dicomCenter[2]);
  actor.GetProperty().LightingOff();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ran-莫待无花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值