Dicom文件的详细解析

使用深度学习进行医疗影像分析:文件格式篇

DICOM文件格式剖析(初识)

一、DICOM格式图像

1、DICOM图像显示以及DICOM图像信息显示

dicom java医学影像_dicom java医学影像

 我们有一堆DICOM文件

使用软件RadiAnt(RadiAnt DICOM Viewer | ZH (radiantviewer.com))读取DICOM文件信息。

dicom java医学影像_人工智能_02

 点击 “A”标志的下拉按钮,点击“ show DICOM tag”

dicom java医学影像_python_03

 下一部分再来学习DICOM tag。

2、DICOM文件理解

DICOM文件包含一个头文件和一个数据集:

dicom java医学影像_深度学习_04

 (1)文件头

128个字节的文件导言:用于应用简介和固定长度数据的详细说明。

4个字节的DICOM前缀:“DICM”,用于标识本文件是否是DICOM文件。

不定字节长度的文件元信息:包含文件元信息版本、媒体存储SOP类、传输语法、实现设备等。

 (2)数据集

数据集是由若干个数据元组成,存储了病人和图像的相关信息。

 数据元

 一个数据元主要由标签(Tag),值类型(VR,Value Representation),数据值长度(Length),值域(VF,Value Field)几部分组成。

dicom java医学影像_dicom java医学影像_05

 

①标签Tag:4字节无符号整型,由组号和元素号组成,是数据元的唯一标识码,文件中Tag标签有大约2000个,我们只需要了解常用的Tag即可。

0002组描述设备通讯

0008组描述特征参数

0010组描述患者信息

0028组描述图像信息参数,上图的表格就是Tag组号0028的数据元信息。

Tag号:0002,0010,决定数据元素的传输方式,VR是显式还是隐式。

Tag号:7fe0,0010对应像素数据开始的地方。

②值类型VR:2字节字符串,是数据元素的数据类型。VR有27种

dicom java医学影像_python_06

 等等

③数据值长度L:2字节或4字节无符号整数,具体长度取决于传输语法,表示数值的长度。

④值域VF:表明数据元素的值。

二、DICOM读取与格式转换

DICOM可以使用第一部分的软件读取方式来读取图像,也可以使用Python库PyDicom来读取。

1、Python读取DICOM文件

import matplotlib.pyplot as plt
import pydicom

dcm = pydicom.read_file("118PCT_01.dcm")   #118PCT_01.dcm是DICOM文件名
img_arr = dcm.pixel_array
print(img_arr.shape)

plt.imshow(img_arr, cmap='gray')
plt.show()

#运行结果:(512,512)还有下图

dicom java医学影像_ico_07

2、DICOM格式文件转JPG格式文件

import cv2
import matplotlib.pyplot as plt
import numpy as np
import pydicom
import imageio

info = {}
# 读取dicom文件
dcm = pydicom.read_file("118CBCT_01.dcm")

# 通过字典关键字来获取图像的数据元信息(当然也可以根据TAG号)
# 这里获取几种常用信息
info["PatientID"] = dcm.PatientID               # 患者ID
info["PatientName"] = dcm.PatientName           # 患者姓名
info["PatientBirthData"] = dcm.PatientBirthData # 患者出生日期
info["PatientAge"] = dcm.PatientAge             # 患者年龄
info['PatientSex'] = dcm.PatientSex             # 患者性别
info['StudyID'] = dcm.StudyID                   # 检查ID
info['StudyDate'] = dcm.StudyDate               # 检查日期
info['StudyTime'] = dcm.StudyTime               # 检查时间
info['InstitutionName'] = dcm.InstitutionName   # 机构名称
info['Manufacturer'] = dcm.Manufacturer         # 设备制造商
info['StudyDescription']=dcm.StudyDescription   # 检查项目描述
print(info)
           
uid = dcm.SOPInstanceUID                       # 获取图像唯一标识符UID
img_arr = dcm.pixel_array                      # 获取像素矩阵
print(img_arr.shape)                           # 打印矩阵大小
lens = img_arr.shape[0]*img_arr.shape[1]       # 获取像素点个数
arr_temp = np.reshape(img_arr,(lens,))         # 获取像素点的最大值和最小值
max_val = max(arr_temp)
min_val = min(arr_temp)

img_arr = (img_arr-min_val)/(max_val-min_val)  # 图像归一化


# 绘制图像并保存
imageio.imsave("118PCT_01.JPG", img_arr)

将DICOM格式图像转换为JPG格式的思路就是:

①从DICOM文件中读出图像数据矩阵ima_arr(512*512,256*256)

②imageio.imsave("118PCT_01.JPG", img_arr)将矩阵img_arr保存成灰度图像

dicom java医学影像_深度学习_08

 鉴别:

#imageio.imsave()函数将从DICOM文件中读取到的512*512的矩阵转换成--->单通道的灰度图像(512,512)
import imageio

dcm = pydicom.read_file("118PCT_01.dcm")
img_arr = dcm.pixel_array
imageio.imsave("118PCT_01.JPG", img_arr)

#512*512矩阵--->三通道图像(512,512,3)
import matplotlib.pyplot as plt

dcm = pydicom.read_file("118PCT_01.dcm")
img_arr = dcm.pixel_array
jpgname = "118PCT_01.jpg"
plt.figure(figsize=(8,8),dpi=64)   # 设置图像分辨率位512*512
plt.imshow(img_arr,'Greys_r')
plt.title("UID:{}".format(uid))
plt.savefig(jpgname)
plt.close()

dicom java医学影像_python_09

    

dicom java医学影像_python_10

3、DICOM格式文件转nii格式文件

(1)批量DICOM转nii

import dicom2nifti

#DICOM文件存放位置
original_dicom_directory = 'E:\\PostGraduate\\Github\\DicomImagePreprocessing\\PinLiangDICOM\\Lung\\118PCT'
#要生成的nii文件名
output_file = '118PCTnii'
dicom2nifti.dicom_series_to_nifti(original_dicom_directory, output_file, reorient_nifti=True)

(2)查看nii文件

import matplotlib
matplotlib.use('TkAgg')
from matplotlib import pylab as plt
import nibabel as nib
from nibabel import nifti1
from nibabel.viewers import OrthoSlicer3D

example_filename = './118PCTnii.nii'

img = nib.load(example_filename)
print(img)
print(img.header['db_name'])  # 输出头信息

width, height, queue = img.dataobj.shape

OrthoSlicer3D(img.dataobj).show()

num = 1
for i in range(0, queue, 10):
    img_arr = img.dataobj[:, :, i]
    plt.subplot(5, 4, num)
    plt.imshow(img_arr, cmap='gray')
    num += 1

plt.show()

dicom java医学影像_python_11

 

(3)批量DICOM转批量nii

dicom java医学影像_深度学习_12

 DICOM2nii.py文件存放在118_HM10395文件夹下

#DICOM2nii.py
import dicom2nifti
import os

pathRoot = 'E:\\PostGraduate\\NBIA\\CBCT_Lung\\118\\manifest-1632732569283\\4D-Lung'     #当前程序所在文件夹
pathNow = 'E:\\PostGraduate\\NBIA\\CBCT_Lung\\118\\manifest-1632732569283\\4D-Lung\\118_HM10395'

#将filename.txt文件中的文本都赋给列表filenames[]
os.chdir(pathRoot)                       #进入filename.txt的所在目录4D-Lung
filenames = []
for line in open("filenames.txt"):       #从filenames.txt文件中读取行信息
    filenames.append(line.rstrip())      #.rstrip去除掉文本文件中的换行符

for i in range(len(filenames)):
    os.chdir(pathNow)    
    Daughternames = []
    Renames = []
    txt_name = filenames[i] + '.txt'
    #print(txt_name)
    for line in open(txt_name):          # 从Daughtername.txt文件中读取行信息
        Daughternames.append(line.rstrip())
        Renames.append(line.rstrip()[-5:-1])

    for j in range(len(Daughternames)):
        os.chdir(pathNow + '\\' + 'nii_' + filenames[i])
        Dicom_ID = pathNow + '\\' + filenames[i] + '\\' + Daughternames[j]
        Nii_ID = Renames[j]

        dicom2nifti.dicom_series_to_nifti(Dicom_ID, Nii_ID, reorient_nifti=True)

最后深度学习网络使用的数据集,有JPG格式的也有nii格式的,但可能nii格式可能会比较方便处理一些,因为一个nii格式数据包含了一个病人一次检查的所有切片图像,而同一个病人的JPG图片可能就需要80多甚至更多的JPG文件。