python 用SimpleITK+pydicom 将4dnii图像转为单张dicom,并重新添加图像头信息

最近在处理一套心脏数据,需要将4dnii图像转换成单张的dicom图像进行试验,看了很多博客,发现SimpleITK是一个处理医学图像的很好用的包,里面支持很多医学图像的读取以及处理,以及对图像头信息的查看及修改。

首先,可以用sitk.ReadImage读取4dnii图像,如下:

itk_img = sitk.ReadImage('E:/cardic_data/training/patient009/patient009_4d.nii.gz')#读取nii图像
img = sitk.GetArrayFromImage(itk_img)#获取图像array
print(img.shape)#查看图像形状
#获取图像头信息
keys = itk_img.GetMetaDataKeys()
print(keys)
for key in keys:
    print (key,':', itk_img.GetMetaData(key)

读取nii图像ndarray后,就可以numpy及切片将图像保存为单张dicom了:

simpleitk读取图像是按照(t,slice,height,width)读取的 我们可以用numpy转换成想要的形状,便于切片:

img = sitk.GetArrayFromImage(itk_img)
print(img.shape)
img =np.transpose(img,(1,0,2,3))
print(img.shape)
结果:
(35, 10, 256, 208)
(10, 35, 256, 208)
切片并保存:
import pydicom
import numpy as np
import SimpleITK as sitk
import nibabel as nib
import os
import pydicom
itk_img = sitk.ReadImage('E:/cardic_data/training/patient009/patient009_4d.nii.gz')
itk_img = sitk.ReadImage('E:/DICOM_data_cardic/patient001_4d_0_1.dcm')
img = sitk.GetArrayFromImage(itk_img)
print(img.shape)
img =np.transpose(img,(1,0,2,3))
print(img.shape)
keys = itk_img.GetMetaDataKeys()
#pixel = itk_img.GetMetaData('pixdim[1]')
#print('pixel:',pixel)
for key in keys:
    print (key,':', itk_img.GetMetaData(key))
print("img shape:",img.shape)

for i in range(img.shape[0]):
    for j in range(img.shape[1]):
       out = sitk.GetImageFromArray(img[i,j,:,:].astype('int16'))#这里需要把切边图像保存为‘int16’,不然保存会出错
       sitk.WriteImage(out, 'E:/DICOM_data_cardic/patient009/patient009_4d_{}_{}.dcm'.format(i,j))

img[i,j,:,:].astype('int16'),这里保存为'int16'主要是因为读取nii图像array是默认的是float32,然后在保存时有些数据会保存不了,出现以下错误:

Traceback (most recent call last):
  File "E:/pycharm/ss1/Nii2Dicom.py", line 42, in
    sitk.WriteImage(out, 'E:/DICOM_data_cardic/patient009/patient009_4d_{}_{}.dcm'.format(i,j))
  File "D:\Anaconda\envs\tensorflow\lib\site-packages\SimpleITK\SimpleITK.py", line 8207, in WriteImage
    return _SimpleITK.WriteImage(*args)
RuntimeError: Exception thrown in SimpleITK WriteImage: D:\a\1\sitk-build\ITK\Modules\IO\GDCM\src\itkGDCMImageIO.cxx:1058:
itk::ERROR: GDCMImageIO(000001BED1A840C0): A Floating point buffer was passed but the stored pixel type was not specified.This is currently not supported
 

对于修改header信息,主要是使用SimpleITK 在修改Series Instance UID 时使用了pydicom,主要是我用SimpleITK修改时保存后不是我修改的值,修改不了,后面发现可以用pydicom修改代码如下:

import pydicom
import numpy as np
import SimpleITK as sitk
import nibabel as nib
import pydicom
itk_img = sitk.ReadImage('E:/cardic_data/training/patient009/patient009_4d.nii.gz')
img = sitk.GetArrayFromImage(itk_img)#这里主要是为了读取nii原图像array然后索引单张dicom,对每张图像添加header信息
pixel = itk_img.GetMetaData('pixdim[1]')
print(pixel)
img =np.transpose(img,(1,0,2,3))
print(img.shape)
#base_path = 'E:/DICOM_data_cardic/patient001'
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        itk_img_1 = sitk.ReadImage('E:/DICOM_data_cardic/patient009/patient009_4d_{}_{}.dcm'.format(i,j))
        itk_img_1.SetMetaData('0020|1041', '{}'.format(float(i)))#0020,1041 添加 Slice Location: 信息
        #itk_img_1.EraseMetaData('0020|000e')#0020,000E 修改 Series Instance UID: 001这里修改不了,后面用pydicom实现
        itk_img_1.SetMetaData('0028|0030',pixel)#0028,0030 修改 Pixel Spacing: 1.5625信息
        m = 30*(j+1)
        itk_img_1.SetMetaData('0018|1060', str(m))#0018,1060 修改 Trigger Time: 30
        #out = sitk.Cast(itk_img_1, sitk.sitkFloat32)
        out = sitk.WriteImage(itk_img_1, 'E:/DICOM_data_cardic1/patient009/patient009_4d_{}_{}.dcm'.format(i,j))
        ds=pydicom.read_file('E:/DICOM_data_cardic1/patient009/patient009_4d_{}_{}.dcm'.format(i,j))
        ds.SeriesInstanceUID = '9'#修改Series Instance UID
        ds.save_as('E:/DICOM_data_cardic2/patient009/patient009_4d_{}_{}.dcm'.format(i,j))

 

这里推荐一个SimpleITK的API document:

https://itk.org/SimpleITKDoxygen/html/namespaceitk_1_1simple.html

很有用!!!

以上就是全过程!

你可能感兴趣的:(医学图像处理,python,医学图像处理nii,dicom,python,SimpleITK,pydicom,4dnii,to,DICOM)