初识DICOM以及pydicom的基础操作
Author:
Labyrinthine Leo
Init_time:
2020.06.30
Index Words:
DICOM
、
pydicom库
、
dicom文件转jpg图片
1、引言
1.1、背景介绍
由于导师推荐入门的研究项目涉及医疗图像识别,这就离不开DICOM文件的基础知识了,因此在这里同大家分享DICOM学习心得,其中包括使用pydicom库将dicom文件转为jpg图片的操作。
1.2、文章结构
-
引言
1.1 背景介绍
1.2 文章结构 -
医学影像
2.1 医学影像
2.2 医学仪器 -
DICOM
3.1 DICOM简介
3.2 DICOM文件格式详解 -
DICOM文件转为JPG图片
4.1 处理DICOM文件的现成库
4.2 pydicom的使用
2、医学影像
2.1、医学影像
医学影像(Medical Imaging),是指利用某种介质(例如X射线、电磁、超声波等等)与人体相互作用,从而以影像方式将人体内部组织器官的结构和密度表现出来,然后提供给医生进行判断并对人体健康状况得出结论的一门科学。
2.2、医学仪器
医学影像仪器主要包含:
1. X光影像仪器
2. CT(Computerized Tomography Computed Tomography)
3. 超声(分B超、彩色多普勒超声、心脏彩超、三维彩超)
4. 核磁共振成像(MRI)
3、DICOM
3.1、DICOM简介
DICOM
(
医学数字成像和通讯
),英文全称
Digital Imaging and Communications in Medicine
,是
ACR
(
美国放射协会
)和
NAMA
(
美国国家电子制造商协会
)联合开发医学数字成像和通讯的一个通用标准。随着X线断层造影技术和其他数字诊断模式的产生,以及计算机的使用在临床应用中的增长,为实现在不同制造商生产的设备之间传输图像和联合信息的标准方法—DICOM标准,在1985年应运而生并不断的改版升级,现在主要是3.0版本
1
。
对于医学专业的同学如要了解更多的相关背景知识,可以参考
Dicom官方文档
。由于笔者是非医学专业,在此只简述我们所需要的知识。
DICOM
顾名思义,关键点在于
D-igital I-maging
和
C-ommunications
,标准主要由三个部分组成:
1. a file format for images and reports
2. a set of defined services
3. a network protocol
即通过网络协议使用服务进行创建、存储和交换文件的若干标准
2
。
3.2、DICOM文件格式详解
前面已经大概了解了DICOM标准,接下来需要知道DICOM标准的使用,其通常通过DICOM格式文件进行体现。DICOM文件是标记的图像文件,包含图像和有关图像的数据集合,其能够在两个以DICOM格式接收患者数据和图像的实体之间进行交流
3
。
通俗的理解就是:患者的医学图像以DICOM文件格式进行存储,其中包含了图像信息以及患者的
PHI
(protected health information,即姓名、性别、年龄等),以及产生图像的设备的相关信息。如下图所示,以dcm后缀结尾的文件即DICOM文件,其存储的信息为二进制格式。
DICOM文件的内容一般由一个DICOM文件头和一个DICOM数据集组成,结构图如下所示:
1、
DICOM文件头包含了标识数据集合的相关信息,每个DICOM文件都必须包含文件头,主要信息:
-
文件导言
:由128个字节组成,描述文件的相关导言信息。 -
DICOM前缀
:由4个字节组成,用于判断其字符串值是否为”DICOM”从而判断是否为DICOM文件,可以理解为一个标志信息。 -
文件元信息元素
2、
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):存储描述该项信息的数据值
3、
其中数据元信息可以根据信息的不同,分为4类:
-
Patient
-
Study
-
Series
-
Image
可以理解为一个患者(
patient
)可以做多次检查(
study
),一次检查包含多个检查部位(
series
),而每个检查部位都有一张或多张相应的影像图像(
image
)。常见的TAG如下
4
:
-
Patient Tag
-
Study Tag
-
Series Tag
-
Image Tag
4、Dicom文件转为jpg图片
4.1 处理DICOM文件的现成库
现在有许多现成的解析DICOM标准的第三方库,在工程中引入它们能够高效的进行项目开发,而不需要使用者了解过多底层的解析操作。常见的库如下:
-
C++
:
DCMTK
-
Java
:
dcm4che
-
Python
:
pydicom
本文主要讲解基于
python
中的
pydicom
库处理dicom文件的一些常规操作。
4.2 pydicom的使用
pydicom
简介:
pydicom
是一个python中的第三方库,用于DICOM文件,主要为了以一种简单的”python式”方式检查和修改dicom数据而设计,可以提供给使用者轻松的修改,读写文件并转换成显式图像图片。
1、
由于
pydicom
是第三方库,所以使用之前需要下载,这里推荐python的
pip
指令进行下载,在cmd中输入如下指令进行下载:
pip install pydicom
如果下载速度慢,可以添加清华镜像源:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pydicom
2、
文件的读取以及数据元的获取:
import pydicom
import os
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)
3、
获取图像Tag中的像素矩阵并保存为JPG图片(其中使用matplotlib库进行绘图以及numpy进行矩阵操作,同理需要pip安装):
import pydicom
import matplotlib.pyplot as plt
import numpy as np
import os
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("UID:{}".format(uid))
plt.savefig(jpgname)
plt.close()
效果如图所示:
4、
批量将DICOM文件转换为JPG图像(多进程、高效率):
# coding : utf-8
# DICOM文件读取及JPG格式图片展示
# @Author : Labyrinthine Leo
# @Time : 2020.06.16
"""
import pydicom
import matplotlib.pyplot as plt
import numpy as np
import os
import multiprocessing
import threading
import time
def extractDicomFileInfo(filename):
"""
提取Dicom文件的tag信息
input :文件名
output:相关信息
"""
info = {}
dcm = pydicom.read_file(filename)
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 # 检查项目描述
return info
def saveAsJPGImage(img_array,jpg_path,uid,lens):
"""
格式转换函数
input : 像素矩阵,图片保存路径,uid,lens
output:
"""
plt.figure(figsize=(12,6),dpi=80) # 绘制画板
arr_temp = np.reshape(img_array,(lens,))
max_val = max(arr_temp) # 获取像素极大值
min_val = min(arr_temp) # 获取像素极小值
img_array = (img_array-min_val)/(max_val-min_val) # 像素值归一化
plt.imshow(img_array,cmap=plt.cm.bone)
plt.title("UID:{}".format(uid))
# print("saving image:{}".format(jpg_path.split('JPG图像/')[1]))
plt.savefig(jpg_path)
plt.close()
def getDicomFile(dicom_dir,jpg_dir):
"""
获取dicom文件的参数信息
input : dicom_dir,jpg_dir
output: args_list
"""
# 定位绝对路径
all_file_list = os.listdir(dicom_dir)
# 初始化args_list
args_list = []
for f in all_file_list:
dicom_file_path = os.path.join(dicom_dir,f)
# dicom_info = extractDicomFileInfo(dicom_file_path) # 提取tag信息备用
jpg_name = jpg_dir+f.split('.d')[0]+'.jpg' # 新建jpg文件名
# print(jpg_name)
dcm = pydicom.read_file(dicom_file_path) # 读取dicom文件
img_array = dcm.pixel_array # 获取图像像素矩阵
lens = img_array.shape[0]*img_array.shape[1] # 获取像素矩阵大小
uid = dcm.SOPInstanceUID # 获取图像uid
args_tuple = (img_array,jpg_name,uid,lens) # 添加参数tuple
args_list.append(args_tuple)
return args_list
def main():
"""
main function
"""
# 存放DICOM文件的文件夹
dicom_dir = "../dicom数据集/DICOM/"
# 存放转换后的JPG图片的文件夹
jpg_dir = "../dicom数据集/JPG图像/"
begin_time = time.time() # 开始时间
pool = multiprocessing.Pool(processes=5) # 创建进程池
args_list = getDicomFile(dicom_dir,jpg_dir) # 获取参数list
pool.starmap(saveAsJPGImage,args_list) # 多进程保存jpg文件
pool.close() # 关闭进程
end_time = time.time() # 结束时间
print("耗时:{}s".format(round(end_time-begin_time,4))) # 打印耗时
if __name__ == '__main__':
main()
References
-
[1]
The DICOM Standrad
-
[2]
DICOM
-
[3]
DICOM文件格式
-
[4]
Tags
临渊羡鱼不如退而结网
如果觉得这篇文章对你有用,可以点个赞,也算是对笔者的支持和激励!同时订阅微信公众号:
Leo的博客城堡
公众号原文
:
初识DICOM以及pydicom的基础操作