Pydicom+SimpleITK操作DICOM图像数据和TAG

  • 当前的需求是将原始DCM文件进行器官分割后,把得到的图像数据再保存为新的dcm文件,且新的dcm文件头要保留原始DCM的基本信息,以便进行后期分析。操作过程中主要有几个问题:

    1. 本来只用了pydicom库,发现它打不开有压缩的dcm文件,官网也说了只能借助其他工具打开(如gdcm),所以行不通(搞不懂这么好用的pydiocm怎么会有这种问题)
    1. 后来改用Simple ITK库,dcm文件倒是都能打开,但是保存为新的dcm时又出了问题:Simple ITK保存时会自动生成Series UID,而且0002开头的tag都不能修改,导致最后生成的dcm文件都不是一个序列,十分蛋疼
    1. 中间就差自己写代码解码dcm文件了,最后是结合pydicom和simpleitk,即用simpleitk读数据,pydicom处理tag并写入新的dcm,成功解决。
  • Pydicom

  • 官网及官方教程:https://pydicom.github.io/pydicom/stable/index.html

  • 利用pydicom读写并修改图像数据

    import pydicom
           
    dataset = pydicom.dcmread('.\001.dcm')                #读取dicom文件
    #val = dataset.data_element('Columns').value          #根据TAG获得其值,可以读写所有tag
    pixeldata = dataset.pixel_array                       #获得图像数据的矩阵形式,只读
    databyte = dataset.PixelData                          #获得图像的byte数据,可直接读写
    
    datanew = pixeldata[0:400, 0:400]                     #截取原图像的一部分
    dataset.Rows, dataset.Columns = datanew.shape         #图像矩阵大小的另一种快速读写方法
    
    newArray = np.ones([400, 400])+254                    #新建一个对应大小的图像数据矩阵
    
    data16 = np.int16(newArray)                           #必须转为int16
    
    #dataset.pixel_array.data = data16                    #第一种修改图像数据的方法,直接修改像素值
    
    dataset.PixelData = data16.tobytes()                  #第二种修改图像数据的方法,修改byte值,建议用这种方式
    
    dataset.save_as(r'.\002.dcm')                         #保存为新dcm文件
    

如果想把一个dcm的图像数据复制到另一个dcm中,需要考虑和pixeldata读写相关的一些tag,除了rows,columns,还有斜率/截距,高低位等,要提前修改。

  • SimpleITK
  • 官网及官方教程:https://simpleitk.readthedocs.io/en/master/index.html
    SimpleITK是python对C++ITK的简化,可以看成是opencv的医学图像版本。
  • 利用Simple ITK读写dcm数据
import SimpleITK as sitk

image = sitk.ReadImage('.\001.dcm')                                 #读取dicom文件
image_array = sitk.GetArrayFromImage(image)
np_array = np.int16(image_array)
image_array = np.squeeze(np_array)                                  #获得图像数据

im = sitk.GetImageFromArray(image_array)                            #用来读写Tag,相当于开始以imagearray构建一个新dcm

reader = sitk.ImageFileReader()
reader.SetFileName('.\002.dcm')
reader.LoadPrivateTagsOn()
reader.ReadImageInformation()                                       #获得Tag信息

ImageType = reader.GetMetaData('0008|0008')                         #读取对应的Tag,0002开头的不能读写
im.EraseMetaData('0008|0008')                                       #删除Tag,更改的话可以不写
im.SetMetaData('0008|0008', ImageType)                              #更改新dcm的Tag值

SOPClassUID = reader.GetMetaData('0008|0016')
im.SetMetaData('0008|0016',SOPClassUID)

SOPInstanceUID = reader.GetMetaData('0008|0018')
im.SetMetaData('0008|0018', SOPInstanceUID)

SeriesInstanceUID = reader.GetMetaData('0020|000e')                 #这个Tag改不了,保存时貌似会随机赋值
im.SetMetaData('0020|000e', SeriesInstanceUID)

sitk.WriteImage(im, '.\003.dcm')                                    #保存为新dcm,不过不能组成序列
  • 利用pydicom+Simple ITK读写有压缩分段的dcm
 dcm = pydicom.dcmread('.\001.dcm')                                  #选择一个普通的非压缩dcm文件作为转换模板
 
 image = sitk.ReadImage('.\002.dcm')                  
 image_array = sitk.GetArrayFromImage(image)
 np_array = np.int16(image_array)
 image_array = np.squeeze(np_array)                                  #读取有压缩分段的dcm图像数据
 
 dataset = pydicom.dcmread('.\002.dcm')                              #用来修改Tag,图像读写相关的tag都要改
 dcm.data_element('PixelSpacing').value = dataset.data_element('PixelSpacing').value
 dcm.data_element('RescaleIntercept').value = dataset.data_element('RescaleIntercept').value
 dcm.data_element('RescaleSlope').value = dataset.data_element('RescaleSlope').value

 dcm.PixelData = image_array.tobytes()
 dcm.save_as('.\002.dcm')                                            #保存文件

你可能感兴趣的:(DICOM处理,Python)