python,CTA血管重建,去除血管钙化部分。dcm转为nii,ITK提取dcm的(ct转)gray像素、GetSpacing、(‘0028|1052‘) intercept slope信息

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)

你可能感兴趣的:(医学知识,python,机器学习)