使用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魔法方法-属性访问控制详解
Jul 25 Python
Python操作MongoDB详解及实例
May 18 Python
python matplotlib中文显示参数设置解析
Dec 15 Python
Python实现随机漫步功能
Jul 09 Python
flask session组件的使用示例
Dec 25 Python
python如何制作英文字典
Jun 25 Python
django如何自己创建一个中间件
Jul 24 Python
对python中的*args与**kwgs的含义与作用详解
Aug 28 Python
Python箱型图绘制与特征值获取过程解析
Oct 22 Python
Python for循环及基础用法详解
Nov 08 Python
Python3 Click模块的使用方法详解
Feb 12 Python
python缺失值的解决方法总结
Jun 09 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
php5 apache 2.2 webservice 创建与配置(java)
2011/01/27 PHP
PHP数组无限分级数据的层级化处理代码
2012/12/29 PHP
浅析php如何实现App常用的秒发功能
2016/08/03 PHP
ThinkPHP实现简单登陆功能
2017/04/28 PHP
yii框架结合charjs统计上一年与当前年数据的方法示例
2020/04/04 PHP
基于PHP实现发微博动态代码实例
2020/12/11 PHP
身份证号码前六位所代表的省,市,区, 以及地区编码下载
2007/04/12 Javascript
利用ajaxfileupload插件实现文件上传无刷新的具体方法
2013/06/08 Javascript
复选框全选与全不选操作实现思路
2013/08/18 Javascript
JavaScript用JQuery呼叫Server端方法示例代码
2014/09/03 Javascript
JavaScript对象属性检查、增加、删除、访问操作实例
2015/07/08 Javascript
jQuery ready()和onload的加载耗时分析
2016/09/08 Javascript
详解webpack+gulp实现自动构建部署
2017/06/29 Javascript
微信小程序实现简单input正则表达式验证功能示例
2017/11/30 Javascript
基于Vue的ajax公共方法(详解)
2018/01/20 Javascript
原生JavaScript实现remove()和recover()功能示例
2018/07/24 Javascript
[53:52]OG vs EG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
[02:07]TI9显影之尘系列 - Vici Gaming
2019/08/20 DOTA
Python中函数的参数定义和可变参数用法实例分析
2015/06/04 Python
windows下安装Python和pip终极图文教程
2017/03/05 Python
利用Python写一个爬妹子的爬虫
2018/06/08 Python
Python封装成可带参数的EXE安装包实例
2019/08/24 Python
jupyter notebook 的工作空间设置操作
2020/04/20 Python
python中JWT用户认证的实现
2020/05/18 Python
使用Python防止SQL注入攻击的实现示例
2020/05/21 Python
Python 实现敏感目录扫描的示例代码
2020/05/21 Python
Python能做什么
2020/06/02 Python
keras的ImageDataGenerator和flow()的用法说明
2020/07/03 Python
CSS3截取字符串实例代码【推荐】
2018/06/07 HTML / CSS
Kate Spade澳大利亚官方网站:美国设计师手袋品牌
2019/09/10 全球购物
教师一岗双责责任书
2014/04/16 职场文书
“六查”、“三学”、“三干”查摆问题整改措施
2014/09/27 职场文书
元旦标语大全
2014/10/09 职场文书
领导班子整改方案
2014/10/25 职场文书
新手开公司创业注意事项有哪些?
2019/07/29 职场文书
如何在C++中调用Python
2021/05/21 Python