The xyz in the luna16 label data and the three values in the dicom.ImagePositionPatient of CT respectively represent the initial points of which axes

Let’s take a look at which axis the three values ​​in dicom.ImagePositionPatient represent. Note that x corresponds to Origin[0], y corresponds to Origin[1], and z corresponds to Origin[2] in the first code. The source of Origin is the following code: Ps: Some of the things inside have troubled me a lot. Here I will record my understanding when my head is clear to prevent confusion in the future.

Let's take a look at the picture first to see how the CT is taken:

So we don't look at the Z axis first, just look at the X and Y axes, and we can see that X is a column and Y is a row. This is very similar to what we usually draw on the map. Picture reference: https://www.cnblogs.com/h2zZhou/p/9072967.html

The dicom.ImagePositionPatient is directly read from the dicom generated by the device, so the three values ​​in dicom.ImagePositionPatient represent the initial points of the X axis, Y axis, and Z axis. It must be noted that X is a column and Y is a row.

Let's take a look at the xyz in the luna16 label data. My previous blog post https://blog.csdn.net/qq_36401512/article/details/85163467 was used to visualize labels in two dimensions. The details can be seen by yourself. We only look at two pieces of code:

 x, y, z = int((nodules[idx, 0]-Origin[0])/SP[0]), int((nodules[idx, 1]-Origin[1])/SP[1]),
 int((nodules[idx, 2]-Origin[2])/SP[2])
# 注意 y代表纵轴,x代表横轴
data[max(0, y - radius):min(data.shape[0], y + radius),
max(0, x - radius - pad):max(0, x - radius)] = 3000  # 竖线
data[max(0, y - radius):min(data.shape[0], y + radius),
min(data.shape[1], x + radius):min(data.shape[1], x + radius + pad)] = 3000  # 竖线
data[max(0, y - radius - pad):max(0, y - radius),
max(0, x - radius):min(data.shape[1], x + radius)] = 3000  # 横线
data[min(data.shape[0], y + radius):min(data.shape[0], y + radius + pad),
max(0, x - radius):min(data.shape[1], x + radius)] = 3000  # 横线

You can notice that x corresponds to nodules[idx, 0], y corresponds to nodules[idx,1], and z corresponds to nodules[idx,2]. The way to mark the label in the following paragraph is to assign a large value. But there is a note y represents the vertical axis, and x represents the horizontal axis. Looking at the y-related parameters in the first line of the above code as the first dimension when data is assigned, the above comments are further confirmed.

For example, we know that the two-dimensional matrix A is assigned to the point (x1, y1) to represent A [x1, y1]. When drawing a picture, to mark the point (x1, y1) requires the following code:

plt.ion()
plt.scatter(y1, x1, marker='o', color='red', s=10, label='First')
plt.imshow(A, cmap=plt.cm.bone)

If it is still ambiguous, let's take a look at the first piece of code where x corresponds to Origin[0], y corresponds to Origin[1], and z corresponds to Origin[2]. The acquisition of Origin is the following code:

filename='E:\\JLS\\dcm_data\\luna\\subset1\\1.3.6.1.4.1.14519.5.2.1.6279.6001.173106154739244262091404659845.mhd'
itkimage = sitk.ReadImage(filename)#读取.mhd文件
Origin=itkimage.GetOrigin()

And itkimage.GetOrigin() is the same as the ImagePositionPatient of the first dicom of this CT sequence. In this way, it can be seen that the label data of luna16 is the same as the axis represented by dicom.ImagePositionPatient, and coordY represents the column and coordX represents the row.

 

 

PS: 2019.11.6 The conclusion of the blog has been written three times, the general process: it is like this, if it is not reversed, it is like that, still like this. Finally, in order to ensure the correctness, I wrote again to draw the results according to the labels, using luna16 data and the data of the current project. The specific code is as follows:

# coding=UTF-8
import cv2
import numpy as np
from PIL import Image
from scipy import misc
import os
import sys
import cv2
from skimage import measure, morphology, segmentation
import matplotlib.pyplot as plt

import SimpleITK as sitk
import pandas

MIN_BOUND = -1000.0
MAX_BOUND = 400.0


def normalize(image):
    image = (image - MIN_BOUND) / (MAX_BOUND - MIN_BOUND)
    image[image > 1] = 1.
    image[image < 0] = 0.
    return image

def load_itk_image(filename):
    with open(filename) as f:
        contents = f.readlines()
        line = [k for k in contents if k.startswith('TransformMatrix')][0]
        transformM = np.array(line.split(' = ')[1].split(' ')).astype('float')
        transformM = np.round(transformM)
        if np.any(transformM != np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])):
            isflip = True
        else:
            isflip = False

    itkimage = sitk.ReadImage(filename)
    numpyImage = sitk.GetArrayFromImage(itkimage)

    numpyOrigin = np.array(list(reversed(itkimage.GetOrigin())))
    numpySpacing = np.array(list(reversed(itkimage.GetSpacing())))

    return numpyImage, numpyOrigin, numpySpacing, isflip


F_path='Tannotations.csv'
L_path='annotations.csv'
F='/FORNEWTEST/change/NewForTest'
L='dcm_data/luna/subsets'

annosF = np.array(pandas.read_csv(F_path))
annosL = np.array(pandas.read_csv(L_path))

nameF = annosF[0][0]
nameL = annosL[55][0]
coordXF,coordYF,coordZF=annosF[0][1],annosF[0][2],annosF[0][3]
coordXL,coordYL,coordZL=annosL[55][1],annosL[55][2],annosL[55][3]
print(nameF,nameL)

for root, dirs, files in os.walk(F):
    for file in files:
        if (file[:-4] == nameF and file[-4:] == '.mhd'):
            sliceim, origin, spacing, isflip = load_itk_image(
                        os.path.join(root, file))
            ZF=np.absolute(coordZF-origin[0])/spacing[0]
            YF=np.absolute(coordYF-origin[1])/spacing[1]
            XF = np.absolute(coordXF - origin[2]) / spacing[2]
            imgF=sliceim[ZF]
            plt.ion()
            plt.scatter(XF, YF, marker='o', color='red', s=10, label='First')
            plt.imshow(imgF, cmap=plt.cm.bone)
            plt.show()

for root, dirs, files in os.walk(L):
    for file in files:
        if (file[:-4] == nameL and file[-4:] == '.mhd'):
            sliceim, origin, spacing, isflip = load_itk_image(os.path.join(root, file))
            ZL=int(np.absolute(coordZL-origin[0])/spacing[0])
            YL=np.absolute(coordYL-origin[1])/spacing[1]
            XL = np.absolute(coordXL - origin[2]) / spacing[2]
            imgL=sliceim[ZL]
            imgC=imgL[YL-20:YL+20,XL-20:XL+20]
            plt.ion()
            plt.scatter(XL, YL, marker='o', color='red', s=2, label='First')
            plt.imshow(imgL, cmap=plt.cm.bone)
            plt.show()
            plt.imshow(imgC, cmap=plt.cm.bone)
            plt.show()

Now the idea is finally very clear. Seeing is believing!

Guess you like

Origin blog.csdn.net/qq_36401512/article/details/102921085
xyz