Dicom文件的详细解析
使用深度学习进行医疗影像分析:文件格式篇
DICOM文件格式剖析(初识)
一、DICOM格式图像
1、DICOM图像显示以及DICOM图像信息显示
我们有一堆DICOM文件
使用软件RadiAnt(RadiAnt DICOM Viewer | ZH (radiantviewer.com))读取DICOM文件信息。
点击 “A”标志的下拉按钮,点击“ show DICOM tag”
下一部分再来学习DICOM tag。
2、DICOM文件理解
DICOM文件包含一个头文件和一个数据集:
(1)文件头
128个字节的文件导言:用于应用简介和固定长度数据的详细说明。
4个字节的DICOM前缀:“DICM”,用于标识本文件是否是DICOM文件。
不定字节长度的文件元信息:包含文件元信息版本、媒体存储SOP类、传输语法、实现设备等。
(2)数据集
数据集是由若干个数据元组成,存储了病人和图像的相关信息。
数据元
一个数据元主要由标签(Tag),值类型(VR,Value Representation),数据值长度(Length),值域(VF,Value Field)几部分组成。
①标签Tag:4字节无符号整型,由组号和元素号组成,是数据元的唯一标识码,文件中Tag标签有大约2000个,我们只需要了解常用的Tag即可。
0002组描述设备通讯
0008组描述特征参数
0010组描述患者信息
0028组描述图像信息参数,上图的表格就是Tag组号0028的数据元信息。
Tag号:0002,0010,决定数据元素的传输方式,VR是显式还是隐式。
Tag号:7fe0,0010对应像素数据开始的地方。
②值类型VR:2字节字符串,是数据元素的数据类型。VR有27种
等等
③数据值长度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)还有下图
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保存成灰度图像
鉴别:
#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()
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()
(3)批量DICOM转批量nii
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文件。