使用Python对Dicom文件进行读取与写入的实现


Posted in Python onApril 20, 2020

Pydicom

单张影像的读取

使用 pydicom.dcmread() 函数进行单张影像的读取,返回一个pydicom.dataset.FileDataset对象.

import os
import pydicom
# 调用本地的 dicom file 
folder_path = r"D:\Files\Data\Materials"
file_name = "PA1_0001.dcm"
file_path = os.path.join(folder_path,file_name)
ds = pydicom.dcmread(file_path)

在一些特殊情况下,比如直接读取从医院拿到的数据(未经任何处理)时,可能会发生以下报错:

raise InvalidDicomError("File is missing DICOM File Meta Information "
pydicom.errors.InvalidDicomError: File is missing DICOM File Meta Information header or the 'DICM' prefix is missing from the header. Use force=True to force reading.

可以看到,由于缺失文件元信息头,无法直接读取,只能强行读取.这种情况可以直接根据提示,调整命令为:

ds = pydicom.dcmread(file_path,force=True)

但后续还会碰到:

AttributeError: 'Dataset' object has no attribute 'TransferSyntaxUID'

在网上检索后发现,可以通过设置TransferSyntaxUID来解决问题:

ds.file_meta.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian

这样就大功告成了(这里实际上就提前接触到了下面读取Dicom Tags的内容了)

一些简单处理

读取成功后,我们可以对 Dicom文件 进行一些简单的处理

读取并编辑Dicom Tags

可以通过两种方法来读取Tag的值

使用的Tag的Description

print(ds.PatientID,ds.StudyDate,ds.Modality)

使用 ds.get() 函数. 函数内参数采用的是Tag ID.几种简单的打开Dicom文件的软件(如RadiAnt DICOM Viewer)都可以直接看到.这里不再赘述.

ds.get(0x00100020) # 这里得到的是PatientID

读取到相应的Tag值后, 也可以将其他的值写入这些Tag.只要最后保存一下就可以了.

借助Numpy与PIL.Image

读取Dicom文件后,可以借助Numpy以及图像处理库(如PIL.Image)来进行简单的处理.

借助Numpy

import numpy as np
data = np.array(ds.pixel_array)

注意这里使用的是 np.array() 而不是 np.asarray(). 因为前者的更改并不会带来原pixel_array的改变.
在转化为ndarray后 可以直接进行简单的切割和连接,比如截取某一部分和将两张图像拼在一起等,之后再写入并保存下来即可.

借助PIL.Image

from PIL import Image
data_img = Image.fromarray(ds.pixel_array)
data_img_rotated = data_img.rotate(angle=45,resample=Image.BICUBIC,fillcolor=data_img.getpixel((0,0)))

这里展示的是旋转, 还有其他功能如resize等.
需要注意的是,从Numpy的ndarray转化为Image时,一般会发生变化:

print(data.dtype) # int16
data_rotated = np.array(data_img_rotated)
print(data_img) # int32

只需要指定参数就可以解决了

data_rotated = np.array(data_img_rotated,dtype = np.int16)

可视化

简单的可视化Pydicom没有直接的实现方法,我们可以通过上面借助Matplotlib以及Image模块来实现.但效果有限.

借助 Matplotlib (Pydicom官方文档中使用的方法)

from matplotlib import pyplot
pyplot.imshow(ds.pixel_array,cmap=pyplot.cm.bone)
pyplot.show()

效果如图所示:

使用Python对Dicom文件进行读取与写入的实现

但真实的图像是:

使用Python对Dicom文件进行读取与写入的实现

显然颜色是有区别的.导致这种差别的原因是pyplot函数使用的cm也就是"color map" 是简单的"bone" 并不能满足医学图像的要求.

借助Image模块

data_img.show()

一条指令即可,但是效果很差,如图所示:

使用Python对Dicom文件进行读取与写入的实现

综合来看,两种方法都不是很好.

单张影像的写入

经过上面对Tag值的修改, 对图像的切割, 旋转等操作.最后需要重新写入该Dicom文件.

ds.PixelData = data_rotated.tobytes()
ds.Rows,ds.Columns = data_rotated.shape
new_name = "dicom_rotated.dcm"
ds.save_as(os.path.join(folder_path,new_name))

SimpleITK

SimpleITK 是从基于C++的ITK迁移到Python的,所以很多方法的使用都跟C++很相似.

import SimpleITK as sitk

单张影像的读取

有两种方法:

sitk.ReadImage()
这种方法直接返回image对象,简单易懂.但是无法读取Tag的值.

img = sitk.ReadImage(file_path)
print(type(img)) # <class 'SimpleITK.SimpleITK.Image'>

sitk.ImageFileReader()
这种方法比较像C++的操作风格,需要先初始化一个对象,然后设置一些参数,最后返回image.相对更复杂,但可以操作的点比较多

file_reader = sitk.ImageFileReader()
file_reader.SetFileName(file_path) #这里只显示了必需的,还有很多可以设置的参数
data = file_reader.Execute()
# 使用这种方法读取Dicom的Tag Value
for key in file_reader.GetMetaDataKeys():
 print(key,file_reader.GetMetaData(key))

以上两种方法返回的都是三维的对象,这与Pydicom有很大的不同.

data_np = sitk.GetArrayFromImage(data)
print(data_np.shape) # (1, 512, 512) = (Slice index, Rows, Columns)

序列读取

序列读取的方法与单张图像读取的第二种方法很相似.
(暂且只发现了一种方法读取序列,如果还有其他方法,请在评论区予以补充,感谢!)

series_reader = sitk.ImageSeriesReader()
fileNames = series_reader.GetGDCMSeriesFileNames(folder_name)
series_reader.SetFileNames(fileNames)
images = series_reader.Execute()

同样,返回的也是三维的对象.

一些简单操作

SimpleITK 包含很多图像处理如滤波的工具,这里简单介绍一个边缘检测工具和可视化工具

边缘检测

以Canny边缘检测算子为例,与读取单张图像类似,同样有两种方式:

sitk.CannyEdgeDetection()
由于滤波的对象必须是32位图像或者其他格式, 需要通过 sitk.Cast() 转换. 之后可以再转换回原格式.

data_32 = sitk.Cast(data,sitk.sitkFloat32)
data_edge_1 = sitk.CannyEdgeDetection(data_32,5,30,[5]*3,[0.8]*3)

sitk.CannyEdgeDetectionImageFilter()
这个操作相对麻烦一些

Canny = sitk.CannyEdgeDetectionImageFilter()
Canny.SetLowerThreshold(5)
Canny.SetUpperThreshold(30)
Canny.SetVariance([5]*3)
Canny.SetMaximumError([0.5]*3)
data_edge_2 = Canny.Execute(data_32)

可视化

可视化的方法非常简单 只需要一条指令:

sitk.Show()

但需要先安装工具ImageJ,否则无法使用.具体的安装链接,可以参考这篇博文:sitk.show()与imageJ结合使用常见的问题

同一张Dicom文件使用sitk.Show()得到的效果如下图:

使用Python对Dicom文件进行读取与写入的实现

除此之外,ImageJ还有一个Tool Bar 支持对图像的进一步处理:

使用Python对Dicom文件进行读取与写入的实现

可见,SimpleITK的可视化要比上面介绍的强大很多,不仅可以实现单张图像的可视化以及图像处理,还可以同时对整个序列的图像进行统一处理.

单张影像的写入

同样有两种方法

sitk.WriteImage()

new_name = "new_MR_2.dcm"
sitk.WriteImage(img,os.path.join(folder_name,new_name))

sitk.ImageFileWriter()

file_writer = sitk.ImageFileWriter()
file_writer.SetFileName(os.path.join(folder_name,new_name))
file_writer.SetImageIO(imageio="GDCMImageIO")
file_writer.Execute(img)

使用这两种方法进行写入的时候,会发现,即便什么也没有做,但得到的新Dicom文件要小于原始的Dicom文件.这是因为新的Dicom文件中没有Private Creator信息(属于Dicom Tag的内容).当然如果原始Dicom文件中本就没有这种信息,文件大小是保持相同的.
因为很多时候只是对图像进行处理,所以不再深究.

到此这篇关于使用Python对Dicom文件进行读取与写入的实现的文章就介绍到这了,更多相关Python Dicom文件进行读取与写入内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python的Urllib库的基本使用教程
Apr 30 Python
Python操作串口的方法
Jun 17 Python
python制作websocket服务器实例分享
Nov 20 Python
Django入门使用示例
Dec 12 Python
Python中xml和json格式相互转换操作示例
Dec 05 Python
python读取目录下所有的jpg文件,并显示第一张图片的示例
Jun 13 Python
基于python 微信小程序之获取已存在模板消息列表
Aug 05 Python
解决Python3用PIL的ImageFont输出中文乱码的问题
Aug 22 Python
Python Tornado批量上传图片并显示功能
Mar 26 Python
python 批量下载bilibili视频的gui程序
Nov 20 Python
Python就将所有的英文单词首字母变成大写
Feb 12 Python
Python 键盘事件详解
Nov 11 Python
python 错误处理 assert详解
Apr 20 #Python
解决Jupyter Notebook使用parser.parse_args出现错误问题
Apr 20 #Python
在ipython notebook中使用argparse方式
Apr 20 #Python
Python绘制全球疫情变化地图的实例代码
Apr 20 #Python
spyder 在控制台(console)执行python文件,debug python程序方式
Apr 20 #Python
python实现小程序推送页面收录脚本
Apr 20 #Python
在spyder IPython console中,运行代码加入参数的实例
Apr 20 #Python
You might like
如何在WIN2K下安装PHP4.04
2006/10/09 PHP
PHP Stream_*系列函数
2010/08/01 PHP
PHP面向对象教程之自定义类
2014/06/10 PHP
PHP之autoload运行机制实例分析
2014/08/28 PHP
PHP加密技术的简单实现
2016/09/04 PHP
Javascript 浮点运算的问题分析与解决方法
2013/08/27 Javascript
解析JSON对象与字符串之间的相互转换
2013/12/18 Javascript
使用jQuery判断IE浏览器版本的代码
2014/06/14 Javascript
Nodejs中自定义事件实例
2014/06/20 NodeJs
Javascript 绘制 sin 曲线过程附图
2014/08/21 Javascript
JavaScript中连接操作Oracle数据库实例
2015/04/02 Javascript
javascript设计模式--策略模式之输入验证
2015/11/27 Javascript
不得不分享的JavaScript常用方法函数集(下)
2015/12/25 Javascript
JavaScript小技巧整理篇(非常全)
2016/01/26 Javascript
JavaScript中常见内置函数用法示例
2018/05/14 Javascript
nodejs实现套接字服务功能详解
2018/06/21 NodeJs
Vue高版本中一些新特性的使用详解
2018/09/25 Javascript
Layui点击图片弹框预览的实现方法
2019/09/16 Javascript
Python标准库inspect的具体使用方法
2017/12/06 Python
django限制匿名用户访问及重定向的方法实例
2018/02/07 Python
python如何实现int函数的方法示例
2018/02/19 Python
Django REST framework内置路由用法
2019/07/26 Python
Django 路由层URLconf的实现
2019/12/30 Python
VSCode基础使用与VSCode调试python程序入门的图文教程
2020/03/30 Python
使用python处理题库表格并转化为word形式的实现
2020/04/14 Python
使用sublime text3搭建Python编辑环境的实现
2021/01/12 Python
香港中原电器网上商店:Chung Yuen
2019/06/26 全球购物
override和overload的区别
2016/03/09 面试题
植树造林的宣传标语
2014/06/23 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
学校总务处领导干部个人对照检查材料思想汇报
2014/10/06 职场文书
2014预防青少年违法犯罪工作总结
2014/12/10 职场文书
就业证明函
2015/06/17 职场文书
合理化建议书范文
2015/09/14 职场文书
古诗之感恩老师
2019/10/24 职场文书
java基础——多线程
2021/07/03 Java/Android