dicom文件_图像识别 | 使用Python对医学Dicom文件的预处理(含代码)
前沿
在处理医学图像时,常常会遇到以Dicom格式保存的医学图像,如CT、MRI等。Dicom文件是需要专门的软件或者通过编程,应用相应的库进行处理。为了能够更好地服务下游任务,例如分割或检测腹腔CT图像中某个病灶组织,需要先将Dicom图像进行读取,脱敏,调窗等步骤,以便于后续的编辑。本文使用python对医学Dicom文件进行相应的处理,相比于封装好的软件,笔者认为自己动手的可操作性更强。
目录
1 导入相应的包
2 读取Dicom图像数据
3 设置CT图像的窗宽和窗位
4 获取Dicom图像的tag信息
5 结果保存及可视化
导入相应的包
# load necessary packages
import matplotlib.pyplot as plt
import pydicom.uid
import sys
from PyQt5 import QtGui
import os
import pydicom
import glob
from PIL import *
import matplotlib.pyplot as plt
from pylab import *
from tkinter.filedialog import *
import PIL.Image as Image
其核心是使用了python中的pydicom库来处理dicom文件。
读取Dicom图像数据
have_numpy = Truetry:import numpy
except ImportError:have_numpy = Falseraisesys_is_little_endian = (sys.byteorder == 'little')NumpySupportedTransferSyntaxes = [pydicom.uid.ExplicitVRLittleEndian,pydicom.uid.ImplicitVRLittleEndian,pydicom.uid.DeflatedExplicitVRLittleEndian,pydicom.uid.ExplicitVRBigEndian,
]# 支持"传输"语法
def supports_transfer_syntax(dicom_dataset):return (dicom_dataset.file_meta.TransferSyntaxUID inNumpySupportedTransferSyntaxes)def needs_to_convert_to_RGB(dicom_dataset):return Falsedef should_change_PhotometricInterpretation_to_RGB(dicom_dataset):return False# 加载 Dicom图像
def get_pixeldata(dicom_dataset):"""If NumPy is available, return an ndarray of the Pixel Data.Raises------TypeErrorIf there is no Pixel Data or not a supported data type.ImportErrorIf NumPy isn't foundNotImplementedErrorif the transfer syntax is not supportedAttributeErrorif the decoded amount of data does not match the expected amountReturns-------numpy.ndarrayThe contents of the Pixel Data element (7FE0,0010) as an ndarray."""if (dicom_dataset.file_meta.TransferSyntaxUID not inNumpySupportedTransferSyntaxes):raise NotImplementedError("Pixel Data is compressed in a ""format pydicom does not yet handle. ""Cannot return array. Pydicom might ""be able to convert the pixel data ""using GDCM if it is installed.")if not have_numpy:msg = ("The Numpy package is required to use pixel_array, and ""numpy could not be imported.")raise ImportError(msg)if 'PixelData' not in dicom_dataset:raise TypeError("No pixel data found in this dataset.")# Make NumPy format code, e.g. "uint16", "int32" etc# from two pieces of info:# dicom_dataset.PixelRepresentation -- 0 for unsigned, 1 for signed;# dicom_dataset.BitsAllocated -- 8, 16, or 32if dicom_dataset.BitsAllocated == 1:# single bits are used for representation of binary dataformat_str = 'uint8'elif dicom_dataset.PixelRepresentation == 0:format_str = 'uint{}'.format(dicom_dataset.BitsAllocated)elif dicom_dataset.PixelRepresentation == 1:format_str = 'int{}'.format(dicom_dataset.BitsAllocated)else:format_str = 'bad_pixel_representation'try:numpy_dtype = numpy.dtype(format_str)except TypeError:msg = ("Data type not understood by NumPy: ""format='{}', PixelRepresentation={}, ""BitsAllocated={}".format(format_str,dicom_dataset.PixelRepresentation,dicom_dataset.BitsAllocated))raise TypeError(msg)if dicom_dataset.is_little_endian != sys_is_little_endian:numpy_dtype = numpy_dtype.newbyteorder('S')pixel_bytearray = dicom_dataset.PixelDataif dicom_dataset.BitsAllocated == 1:# if single bits are used for binary representation, a uint8 array# has to be converted to a binary-valued array (that is 8 times bigger)try:pixel_array = numpy.unpackbits(numpy.frombuffer(pixel_bytearray, dtype='uint8'))except NotImplementedError:# PyPy2 does not implement numpy.unpackbitsraise NotImplementedError('Cannot handle BitsAllocated == 1 on this platform')else:pixel_array = numpy.frombuffer(pixel_bytearray, dtype=numpy_dtype)length_of_pixel_array = pixel_array.nbytesexpected_length = dicom_dataset.Rows * dicom_dataset.Columnsif ('NumberOfFrames' in dicom_dataset anddicom_dataset.NumberOfFrames > 1):expected_length *= dicom_dataset.NumberOfFramesif ('SamplesPerPixel' in dicom_dataset anddicom_dataset.SamplesPerPixel > 1):expected_length *= dicom_dataset.SamplesPerPixelif dicom_dataset.BitsAllocated > 8:expected_length *= (dicom_dataset.BitsAllocated // 8)padded_length = expected_lengthif expected_length & 1:padded_length += 1if length_of_pixel_array != padded_length:raise AttributeError("Amount of pixel data %d does not ""match the expected data %d" %(length_of_pixel_array, padded_length))if expected_length != padded_length:pixel_array = pixel_array[:expected_length]if should_change_PhotometricInterpretation_to_RGB(dicom_dataset):dicom_dataset.PhotometricInterpretation = "RGB"if dicom_dataset.Modality.lower().find('ct') >= 0: # CT图像需要得到其CT值图像pixel_array = pixel_array * dicom_dataset.RescaleSlope + dicom_dataset.RescaleIntercept # 获得图像的CT值pixel_array = pixel_array.reshape(dicom_dataset.Rows, dicom_dataset.Columns*dicom_dataset.SamplesPerPixel)return pixel_array, dicom_dataset.Rows, dicom_dataset.Columns
读取到dicom文件中的数据后,实质上是几个图像矩阵,这个过程同时也处理了“脱敏”问题。
设置CT图像的窗宽和窗位
def setDicomWinWidthWinCenter(img_data, winwidth, wincenter, rows, cols):img_temp = img_dataimg_temp.flags.writeable = Truemin = (2 * wincenter - winwidth) / 2.0 + 0.5max = (2 * wincenter + winwidth) / 2.0 + 0.5dFactor = 255.0 / (max - min)for i in numpy.arange(rows):for j in numpy.arange(cols):img_temp[i, j] = int((img_temp[i, j]-min)*dFactor)min_index = img_temp < minimg_temp[min_index] = 0max_index = img_temp > maximg_temp[max_index] = 255return img_temp
该函数的输入变量winwidth和wincenter即为需要设置的窗宽和窗位,这两个值根据研究的问题(不同的组织器官对应不同的窗宽和窗位,有时候也要根据图像效果进行一定的调整)调整不同的值。网上有很多关于相关的窗位和窗宽对应值,这里给出一些参考资料,如果遇到不确定的,最好借鉴查阅相应领域的论文。
Windowing (CT) | Radiology Reference Article | Radiopaedia.orgradiopaedia.org
获取Dicom图像的tag信息
def loadFileInformation(filename):information = {}ds = pydicom.read_file(filename)information['PatientID'] = ds.PatientIDinformation['PatientName'] = ds.PatientNameinformation['PatientBirthDate'] = ds.PatientBirthDateinformation['PatientSex'] = ds.PatientSexinformation['StudyID'] = ds.StudyIDinformation['StudyDate'] = ds.StudyDateinformation['StudyTime'] = ds.StudyTimeinformation['InstitutionName'] = ds.InstitutionNameinformation['Manufacturer'] = ds.Manufacturerprint(dir(ds))print(type(information))return information
这个步骤视需求而定,如果不需要查看dicom文件的具体tag信息,此步骤可以跳过。
结果保存及可视化
可以单张保存,或者批量处理。
读取单张dicom文件
def main_single():dcm = dicom.read_file('81228816') # load dicom_file# 得到 CT 值,图像的 长, 宽pixel_array, dcm.Rows, dcm.Columns = get_pixeldata(dcm)# 调整窗位、窗宽img_data = pixel_arraywinwidth = 500wincenter = 50rows = dcm.Rowscols = dcm.Columnsdcm_temp = setDicomWinWidthWinCenter(img_data, winwidth, wincenter, rows, cols)# 可视化dcm_img = Image.fromarray(dcm_temp) # 将Numpy转换为PIL.Imagedcm_img = dcm_img.convert('L')# plt.imshow(img, cmap=plt.cm.bone)# 保存为jpg文件,用作后面的生成label用dcm_img.save('../output/temp.jpg')# 显示图像dcm_img.show()
同时读取一个文件夹中的 dicom 文件,并处理保存 (写成循环即可)
def
注意,以上都写成函数的形式,运行时需要调用,并注意文件路径的修改。
单张dicom文件处理
main_single()
批量处理
main_mulit(path)
公众号文章链接:
图像识别 | 使用Python对医学Dicom文件的预处理(含代码)mp.weixin.qq.com
觉得有收获的话,麻烦点个赞再走呗~
dicom文件_图像识别 | 使用Python对医学Dicom文件的预处理(含代码)相关推荐
- python dicom 器官分割_图像识别 | 使用Python对医学Dicom文件的预处理(含代码)
前沿 在处理医学图像时,常常会遇到以Dicom格式保存的医学图像,如CT.MRI等.Dicom文件是需要专门的软件或者通过编程,应用相应的库进行处理.为了能够更好地服务下游任务,例如分割或检测腹腔CT ...
- python解析sql文件_如何从Python中解析sql文件?
是否有任何方法可以从Python中执行.SQL文件中的某些SQL命令,而不是文件中的所有SQL命令?假设我有以下.sql文件:DROP TABLE IF EXISTS `tableA`; CREATE ...
- python怎样打开加密的文件_如何使用python加密多个文件
我正在尝试搜索指定文件夹中的.txt文件,并对使用我的加密算法找到的每个.txt文件进行加密.不过,我似乎无法能够弄清楚如何将所有的文件夹中找到的.txt文件加密并重新命名如何使用python加密多个 ...
- python 读取sqlite存入文件_如何通过python读取sqlite数据文件
sqlite简介:sqlite是一个进程内的库,实现了自给自足的.无服务器的.零配置的.事务性的 SQL 数据库引擎.它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它(如安卓系统),它占 ...
- python 读取日志文件_如何在Python中跟踪日志文件?
使用SH模块(PIP安装sh):from sh import tail# runs foreverfor line in tail("-f", "/var/log/som ...
- python发送excel文件_如何在Python中使用Excel文件(xlsx)附件发送电子邮件
我需要发送一封带有Excel附件的电子邮件 我的代码如下,可以发送电子邮件 但是当我收到邮件时,附件文件不是Excel文件~~ 看来我附加的格式不对~~~ 我添加了不同的电子邮件地址来接收此电子邮件 ...
- python 资源文件_如何用 Python 正确读取资源文件
但这样写稍显麻烦. 如果你的 Python 版本不低于3.7,那么你可以使用importlib.resources来快速读取资源文件: from importlib import resources ...
- python读取lmdb文件_如何使用python創建LMDB文件
匿名用户 1级 2018-11-19 回答 import numpy as np import os import matplotlib.pyplot as plt import lmdb from ...
- python打开zip文件_如何从Python中的zip文件中读取?
我有一个我想要阅读的文件本身是压缩在一个zip档案.例如,parent.zip包含child.zip,其中包含child.txt.我在阅读child.zip时遇到麻烦.有人可以修改我的代码吗? 我假设 ...
最新文章
- nagios 监控NFS
- pytorch模型转换
- docker镜像为什么要采用分层结构
- 小程序button去除边框
- AI开发者顶会,这一次,人人都可以参加!
- 框架整合——Spring与MyBatis框架整合
- HTML5基础知识习题 一
- 教你免费轻松下载百度文库的文件
- R语言绘图的配色——ggsci
- pwnable.kr第二遍---mistake
- 雅虎终于死了:从市值 1000 亿到贱卖 48 亿,到最后连名字都没保住
- 腾讯视频VIP会员,周卡特价9.5元!
- 值得学习的言语 | 对话技巧 | 开场白
- 什么是ActiveRecord
- 数据类型和运算符(使用Python的AI编程2部1单元2课)
- 芮城县县名由来 芮伯庙 古魏城 芮伯万 永乐县
- 怎样共享苹果Mac上的 Wi-Fi 密码?
- 2017年中兴捧月神算师算法精英挑战赛之阿尔法勒克斯特派(AlphaNext派)-----进来加群咯
- 计算机网络技术课程答案网课,《计算机网络技术》大学生网课答案.docx
- Okhttp之Https
热门文章
- go语言和java并发_彻底搞清楚Java并发 (一) 基础
- qt调用c语言编写的dll文件,Qt之调用外部DLL - moki_oschina的个人空间 - OSCHINA - 中文开源技术交流社区...
- unity 打开指定文件夹_unity 打开指定路径文件夹
- dynamo方程怎么写_根据以下说明,画出因果关系图,建立流图模型,并拟定变量名称和适当数据,写出对应的...
- js post中服务器500错误信息,node.js - Node Express Post 500(内部服务器错误)jquery-3.4.1.min.js - 堆栈内存溢出...
- 广义hough变换matlab,matlab – 广义Hough R表
- 怎么添加新项目到svn服务器,用eclipse+svn插件,上传新项目到svn服务器
- 实时检测神经振荡可实现行为相关的神经反馈
- JAVA实现斐波那契数列问题(《剑指offer》)
- 魔改ResNet反超Transformer再掀架构之争!作者说“没一处是创新”,这些优化trick值得学...