前沿

在处理医学图像时,常常会遇到以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.org​radiopaedia.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文件的预处理(含代码)相关推荐

  1. python dicom 器官分割_图像识别 | 使用Python对医学Dicom文件的预处理(含代码)

    前沿 在处理医学图像时,常常会遇到以Dicom格式保存的医学图像,如CT.MRI等.Dicom文件是需要专门的软件或者通过编程,应用相应的库进行处理.为了能够更好地服务下游任务,例如分割或检测腹腔CT ...

  2. python解析sql文件_如何从Python中解析sql文件?

    是否有任何方法可以从Python中执行.SQL文件中的某些SQL命令,而不是文件中的所有SQL命令?假设我有以下.sql文件:DROP TABLE IF EXISTS `tableA`; CREATE ...

  3. python怎样打开加密的文件_如何使用python加密多个文件

    我正在尝试搜索指定文件夹中的.txt文件,并对使用我的加密算法找到的每个.txt文件进行加密.不过,我似乎无法能够弄清楚如何将所有的文件夹中找到的.txt文件加密并重新命名如何使用python加密多个 ...

  4. python 读取sqlite存入文件_如何通过python读取sqlite数据文件

    sqlite简介:sqlite是一个进程内的库,实现了自给自足的.无服务器的.零配置的.事务性的 SQL 数据库引擎.它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它(如安卓系统),它占 ...

  5. python 读取日志文件_如何在Python中跟踪日志文件?

    使用SH模块(PIP安装sh):from sh import tail# runs foreverfor line in tail("-f", "/var/log/som ...

  6. python发送excel文件_如何在Python中使用Excel文件(xlsx)附件发送电子邮件

    我需要发送一封带有Excel附件的电子邮件 我的代码如下,可以发送电子邮件 但是当我收到邮件时,附件文件不是Excel文件~~ 看来我附加的格式不对~~~ 我添加了不同的电子邮件地址来接收此电子邮件 ...

  7. python 资源文件_如何用 Python 正确读取资源文件

    但这样写稍显麻烦. 如果你的 Python 版本不低于3.7,那么你可以使用importlib.resources来快速读取资源文件: from importlib import resources ...

  8. python读取lmdb文件_如何使用python創建LMDB文件

    匿名用户 1级 2018-11-19 回答 import numpy as np import os import matplotlib.pyplot as plt import lmdb from ...

  9. python打开zip文件_如何从Python中的zip文件中读取?

    我有一个我想要阅读的文件本身是压缩在一个zip档案.例如,parent.zip包含child.zip,其中包含child.txt.我在阅读child.zip时遇到麻烦.有人可以修改我的代码吗? 我假设 ...

最新文章

  1. nagios 监控NFS
  2. pytorch模型转换
  3. docker镜像为什么要采用分层结构
  4. 小程序button去除边框
  5. AI开发者顶会,这一次,人人都可以参加!
  6. 框架整合——Spring与MyBatis框架整合
  7. HTML5基础知识习题 一
  8. 教你免费轻松下载百度文库的文件
  9. R语言绘图的配色——ggsci
  10. pwnable.kr第二遍---mistake
  11. 雅虎终于死了:从市值 1000 亿到贱卖 48 亿,到最后连名字都没保住
  12. 腾讯视频VIP会员,周卡特价9.5元!
  13. 值得学习的言语 | 对话技巧 | 开场白
  14. 什么是ActiveRecord
  15. 数据类型和运算符(使用Python的AI编程2部1单元2课)
  16. 芮城县县名由来 芮伯庙 古魏城 芮伯万 永乐县
  17. 怎样共享苹果Mac上的 Wi-Fi 密码?
  18. 2017年中兴捧月神算师算法精英挑战赛之阿尔法勒克斯特派(AlphaNext派)-----进来加群咯
  19. 计算机网络技术课程答案网课,《计算机网络技术》大学生网课答案.docx
  20. Okhttp之Https

热门文章

  1. go语言和java并发_彻底搞清楚Java并发 (一) 基础
  2. qt调用c语言编写的dll文件,Qt之调用外部DLL - moki_oschina的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. unity 打开指定文件夹_unity 打开指定路径文件夹
  4. dynamo方程怎么写_根据以下说明,画出因果关系图,建立流图模型,并拟定变量名称和适当数据,写出对应的...
  5. js post中服务器500错误信息,node.js - Node Express Post 500(内部服务器错误)jquery-3.4.1.min.js - 堆栈内存溢出...
  6. 广义hough变换matlab,matlab – 广义Hough R表
  7. 怎么添加新项目到svn服务器,用eclipse+svn插件,上传新项目到svn服务器
  8. 实时检测神经振荡可实现行为相关的神经反馈
  9. JAVA实现斐波那契数列问题(《剑指offer》)
  10. 魔改ResNet反超Transformer再掀架构之争!作者说“没一处是创新”,这些优化trick值得学...