python醫學影像3Dnii文件轉成2Ddicom文件(保留原始dicom信息)

1.原始的每個DCE序列中有多個dicom文件,經過插值裁剪后轉成以一個3Dmatnii矩陣
2.現在的需求是把處理過的3Dnii矩陣還原成2Ddicom文件,并且保留原始dicom信息.

1.插值裁剪后的影像數據

image.png

每一個.nii.gz文件代表DCE-MRI中的一個序列

2.原始DCE-MRI影像數據中一個序列包含多個dcm文件

image.png

3.Python代碼:把3Dnii文件還原成2Ddicom文件,并且保留原始dicom信息.

導入需要的包

import os
import SimpleITK as sitk
import numpy as np
import pydicom as dicom

定義翻轉函數實現圖像的180°旋轉

def flip180(arr):#圖片反轉180°
    new_arr =arr.copy()
    new_arr = arr.reshape(arr.size)
    new_arr = new_arr[::-1]
    new_arr = new_arr.reshape(arr.shape)
    return new_arr

定義給dicom的tag賦值的函數

def modify_dicom(ds,dcm):#把原始dicom的元數據寫進新的dicom中,否則無法成為一個序列
     #PatientInfo
    ds.PatientID = dcm.PatientID
    ds.PatientName =  dcm.PatientName
    ds.PatientBirthDate = dcm.PatientBirthDate
    ds.PatientSex = dcm.PatientSex
    ds.PatientAge = dcm.PatientAge
    ds.PatientWeight = dcm.PatientWeight
    try:
        ds.MagneticFieldStrength = dcm.MagneticFieldStrength
        ds.Manufacturer = dcm.Manufacturer
    except TypeError:
        print("Error:沒有InstitutionName、Manufacturer、InstitutionName tag")
    #studyInfo
    ds.StudyDate =dcm.StudyDate
    ds.StudyTime = dcm.StudyTime
    ds.StudyDescription = dcm.StudyDescription
    ds.StudyInstanceUID = dcm.StudyInstanceUID
    ds.StudyID = ds.StudyID
    # seriesInfo
    ds.SeriesInstanceUID = dcm.SeriesInstanceUID 
    ds.SeriesDescription = dcm.SeriesDescription
    ds.Modality = dcm.Modality
    ds.SeriesNumber = dcm.SeriesNumber
    #ds.InstanceNumber  = instanceNumber #Instance Number    
    ds.SeriesDate = dcm.SeriesDate
    ds.SeriesTime = dcm.SeriesTime
    ds.SOPClassUID = dcm.SOPClassUID
    return ds

定義給nii轉dicom的核心函數

def nii2dicom(nii_img,save_dir,DCE_MR):
    
    """[將重采樣后的nii圖片轉dicom保存]
    Args:
        nii_img ([]): 一個3維nii類型,shape=(W,H,切片數)
        save_dir ([type]): 轉成dicom序列文件保存路徑
    """
    itk_img = sitk.ReadImage(nii_img)    
    img_3Dndarray = sitk.GetArrayFromImage(itk_img)#得到圖像矩陣
    img_shape = img_3Dndarray.shape
    print(img_shape,img_shape[0])#查看 3D 維度
    img_num = img_3Dndarray.shape[0]
    
    PixelSpacing = itk_img.GetMetaData('pixdim[1]')#pixdim[1] : 0.379464 pixdim[2] : 0.379464 pixel spacing
    SliceThickness =  itk_img.GetMetaData('pixdim[3]')#pixdim[3] : 1.2  層厚
    BitsAllocated =  itk_img.GetMetaData('bitpix')#16
    Columns = itk_img.GetMetaData('dim[1]')#dim[1] : 896
    Rows = itk_img.GetMetaData('dim[2]')
    for i in range(img_num-13):
        #從第13張slice開始,13張之前的均是不完整的切片
        ####.nii切片倒著讀,并旋轉180度,也要變為int16才行 img_num-i-1
        out = flip180(img_3Dndarray[12+i,:,:]).astype('uint16')
        itk_img_1 = sitk.GetImageFromArray(out)
        InstanceNumber = ''
        if (i+1) <10:
            InstanceNumber = '0000'+str(i+1)
        elif (i+1) <100:
            InstanceNumber = '000'+str(i+1)
        elif (i+1) <300:
            InstanceNumber = '00'+str(i+1)
        else:
            print('Warning!!',InstanceNumber,"dicom數量大于300")
        dicom_save_file_path = save_dir+'\\'+InstanceNumber+'.dcm'#to do i range
        itk_img_1.SetMetaData('0028|0030',PixelSpacing)#0028,0030 修改 Pixel Spacing: 1.5625信息
        itk_img_1.SetMetaData('0018|0050',SliceThickness)
        itk_img_1.SetMetaData('0028|0100',str(16))#bitpix : 16  位數
        itk_img_1.SetMetaData('0028|0011',Columns)#Columns
        itk_img_1.SetMetaData('0028|0010',Rows)#Rows
        itk_img_1.SetMetaData('0020|0013',str(i+1))#instanceNumber
        sitk.WriteImage(itk_img_1,dicom_save_file_path)

        ######再讀文件,修改dicom的tag信息使這些圖片成為一個序列
        read_dicom_path = DCE_MR+'\\'+'00010.dcm'  #原始dcm文件的具體路徑
        dcm = dicom.read_file(read_dicom_path)
        ds = dicom.read_file(dicom_save_file_path)
        if i == 0:
            seriesInstanceUID = ds.SeriesInstanceUID
            studyInstanceUID = ds.StudyInstanceUID
            frameUID = ds[0X0020, 0X0052].value 
        else:
            ds.SeriesInstanceUID = seriesInstanceUID #修改Series Instance UID
            ds.StudyInstanceUID = studyInstanceUID
            ds[0X0020, 0X0052].value = frameUID
        ds = modify_dicom(ds,dcm)
        ds.InstanceNumber = i+1 ###必須加,形成連續變化的序列,不然,dicom軟件讀取切片會變亂
        ds.save_as(dicom_save_file_path)

返回具體nii文件的路徑

def get_NII_path(root_path,niidata_path,reliceniidata_path):
    '''
    返回具體nii文件的路徑
    '''
    count_study = 0
    for every_study in os.listdir(niidata_path):#遍歷所有的病歷號
        count_study +=1
        tmp_MR_path = os.path.join(root_path,every_study,'MR')#DWI ,T2等
        _renii_path =os.path.join(reliceniidata_path,every_study)
        if count_study <80:
            continue
        for every_MRI in os.listdir(tmp_MR_path):#每個病歷號下面可能有多次MRI
            tmp_MRI_path = os.path.join(tmp_MR_path,every_MRI)
            tmp_DCEseries = tmp_MRI_path+"\DCE00000"
            DCE_length = len(os.listdir(tmp_DCEseries))
            print(tmp_DCEseries,"-->",DCE_length)
            _rdicom_path = os.path.join(niidata_path,every_study,'ResliceMR',every_MRI)
            for every_nii in os.listdir(_renii_path):
                if DCE_length!=112 and "corDCE0000" in every_nii:
                    str1 = every_nii.replace(".nii.gz","")
                    str2 = str1.replace("cor","")
                    DCE_MR = os.path.join(tmp_MRI_path,str2)
                    every_niidata = os.path.join(_renii_path,every_nii)
                    print(every_niidata)
                    save_rDCE = os.path.join(_rdicom_path,str1)
                    if not os.path.exists(save_rDCE):
                        os.makedirs(save_rDCE)
                        print("create-->"+save_rDCE+"-->successfully!!")
                    else:
                        print(save_rDCE+" have exists!")
                    nii2dicom(every_niidata,save_rDCE,DCE_MR)

定義路徑,調用函數執行

if __name__ =="__main__":
    root_path = r"G:\DCE+T2+ADC"
    niidata_path = r"G:\DCE90_NiiDATA"
    reliceniidata_path =r"G:\DCE_ResliceNiiDATA"
    get_NII_path(root_path,niidata_path,reliceniidata_path)

代碼執行過程:


image.png
特別說明:本文為原創文章,參考或轉發本文需注明本文鏈接,有問題請聯系:nick.yu.jd@qq.com
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容