3d 如何在python中获得dicom切片的三维重建?

3d 如何在python中获得dicom切片的三维重建?,3d,vtk,dicom,pydicom,3d,Vtk,Dicom,Pydicom,我有一个目录,其中包含一次扫描的.dcm文件。我能够获得2D视图(我与其他dicom查看器进行了交叉检查)。但我无法让3D视图正常工作。我尝试使用vtkDICOMImageReader类,但它无法读取文件。因此,我尝试从3D numpy数组中获取一个体积对象,并使用vtkplotter显示它。得出的观点显然是错误的。我认为3D阵列需要一些处理 import time import glob import pydicom import numpy as np from vtkplotter imp

我有一个目录,其中包含一次扫描的.dcm文件。我能够获得2D视图(我与其他dicom查看器进行了交叉检查)。但我无法让3D视图正常工作。我尝试使用
vtkDICOMImageReader
类,但它无法读取文件。因此,我尝试从3D numpy数组中获取一个体积对象,并使用
vtkplotter
显示它。得出的观点显然是错误的。我认为3D阵列需要一些处理

import time
import glob
import pydicom
import numpy as np
from vtkplotter import Volume
import sys, os

def main(folderPath):
    st = time.time()
    my_glob = glob.glob1(folderPath, "*")
    numFiles = 0
    rejected = 0

    # return if empty directory
    if len(my_glob) == 0:
        return False

    # get all readable dicom files in  array
    tem = []
    for file in list(my_glob):
        try:
            data_item = pydicom.dcmread(os.path.join(folderPath, file))
            if hasattr(data_item, 'SliceLocation'):
                tem.append(data_item)
                numFiles += 1
            else:
                rejected += 1
                print(file)
        except Exception as e:
            pass
    print("read done %s | %d files | %d rejected" % (time.time() - st, numFiles, rejected))
    if len(tem) <= 0:
        return False

    tem.sort(key=lambda x: x.InstanceNumber)

    # make 3d np array from all slices
    unset = True
    for i in range(len(tem)):
        arr = tem[i].pixel_array.astype(np.float32)
        if unset:
            imShape = (arr.shape[0], arr.shape[1], len(tem))
            scaledIm = np.zeros(imShape)
            pix_spacing = tem[i].PixelSpacing
            dist = 0
            for j in range(2):
                cs = [float(q) for q in tem[j].ImageOrientationPatient]
                ipp = [float(q) for q in tem[j].ImagePositionPatient]
                parity = pow(-1, j)
                dist += parity*(cs[1]*cs[5] - cs[2]*cs[4])*ipp[0]
                dist += parity*(cs[2]*cs[3] - cs[0]*cs[5])*ipp[1]
                dist += parity*(cs[0]*cs[4] - cs[1]*cs[3])*ipp[2]
            z_spacing = abs(dist)
            slope = tem[i].RescaleSlope
            intercept = tem[i].RescaleIntercept
            unset = False
        scaledIm[:, :, i] = arr

    # convert to hounsfield units
    scaledIm = slope*scaledIm + intercept
    pix_spacing.append(z_spacing)

    wl = 300    # window parameters for Angio
    ww = 600

    windowed = np.zeros(imShape, dtype=np.uint8)
    # allImages[scaledIm <= (wl-0.5-(ww-1)/2.0)] = 0
    k = np.logical_and(scaledIm > (wl-0.5-(ww-1)/2.0), scaledIm <= (wl-0.5+(ww-1)/2.0))
    windowed[k] = ((scaledIm[k] - (wl-0.5))/(ww-1)+0.5)*255
    windowed[scaledIm > (wl-0.5+(ww-1)/2.0)] = 255
    # windowed image (in 2D) is correct i checked visually in other DICOM viewers
    print("arrays made %s" % (time.time() - st))


    # Volume(scaledIm, spacing=pix_spacing).show(bg="black")
    Volume(windowed, spacing=pix_spacing).show(bg="black")

    # X, Y, Z = np.mgrid[:30, :30, :30]
    # scalar_field = ((X-15)**2 + (Y-15)**2 + (Z-15)**2)/225
    # Volume(scalar_field, spacing=pix_spacing).show(bg="black")      # looks good on this example


if __name__ == '__main__':
    folder = sys.argv[1]
    main(folder)

导入时间
导入glob
导入pydicom
将numpy作为np导入
从vtkplotter导入卷
导入系统,操作系统
def主(文件夹路径):
st=时间。时间()
my_glob=glob.glob1(folderPath,“*”)
numFiles=0
拒绝=0
#如果目录为空,则返回
如果len(my_glob)==0:
返回错误
#获取数组中的所有可读dicom文件
tem=[]
对于列表中的文件(my_glob):
尝试:
data_item=pydicom.dcmread(os.path.join(folderPath,file))
如果hasattr(数据项“切片位置”):
附加项(数据项)
numFiles+=1
其他:
拒绝+=1
打印(文件)
例外情况除外,如e:
通过
打印(“读取完成%s |%d个文件|%d个已拒绝”%(time.time()-st,numFiles,已拒绝))

如果len(tem)我无法再现该问题,因为我从pydicom收到一条错误消息:

AttributeError:“FileDataset”对象没有属性“RescaleSlope”

无论如何,您可以尝试以下方法:

  • 更新至最新提交
    pip-install-git+https://github.com/marcomusy/vtkplotter.git

  • 实例化修改为:

#请注意,pix_间距[0]和pix_间距[2]可能是反向的
体积=体积(带窗口,间距=像素间距)
第二卷,第1卷,第0卷,镜像(“y”)
卷展(bg=“黑色”)
你也可以退房

  • 另一种可能是使用
    load(mydicomdir,threshold=False)
    直接加载目录,这将返回一个
  • 请随时打开一个问题