pydicom+gdcm+dicom文件格式详解
PyDicom
DICOM
医学影像
医学影像(Medical Imaging),是指利用某种介质(例如X射线、电磁、超声波等等)与人体相互作用,从而以影像方
式将人体内部组织器官的结构和密度表现出来,然后提供给医生进行判断并对人体健康状况得出结论的一门科学。
医学仪器
医学影像仪器主要包含:
1, X光影像仪器
2, CT(Computerized Tomography Computed Tomography)
3, 超声(分B超、彩色多普勒超声、心脏彩超、三维彩超)
4, 核磁共振成像(MRI)
DICOM简介
DICOM(医学数字成像和通讯),英文全称Digital Imaging and Communications in Medicine,是ACR(美国放射协会
和NAMA(美国国家电子制造商协会)联合开发医学数字成像和通讯的一个通用标准。随着X线断层造影技术和其他数字诊断模式的产生,
以及计算机的使用在临床应用中的增长,为实现在不同制造商生产的设备之间传输图像和联合信息的标准方法—DICOM标准,在1985年
应运而生并不断的改版升级,现在主要是3.0版本。对于医学专业的同学如要了解更多的相关背景知识,可以参考Dicom
官方文档。DICOM顾名思义,关键点在于D-igital I-maging和C-ommunications,
标准主要由三个部分组成:
- a file format for images and reports
- a set of defined services
- a network protocol
DICOM文件格式详解
Dicom全称是医学数字图像与通讯,文件后缀通常为*.dcm,DICOM文件是标记的图像文件,包含图像和有关图像的数据集合,其能够在两
个以DICOM格式接收患者数据和图像的实体之间进行交流。通俗的理解就是:患者的医学图像以DICOM文件格式进行存储,其中包含了图像 信息以及患者的PHI(protected health
information,即姓名、性别、年龄等),以及产生图像的设备的相关信息。
文件解析:整体结构先是128字节所谓的导言部分,然后是dataElement依次排列的方式 就是一个dataElement接一个dataElement的 方式排到文件结尾,其存储的信息为二进制格式。
DICOM文件头包含了标识数据集合的相关信息,每个DICOM文件都必须包含文件头,主要信息:
- 文件导言: 由128个字节组成,描述文件的相关导言信息。
- DICOM前缀: 由4个字节组成,用于判断其字符串值是否为"DICOM"从而判断是否为DICOM文件,可以理解为一个标志信息。
- 文件元信息元素
DICOM数据集是DICOM文件的主要组成部分,其由DICOM数据元素按照指定的顺序排列。数据元素最基本的数据单元是数据元, 按照TAG从小到大顺序排列,即一个数据元表示一个TAG。数据元主要由4个部分组成:
- TAG号: 由4个字节组成,包括2字节的组号和2字节的元素号(例如:0010 0040
表示患者性别,其中的组号:0002描述设备通讯信息、0008描述特征参数、0010描述患者信息、0028描述图像信息参数)。我们后期所需要的DICOM文件相关数据时,就是根据TAG来获取。 - 值表示(VR,value representation) 由两个字节的字符组成,存储描述该项数据元信息的数据类型,包含例如:LO(Long String,长字符串)、IS(Interger
String,整型字符串),DA(data,日期)等等共27种数据类型。 - 值长度(value length 存储描述该项信息的数据长度
- 值域(value) 存储描述该项信息的数据值
标记tag(2字节UInt16分组号和2字节UInt16元素号)
tag是4个字节表示的 前两字节是组号后两字节是元素号 比如0008(组号) 0018(元素号)。
我们获取dicom里面的数据,就是根据tag,来知道这个dataElement里面是否是我们需要的数据,然后读取该dataElement里面的数据。
tag的dataElement结构,分为下面三种:
- 显示VR:VR为OB OW OF UT SQ UN的元素结构
组号 | 元素号 | VR | 预留 | 值长度 | 数据元素值 |
---|---|---|---|---|---|
2 | 2 | 2 | 2(0x00,0x00) | 4 | 由数据长度决定 |
组号和元素号组成tag,上面的数组表示给类型占有的字节长度
- 显示VR:VR为普通类型时元素结构(少了预留那一行)
组号 | 元素号 | VR | 值长度 | 数据元素值 |
---|---|---|---|---|
2 | 2 | 2 | 4 | 由数据长度决定 |
- 隐式VR时元素结构(也就是dataElement中没有VR这个值)
组号 | 元素号 | 值长度 | 数据元素值 |
---|---|---|---|
2 | 2 | 4 | 由数据长度决定 |
所有dataElement从前到后按tag又可简单分段
文件元dataElement | 不受传输语法影响 总是以显示VR方式表示 因为它里面就定义了传输语法 |
---|---|
普通dataElement | 受传输语法影响 显示VR表示方式还是隐式VR表示方式 |
像素数据dataElement | 最重要也是最大的一个数据项 其实存储的就是图像数据 |
dicom文件的图像分为压缩过的和没压缩的。
下面罗列出该tag的VF值,并介绍他表示的意义
未压缩:
无损压缩:
有损压缩:
其中数据元信息可以根据信息的不同,分为4类:
Patient Study Series Image
可以理解为一个患者(patient)可以做多次检查(study),一次检查包含多个检查部位(series),而每个检查部位都有一张或多张相应的影像图像(image)。常见的TAG如下:
-
Patient Tag
-
Study Tag
-
Series Tag
-
Image Tag
pydicom
说明
- Pydicom是一个用于处理DICOM格式文件的Python包,可以处理包括如医学图像(CT等)、报告等。
- Pydicom支持DICOM格式的读取:可以将dicom文件读入python结构,同时支持修改后的数据集可以
再次写入DICOM格式文件。但需要注意,它不是被设计为查看图像,主要是用来操作DICOM文件的各种数据元素。
安装
- 支持PIP和Conda安装
# conda
conda install pydicom --channel conda-forge
# pip
pip install pydicom
文件的读取以及数据元的获取
import pydicom
info = {}
# 读取dicom文件
dcm = pydicom.read_file("test.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)
获取图像Tag中的像素矩阵并保存为JPG图片
import pydicom
import matplotlib.pyplot as plt
import numpy as np
filename = "test.dcm"
jpgname = "test.jpg"
# 读取dicom文件
dcm = pydicom.read_file(filename)
# 获取图像唯一标识符UID
uid = dcm.SOPInstanceUID
# 获取像素矩阵
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)
# 绘制图像并保存
plt.figure(figsize=(12, 12), dpi=250) # 图像大小可以根据文件不同进行设置
plt.imshow(img_arr, cmap=plt.cm.bone)
plt.title(f"UID:{uid}")
plt.savefig(jpgname)
plt.close()
若试图直接用pydicm打开并读取pixel_array,则会报错:
安装gdcm后进行读取:
dicom格式转换从PEG-LS Lossless Image Compression 转为UI: Explicit VR Little Endian
# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: 解压缩
# Author: yunhgu
# Date: 2022/2/16 18:25
# Description: dicom格式转换从PEG-LS Lossless Image Compression 转为UI: Explicit VR Little Endian
# -------------------------------------------------------------------------------
import gdcm
file = r"F:\测试代码\个人学习\Pydicom使用测试\code\data\16365990659181.dcm"
file2 = r"F:\测试代码\个人学习\Pydicom使用测试\code\data\16365990659181.unzip.dcm"
reader = gdcm.ImageReader()
reader.SetFileName(file)
if not reader.Read():
print("error")
change = gdcm.ImageChangeTransferSyntax()
change.SetInput(reader.GetImage())
change.SetTransferSyntax(gdcm.TransferSyntax(gdcm.TransferSyntax.ImplicitVRLittleEndian))
if not change.Change():
print("error2")
writer = gdcm.ImageWriter()
writer.SetFileName(file2)
writer.SetFile(reader.GetFile())
writer.SetImage(change.GetOutput())
if not writer.Write():
print("write")