使用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中使用select模块实现非阻塞的IO
Feb 03 Python
用 Python 连接 MySQL 的几种方式详解
Apr 04 Python
初探利用Python进行图文识别(OCR)
Feb 26 Python
详解pandas删除缺失数据(pd.dropna()方法)
Jun 25 Python
详解PyTorch中Tensor的高阶操作
Aug 18 Python
python 多进程并行编程 ProcessPoolExecutor的实现
Oct 11 Python
基于Python和PyYAML读取yaml配置文件数据
Jan 13 Python
tensorflow mnist 数据加载实现并画图效果
Feb 05 Python
python3 循环读取excel文件并写入json操作
Jul 14 Python
python3中数组逆序输出方法
Dec 01 Python
Python列表元素删除和remove()方法详解
Jan 04 Python
Python语言规范之Pylint的详细用法
Jun 24 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
黑夜路人出的几道php笔试题
2009/08/04 PHP
PHP调用QQ互联接口实现QQ登录网站功能示例
2019/10/24 PHP
基于jquery的图片的切换(以数字的形式)
2011/02/14 Javascript
uploadify 3.0 详细使用说明
2012/06/18 Javascript
JQuery动画和停止动画实例代码
2013/03/01 Javascript
实用的Jquery选项卡TAB示例代码
2013/08/28 Javascript
一张Web前端的思维导图分享
2015/07/03 Javascript
javascript实现动态导入js与css等静态资源文件的方法
2015/07/25 Javascript
JS百度地图搜索悬浮窗功能
2017/01/12 Javascript
JS身份证信息验证正则表达式
2017/06/12 Javascript
AngularJS学习笔记之表单验证功能实例详解
2017/07/06 Javascript
vue3.0 CLI - 2.4 - 新组件 Forms.vue 中学习表单
2018/09/14 Javascript
深入解析ES6中的promise
2018/11/08 Javascript
JS实现的贪吃蛇游戏案例详解
2019/05/01 Javascript
vue用elementui写form表单时,在label里添加空格操作
2020/08/13 Javascript
[08:54]《一刀刀一天》之DOTA全时刻18:十九支奔赴西雅图队伍全部出炉
2014/06/04 DOTA
[01:57]2018年度DOTA2最具潜力解说-完美盛典
2018/12/16 DOTA
在Python中使用swapCase()方法转换大小写的教程
2015/05/20 Python
python自动发邮件库yagmail的示例代码
2018/02/23 Python
python中元组的用法整理
2020/06/15 Python
如何在 Matplotlib 中更改绘图背景的实现
2020/11/26 Python
Python实例教程之检索输出月份日历表
2020/12/16 Python
pandas数据分组groupby()和统计函数agg()的使用
2021/03/04 Python
CSS3实现瀑布流布局与无限加载图片相册的实例代码
2016/12/22 HTML / CSS
家得宝墨西哥官网:The Home Depot墨西哥
2019/11/18 全球购物
大学生专业个人学习的自我评价
2013/10/26 职场文书
给同事的道歉信
2014/01/11 职场文书
协议书范本
2014/04/23 职场文书
2014年感恩母亲演讲稿
2014/05/27 职场文书
人力资源本科毕业生求职信
2014/06/04 职场文书
2014党员学习习主席讲话思想汇报
2014/09/15 职场文书
个人学习党的群众路线教育实践活动心得体会
2014/11/05 职场文书
当幸福来敲门观后感
2015/06/01 职场文书
烛光里的微笑观后感
2015/06/17 职场文书
中秋节主题班会
2015/08/14 职场文书
mysql事务对效率的影响分析总结
2021/10/24 MySQL