医学数据处理:mat文件的3D矩阵转dicom文件


前言

因为想把3维矩阵进行3D显示,但原本的数据存储在mat文件里,3D显示需要dicom形式的,所以需要对数据进行处理。具体内容还是参考了一些文章,比如dicom形式的文章,mat的3D矩阵转dicom的文章。


一、dicom

具体格式可以参考其他文章,我在转换时遇到了一些问题,比如modality这个tag,因为我需要得到CT图像并在小赛看看里观察,所以这个tag需要设置为‘CT’。和CT图像相关的还有一些tag,不过我用sitk.writeimage写入后没有问题就没关注。

参考:https://blog.csdn.net/sinolover/article/details/114311823?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-114311823-blog-101880158.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.1&utm_relevant_index=3

二、具体代码

代码如下:

import numpy as np
import SimpleITK as sitk
import pydicom 
from scipy.io import loadmat
import os

def mat2dicom(folderPath):
    count_study = 0
    folderPath_new = folderPath + '/3D'#这个是我的路径相关的处理
    all_study = os.listdir(folderPath_new)
    for every_study_idx in range(len(all_study)):#读取每个增强序列对应的mat文件(3维矩阵)
        count_study +=1
        tmp_MAT_path = os.path.join(folderPath_new,all_study[every_study_idx])
        source_MAT_path = folderPath
        final_mat_path = tmp_MAT_path
        #读取三维矩阵 mat文件
        mat = loadmat(final_mat_path)#读mat文件,用loadmat来处理了
        # 可以用shape查看维度信息
        mat_t = mat.get('tensor')#tensor是我的数据的key
        # print(type(mat_t),mat_t.shape,mat_t.shape[2]) #可以看看得到数据的shape
        #定义存储dicom的路径
        every_DCM_path = source_MAT_path + '/DCM' + str(every_study_idx)
        print(every_DCM_path)#打印路径
        begin = 0#表示起始位置的参数
        flag = np.zeros((88,120))#画图需要有信息的数据,用这个全0矩阵来去掉没信息的dcm
        if not os.path.exists(every_DCM_path):
            os.makedirs(every_DCM_path)
        for i in range(mat_t.shape[0]):#一个mat中的三维矩阵有k维,这个循环就对k维循环输出每一层的dcm
            out = mat_t[i, :, :].astype('int16')#这个int16是必须要增加的,不能直接使用float,在实验的时候一改就报错,且int和int16不同
            if((out == flag).all()):#保留有信息的dcm
                continue
            InstanceNumber = begin + i
            if InstanceNumber <10:
                InstanceNumber = '0000'+str(InstanceNumber)
            elif InstanceNumber <100:
                InstanceNumber = '000'+str(InstanceNumber)
            elif InstanceNumber <200:
                InstanceNumber = '00'+str(InstanceNumber)
            else:
                print('Warning!!',InstanceNumber,"dicom数量大于200")
            
            dicom_save_file_path = every_DCM_path + '/'+InstanceNumber +'.dcm'
            if os.path.exists(dicom_save_file_path):
                continue
            sitk.WriteImage(sitk.GetImageFromArray(out),dicom_save_file_path)
            
            ######再读文件,修改dicom的tag信息使这些图片成为一个序列
            read_dicom_path = every_DCM_path+'/'+InstanceNumber+'.dcm'  #每个dcm文件的具体路径

            dcm = pydicom.read_file(read_dicom_path)
            ds = pydicom.read_file(dicom_save_file_path)
            #print(dcm)
            print(dicom_save_file_path)
            ds = modify_dicom(ds,dcm)
            #保存
            ds.save_as(dicom_save_file_path)


def modify_dicom(ds,dcm):#这个函数里注释掉比较多的内容,是因为在实验中报错的地方全注释了,应该是我的数据没有这些
     #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
        #ds.InstitutionName = dcm.InstitutionName
    #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 #修改Series Instance UID
    #ds.SeriesDescription = dcm.SeriesDescription
    ds.Modality = 'CT'#这个是为了适应需要获得CT图像而定义的
    ds.SeriesNumber = dcm.SeriesNumber
    ds.InstanceNumber  = dcm.InstanceNumber
    #ds.SeriesDate = dcm.SeriesDate
    #ds.SeriesTime = dcm.SeriesTime
    #ds.SliceThickness = dcm.SliceThickness
    #ds.SliceLocation = dcm.SliceLocation
    ds.FrameOfReferenceUID = dcm.FrameOfReferenceUID
    ds[0X0020, 0X0052].value = dcm[0X0020, 0X0052].value 
    #ImageInfo
    ds.SOPClassUID  = dcm.SOPClassUID
    ds.SOPInstanceUID = dcm.SOPInstanceUID
    ds.PixelData = dcm.PixelData
    #ds.ReferencedSOPInstanceUID =dcm.ReferencedSOPInstanceUID
    #ds.ReferencedSOPClassUID =dcm.ReferencedSOPClassUID
    return ds

if __name__=="__main__":
    folderPath ='D:/code final/data/3D'#路径
    mat2dicom(folderPath)

修改代码的时候遇到的问题主要是dicom形式不熟悉、sitk.writeimage写入图像时out必须是int16、modality这个tag改为CT、去除没有信息的dcm。其中int16和modality这两个问题耗费时间比较久,int16也找了网上的其他文章,也有人遇到这种问题,modality这个是因为想在小赛看看里看到具体的CT图像,而不修改为CT在里面看到的都是全黑的。

代码参考:https://www.jianshu.com/p/4afb1cb5b5c6

总结

具体的代码还得参考实验来修改,不过对dicom形式有了一定了解。


后记:
1.发现得到的dicom不是一个序列的,看了一个病例dicom中的tag信息,发现很多UID都是一样,然后实验了一下,自定义了所有UID,结果表明,确实能够产生一个序列的dicom。
2.Frame UID和SOP UID需要不同,否则小赛看看读取的是一个序列,但是radiant读取的不是一个序列。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值