dcm转nii,把501序列和201序列dcm提取出的数值相减,期间需要将个别文件的HU值(-1024~3071)转为GRAY(0-4096),格式为uint16,保存为nii时用到了501序列和201序列的CT的,origin、spacing、direction信息,501是打了造影剂的CTA序列,201是没打造影的CT序列。
#coding=utf-8
import SimpleITK as sitk
import numpy as np
import scipy.misc
from scipy import misc
from PIL import Image
import cv2
import os
import matplotlib.pyplot as pyplot
import pydicom
def dcm2nii(dcms_path, nii_path):
#获取501序列和201序列像素信息,
# 1.构建dicom序列文件阅读器,并执行(即将dicom序列文件“打包整合”)
reader_501 = sitk.ImageSeriesReader()
dicom_names_501 = reader_501.GetGDCMSeriesFileNames(dcms_path)
reader_501.SetFileNames(dicom_names_501)
image_501 = reader_501.Execute()
# 2.将整合后的数据转为array,并获取dicom文件基本信息
image_array_501 = sitk.GetArrayFromImage(image_501) # z, y, x 注意这里得到的三维数组好像是倒序的,第一个文件的信息在image_array_501[353]
reader_201 = sitk.ImageSeriesReader()
dicom_names_201 = reader_201.GetGDCMSeriesFileNames(dcms_path.split('/50')[0] + '/201')
reader_201.SetFileNames(dicom_names_201)
image_201 = reader_201.Execute()
image_array_201 = sitk.GetArrayFromImage(image_201) # z, y, x
#获取origin、spacing、direction信息,两个序列应该都一样
origin = image_201.GetOrigin() # x, y, z origin原始图像中心点在相机坐标系的位置
spacing = image_201.GetSpacing() # x, y, z spacing是两个像素之间的间隔
direction = image_201.GetDirection() # x, y, z direction是方向
reader_201 = sitk.ImageSeriesReader()
image_array = np.ones(image_array_501.shape)
image_array = image_array_501 - image_array_201
# 先统一好两个dcm序列图片的名字方便检索,复制dcm文件改名并重新另保存
# for img_name in os.listdir(dcms_path):
# image1 = pydicom.dcmread(dcms_path + img_name)
# new_1 = img_name.split('_')[0]
# new_2 = img_name.split('_')[1]
# new_3 = img_name.split('_')[2]
# new_name1 = new_1 + '_' + new_2 + '_' + new_3
# # print('new_name1:',new_name1)
# image1.save_as(dcms_path.split('501')[0] + 'rename501/' + new_name1 + '.dcm', image1)
# for img_name in os.listdir(dcms_path.split('501')[0] + '201/'):
# image2 = pydicom.dcmread(dcms_path.split('501')[0] + '201/' + img_name)
# new_1 = img_name.split('_')[0]
# new_2 = img_name.split('_')[1]
# new_3 = img_name.split('_')[2]
# new_name2 = new_1 + '_' + new_2 + '_' + new_3
# print('new_name2:',new_name2)
# image2.save_as(dcms_path.split('501')[0] + 'rename201/' + new_name2 + '.dcm', image2)
#读取rename中的dcm文件
filename_dcm501 = dcms_path.split('501')[0] + 'rename501/name_501_0001.dcm'
filename_dcm201 = dcms_path.split('501')[0] + 'rename201/name_201_0001.dcm'
#得到501和201的Rescale intercept (0028|1052) 和Rescale slope (0028|1053)
dicom_501 = sitk.ReadImage(filename_dcm501)
dicom_201 = sitk.ReadImage(filename_dcm201)
intercept_501 = dicom_501.GetMetaData('0028|1052')
slope_501 = dicom_501.GetMetaData('0028|1053')
intercept_201 = dicom_201.GetMetaData('0028|1052')
slope_201 = dicom_201.GetMetaData('0028|1053')
#创建一个和image_array_501一样大小的三维数组以便生成nii
seg_sub_all = np.ones(image_array_501.shape)
i = 0
num = image_array_501.shape[0]#读取病人的dcm文件数
print('病人的dcm文件数num:', num)
for img_name in os.listdir(dcms_path.split('501')[0] + 'rename501/'):
fileName1 = dcms_path.split('501')[0] + 'rename501/' + img_name
fileName2 = dcms_path.split('501')[0] + 'rename201/' + img_name.split('_')[0] + '_201_' + img_name.split('_')[2]
dataset_501 = pydicom.dcmread(fileName1)
dataset_201 = pydicom.dcmread(fileName2)
image_dataset_501 = dataset_501.pixel_array
image_dataset_201 = dataset_201.pixel_array
#有个别dcm的pixel_array居然是HU值,dtype是int16,与uint16不一致导致cv2.subtract相减出错,用hu2gray转过来
min_501 = np.min(image_dataset_501)# 找到最小的
if(min_501 < 0):
image_dataset_501 = hu2gray(image_dataset_501, int(slope_501), int(intercept_501))
min_201 = np.min(image_dataset_501)# 找到最小的
if(min_201 < 0):
image_dataset_201 = hu2gray(image_dataset_201, int(slope_201), int(intercept_201))
image_dataset_501[image_dataset_501 > 1150] = 2183#将钙质和被造影拉高亮度的血管值赋高值,也可以直接赋4096
image_dataset_201[image_dataset_201 > 1150] = 2183
dataset_sub = cv2.subtract(image_dataset_501, image_dataset_201) #注意此处用0-4096,不是用CT HU值
#将其它gray值置为0
image_dataset_501[image_dataset_501 <= 1150] = 0
image_dataset_201[image_dataset_201 <= 1150] = 0
sub_erzhi = cv2.subtract(image_dataset_501, image_dataset_201)#将图像binary1与binary2相减,理论上得到只剩血管的图,但依然有骨杂质,这是因为造影剂会同时把骨头和组织里的细微血管也充满,此时sub_erzhi剩0 255 ,uint8格式
sub_erzhi[sub_erzhi == 2183] = 1
seg = np.multiply(dataset_sub, sub_erzhi)#根据sub_erzhi掩膜把dataset_sub中的区域截取出来,结果含有很多骨质血管杂质,可以将最后得到的nii文件用3d sclier重建再剪掉杂质,因为用像素做杂质处理怎么弄都会影响血管的形状
seg_sub_all[i,:,:] = seg
print('i:',i)
i = i + 1
# 3.将array转为img,并保存为.nii.gz
image3 = sitk.GetImageFromArray(seg_sub_all)
image3.SetSpacing(spacing)
image3.SetDirection(direction)
image3.SetOrigin(origin)
sitk.WriteImage(image3, nii_path)
#Hu转化为gray
def hu2gray(hu, RescaleSlope, RescaleIntercept):
gray = (hu - RescaleIntercept) / RescaleSlope
gray_int = gray.astype(np.uint16)
return gray_int
if __name__ == '__main__':
dcms_path = r'./501/' # dicom序列文件所在路径
nii_path = r'./xx.nii' # 所需.nii.gz文件保存路径
dcm2nii(dcms_path, nii_path)