vtk勾画rtstruct坐标轮廓

使用fo-dicom读取rtstruct文件,拿到roi的轮廓坐标之后再勾画到原始图像上面的时候方向和原始图像的方向是相反的,这个问题怎么处理?

img

代码如下:

void SetRoiContour()
        {
            foreach (vtkActor contourActor in ContourActors)
            {
                imageViewer2.GetRenderer().RemoveViewProp(contourActor);
            }
            ContourActors = new List<vtkActor>();
            string SopUId = dicomDataset.GetStringValue(DicomTag.SOPInstanceUID);
            int rows = dicomImageReader.GetHeight();
            float[] imagePositionPatient = dicomImageReader.GetImagePositionPatient();
            double[] spacing = dicomImageReader.GetDataSpacing();
            foreach (RoiSequence roiSequence in RoiSequences)
            {
                if (roiSequence == null || roiSequence.RoiColor == null || roiSequence.roiContourDatas == null) continue;
                List<RoiContourData> roiContourData = roiSequence.roiContourDatas.FindAll(p => p.RefeRenceSopUId == SopUId);
                if (roiContourData == null) continue;
                foreach (RoiContourData roiContour in roiContourData)
                {
                    if (roiContour.ContourData == null) continue;
                    // 创建一个空的vtkPoints对象,用于存储轮廓的顶点坐标
                    var contourPoints = vtkPoints.New();
                    // 创建一个空的vtkCellArray对象,用于存储轮廓的多边形拓扑信息
                    var contourCells = vtkCellArray.New();
                    // 创建一个vtkPolyLine对象,用于表示轮廓的多边形线段
                    var polyLine = new vtkPolyLine();
                    // 获取轮廓点数
                    var contourPointsNumber = roiContour.ContourData.Length / 3;
                    // 设置polyLine的点数为numberOfContourPoints
                    polyLine.GetPointIds().SetNumberOfIds(contourPointsNumber);
                    // 将轮廓坐标添加到vtkPoints对象中,并记录其索引
                    var contourPointIds = new List<int>();
                    for (int i = 0; i < roiContour.ContourData.Length; i += 3)
                    {
                        
                        double[] doubles = new double[3];
                        doubles[0] = (roiContour.ContourData[i] - imagePositionPatient[0]);
                        doubles[1] = (roiContour.ContourData[i + 1] - imagePositionPatient[1]);
                        doubles[2] = 1;


                        int contourPointId = (int)contourPoints.InsertNextPoint(doubles[0], doubles[1], doubles[2]);
                        contourPointIds.Add(contourPointId);
                    }
                    // 根据轮廓点数创建一个对应的vtkPolyLine对象,并设置其顶点索引
                    for (int i = 0; i < contourPointsNumber; i++)
                    {
                        polyLine.GetPointIds().SetId(i, contourPointIds[i]);
                    }
                    // 将轮廓多边形添加到vtkCellArray对象中
                    contourCells.InsertNextCell(polyLine);
                    

                    // 创建一个vtkPolyData对象,用于存储轮廓的顶点和多边形
                    vtkPolyData contourPolydata = vtkPolyData.New();
                    contourPolydata.SetPoints(contourPoints);
                    contourPolydata.SetLines(contourCells);
                    // 创建一个vtkPolyDataMapper对象,用于映射轮廓的几何数据到图形基元上
                    var contourMapper = vtkPolyDataMapper.New();
                    contourMapper.SetInputData(contourPolydata);
                    // 创建一个vtkActor对象,用于显示轮廓的颜色和透明度
                    var contourActor = vtkActor.New();
                    contourActor.SetMapper(contourMapper);
                    contourActor.GetProperty().SetColor(roiSequence.RoiColor[0], roiSequence.RoiColor[1], roiSequence.RoiColor[2]);
                    contourActor.GetProperty().SetOpacity(0.5);
                    ContourActors.Add(contourActor);
                }
            }
            foreach (var contourActor in ContourActors)
            {
                imageViewer2.GetRenderer().AddActor(contourActor);
            }

        }

  • 以下回答由chatgpt基于相关博客总结生成:

    对于原问题,可以通过调整绘制轮廓的顺序来解决方向相反的问题。具体步骤如下:

    1. 获取轮廓坐标后,按顺序将坐标点分别存储在两个列表中,分别为x_points和y_points。

    2. 对y_points列表中的坐标进行倒序操作,即将y_points列表反转,可以使用Python内置函数reverse()进行操作。

    3. 将x_points和y_points列表中的坐标顺序重新组合,并将其作为参数传递给绘制轮廓的函数进行绘制。

    具体代码如下:

    # 原始代码获取的轮廓坐标
    x_points = [100, 120, 140, 160, 180, 200, 220, 240, 260]
    y_points = [50, 70, 90, 110, 130, 150, 170, 190, 210]
    
    # 对y_points进行反转操作
    y_points.reverse()
    
    # 组合x_points和y_points
    points = []
    for i in range(len(x_points)):
        points.append((x_points[i], y_points[i]))
    
    # 调用绘制轮廓的函数,并传入重新组合后的点坐标
    draw_contour(points)
    

    另外,使用3D Slicer将实验结果转换为DICOM-RT的过程可以参考上述提供的参考资料,按照步骤操作即可。

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
根据你提供的代码,使用的是VTK库来显示RTSTRUCT中的轮廓信息。可能是由于VTK中的坐标系和DICOM中的坐标系的方向不同,导致显示的轮廓方向和DICOM图像的方向相反。

DICOM图像中的坐标系是一个右手坐标系,即X轴指向左侧,Y轴指向前方,Z轴指向头顶。而VTK中的坐标系是一个左手坐标系,即X轴指向右侧,Y轴指向头顶,Z轴指向前方。所以,当你将轮廓坐标从DICOM中读取出来之后,需要将其坐标系转换到VTK中的坐标系。

可以通过以下方式将DICOM中的坐标转换为VTK中的坐标:

  1. 将DICOM中的坐标系原点(ImagePositionPatient)作为VTK中的坐标系原点。

  2. 将DICOM中的X轴(ImageOrientationPatient的前3个元素)作为VTK中的Y轴。

  3. 将DICOM中的Y轴(ImageOrientationPatient的后3个元素)作为VTK中的X轴。

  4. 将DICOM中的Z轴(ImageOrientationPatient的前两个元素的叉积)作为VTK中的Z轴。

具体实现可以参考以下代码:

double[] vtkImagePositionPatient = new double[3];
vtkImagePositionPatient[0] = imagePositionPatient[0];
vtkImagePositionPatient[1] = imagePositionPatient[1];
vtkImagePositionPatient[2] = imagePositionPatient[2];

double[] vtkImageOrientationPatient = new double[9];
vtkImageOrientationPatient[0] = imageOrientationPatient[1];
vtkImageOrientationPatient[1] = imageOrientationPatient[0];
vtkImageOrientationPatient[2] = -imageOrientationPatient[2];
vtkImageOrientationPatient[3] = imageOrientationPatient[4];
vtkImageOrientationPatient[4] = imageOrientationPatient[3];
vtkImageOrientationPatient[5] = -imageOrientationPatient[5];
vtkImageOrientationPatient[6] = imageOrientationPatient[6];
vtkImageOrientationPatient[7] = imageOrientationPatient[7];
vtkImageOrientationPatient[8] = -imageOrientationPatient[8];

double[] vtkContourPoints = new double[roiContour.ContourData.Length];
for (int i = 0; i < roiContour.ContourData.Length; i += 3)
{
    vtkContourPoints[i] = roiContour.ContourData[i] - vtkImagePositionPatient[0];
    vtkContourPoints[i + 1] = roiContour.ContourData[i + 1] - vtkImagePositionPatient[1];
    vtkContourPoints[i + 2] = roiContour.ContourData[i + 2] - vtkImagePositionPatient[2];
    double x = vtkContourPoints[i];
    double y = vtkContourPoints[i + 1];
    double z = vtkContourPoints[i + 2];
    double newX = vtkImageOrientationPatient[0] * x + vtkImageOrientationPatient[3] * y + vtkImageOrientationPatient[6] * z;
    double newY = vtkImageOrientationPatient[1] * x + vtkImageOrientationPatient[4] * y + vtkImageOrientationPatient[7] * z;
    double newZ = vtkImageOrientationPatient[2] * x + vtkImageOrientationPatient[5] * y + vtkImageOrientationPatient[8] * z;
    vtkContourPoints[i] = newY;
    vtkContourPoints[i + 1] = newX;
    vtkContourPoints[i + 2] = -newZ;
}

其中,imageOrientationPatient是DICOM中的ImageOrientationPatient,是一个6个元素的数组,前3个元素是X轴的方向向量,后3个元素是Y轴的方向向量。vtkImageOrientationPatient是转换后的VTK中的方向向量,也是一个9个元素的数组,前3个元素是VTK中的Y轴方向向量,后3个元素是VTK中的X轴方向向量,最后3个元素是VTK中的Z轴方向向量。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
该问题的原因是DICOM文件中的像素数据可能存在旋转和镜像,导致RTSTRUCT文件中获取到的坐标系与原始DICOM图像的坐标系不一致。

解决方法:

一种简单的方法是通过官方提供的DICOM标准中的方向信息来解决,即使用DICOM文件中的Image Orientation (0020,0037)标签来确定轮廓的方向,其中包含了两个矢量,每个矢量具有三个元素,描述了图像的行方向和列方向。通过计算这两个向量的叉积,可以确定图像数据的Z轴方向。同时也可以使用imagePositionPatient (0020,0032)标签来确定图像的位置信息。

下面是代码实现:

// 获取方向向量信息
double[] imageOrientationPatient = dicomDataset.GetValues<double>(DicomTag.ImageOrientationPatient);
var rowDirection = new double[3];
var columnDirection = new double[3];
var normalDirection = new double[3];

rowDirection[0] = imageOrientationPatient[0];
rowDirection[1] = imageOrientationPatient[1];
rowDirection[2] = imageOrientationPatient[2];

columnDirection[0] = imageOrientationPatient[3];
columnDirection[1] = imageOrientationPatient[4];
columnDirection[2] = imageOrientationPatient[5];

normalDirection[0] = rowDirection[1] * columnDirection[2] - rowDirection[2] * columnDirection[1];
normalDirection[1] = rowDirection[2] * columnDirection[0] - rowDirection[0] * columnDirection[2];
normalDirection[2] = rowDirection[0] * columnDirection[1] - rowDirection[1] * columnDirection[0];

// 获取图像位置信息
double[] imagePositionPatient = dicomDataset.GetValues<double>(DicomTag.ImagePositionPatient);

// 根据方向向量和位置信息调整轮廓坐标
for (int i = 0; i < roiContour.ContourData.Length; i += 3)
{
    double[] pos = new double[3];
    pos[0] = roiContour.ContourData[i] - imagePositionPatient[0];
    pos[1] = roiContour.ContourData[i + 1] - imagePositionPatient[1];
    pos[2] = roiContour.ContourData[i + 2] - imagePositionPatient[2];
    double r = pos[0] * rowDirection[0] + pos[1] * rowDirection[1] + pos[2] * rowDirection[2];
    double c = pos[0] * columnDirection[0] + pos[1] * columnDirection[1] + pos[2] * columnDirection[2];
    double n = pos[0] * normalDirection[0] + pos[1] * normalDirection[1] + pos[2] * normalDirection[2];

    roiContour.ContourData[i] = r;
    roiContour.ContourData[i + 1] = c;
    roiContour.ContourData[i + 2] = n;
}

另外,需要注意的是,在对轮廓坐标系进行旋转或者翻转之前,应该记录下原始图像的方向信息,以便后续使用。
如果我的回答解决了您的问题,请采纳!