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

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

1.插值裁剪后的影像數(shù)據(jù)

image.png

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

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

image.png

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

導入需要的包

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

定義翻轉函數(shù)實現(xiàn)圖像的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賦值的函數(shù)

def modify_dicom(ds,dcm):#把原始dicom的元數(shù)據(jù)寫進新的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的核心函數(shù)

def nii2dicom(nii_img,save_dir,DCE_MR):
    
    """[將重采樣后的nii圖片轉dicom保存]
    Args:
        nii_img ([]): 一個3維nii類型嫡秕,shape=(W,H,切片數(shù))
        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度,也要變?yōu)閕nt16才行 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數(shù)量大于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  位數(shù)
        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 ###必須加驾凶,形成連續(xù)變化的序列牙甫,不然,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)

定義路徑,調用函數(shù)執(zhí)行

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)

代碼執(zhí)行過程:


image.png
特別說明:本文為原創(chuàng)文章,參考或轉發(fā)本文需注明本文鏈接调违,有問題請聯(lián)系:nick.yu.jd@qq.com
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末窟哺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子技肩,更是在濱河造成了極大的恐慌且轨,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虚婿,死亡現(xiàn)場離奇詭異旋奢,居然都是意外死亡,警方通過查閱死者的電腦和手機雳锋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門黄绩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玷过,你說我怎么就攤上這事爽丹。” “怎么了辛蚊?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵粤蝎,是天一觀的道長。 經(jīng)常有香客問我袋马,道長初澎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任虑凛,我火速辦了婚禮碑宴,結果婚禮上,老公的妹妹穿的比我還像新娘桑谍。我一直安慰自己延柠,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布锣披。 她就那樣靜靜地躺著贞间,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雹仿。 梳的紋絲不亂的頭發(fā)上增热,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音胧辽,去河邊找鬼峻仇。 笑死,一個胖子當著我的面吹牛邑商,可吹牛的內容都是我干的础浮。 我是一名探鬼主播帆调,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼豆同!你這毒婦竟也來了番刊?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤影锈,失蹤者是張志新(化名)和其女友劉穎芹务,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸭廷,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡枣抱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了辆床。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佳晶。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讼载,靈堂內的尸體忽然破棺而出轿秧,到底是詐尸還是另有隱情,我是刑警寧澤咨堤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布菇篡,位于F島的核電站,受9級特大地震影響一喘,放射性物質發(fā)生泄漏驱还。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一凸克、第九天 我趴在偏房一處隱蔽的房頂上張望议蟆。 院中可真熱鬧,春花似錦萎战、人聲如沸咐容。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颖侄,卻和暖如春鸟雏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背览祖。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工孝鹊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人展蒂。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓又活,卻偏偏與公主長得像苔咪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子柳骄,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容