使用pydicom实现Dicom文件读取与CT图像窗宽窗位调整
1. 前言
为了能够在Labelme上对Dicom图像进行编辑,这里对python环境下Dicom文件的读取进行了研究。在Dicom图像中CT的窗宽窗位是一个很重要的概念,但是找了半天在pydicom中没有相关设置函数,这里跟DCMTK还不一样。但是可以根据两个tag得到CT图像的CT值,那就是(0028|1052):rescale intercept和(0028|1053):rescale slope。则按照下面的算子得到CT图像,进而就可以调整窗宽窗位了
Hu = pixel * slope + intercept
至于那个部位的窗宽窗位是多少各位看官就可以自行百度了。
2. 代码实现
# -*- coding=utf-8 -*-
import matplotlib.pyplot as plt
import pydicom
import pydicom.uid
import sys
import PIL.Image as Image
from PyQt5 import QtGui
import os
step1:读取Dicom图像数据与得到CT值图像(CT图)
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):"""Returns-------boolTrue if this pixel data handler might support this transfer syntax.False to prevent any attempt to try to use this handlerto decode the given transfer syntax"""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.")# 设置窗宽窗位#dicom_dataset.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
step2:对于CT图像设置窗宽窗位
# 调整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 < 0img_temp[min_index] = 0max_index = img_temp > 255img_temp[max_index] = 255return img_temp
step3:获取Dicom中的tag信息
第一种方式:
# 加载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
第二种方式
dcm = pydicom.dcmread(fileanme) # 加载Dicom数据print(dcm[0x0008, 0x0060])
>>(0008, 0060) Modality CS: 'MR'
print(dcm[0x0008, 0x0060].VR)
>>CS
print(dcm[0x0008, 0x0060].value)
>>MR
step4:Dicom图像数据转换为PIL.Image
dcm = pydicom.dcmread(fileanme) # 加载Dicom数据
dcm_img = Image.fromarray(img_data) # 将Numpy转换为PIL.Image
dcm_img = dcm_img.convert('L')# 保存为jpg文件,用作后面的生成label用
dcm_img.save('temp.jpg')
# 显示图像
dcm_img.show()
3. 结果展示
调整了窗宽窗位的脑部CT图像:
4. 参考资料
- Pydicom User Guide
- 【医学影像】窗宽窗位与其处理方法
使用pydicom实现Dicom文件读取与CT图像窗宽窗位调整相关推荐
- python nii 图像读取,转换成CT 值,设置窗宽窗位,保存成png 图像
import numpy as np import os # 遍历文件夹 import nibabel as nib # nii格式一般都会用到这个包 import imageio # 转换成图像ce ...
- CT图像之Hu值变换与窗宽窗位调整
今天通过分析实验结果,完善了之前的预处理代码,借此博文分享给大家,另外 点击此处可以查看预处理的完整代码,欢迎大家一起来完善. 最重要的是,欢迎大家的批评指正,您的建议和意见将会是我成长源泉. 接下来 ...
- matlab设置固定的窗宽窗位,python实现CT窗宽窗位的调整(即指定HU值保存图像)...
最近一直在做实验,所以好久没有更新了,先把上周做的一些小的实验贴出来供大家分享. 在医生诊断时,是会将CT图像调整成不同的窗来处理的.比如说肺部CT吧,肺窗(窗宽为2000,窗位为-400)用于看小的 ...
- CT图像中的窗宽和窗位
通常我们称CT图像为DICOM(Digital Imaging and Communications in Medicine)图像,但是DICOM不是一个图像或者文件格式,它是包含了传输.存储.检索. ...
- CT值以及窗宽窗位(未完待续)
1 常见人体组织的CT值(HU) 常见人体组织的CT值(HU)组织 CT值 组织 CT值骨组织 >400 肝脏 50-70 钙值 80-300 脾脏 35-60 血块 64-84 胰腺 30-5 ...
- DICOM文件读取及PNG格式图片展示
import globimport pydicom import matplotlib.pyplot as plt import numpy as np import os import multip ...
- matlab设置固定的窗宽窗位,【经验谈】如何设定窗宽窗位,附正常人体组织CT值...
让学习成为一种习惯! 医学影像服务中心拥有500病例征象+讲座 一般CT机可显示的CT值范围为-1000-+1000共2000个密度等级,而人的肉眼仅能识别16个灰阶,若把2000个CT值分成16个灰 ...
- CT图像分割dicom文件与nii.gz文件预处理----窗宽(window width)和窗位(window level)的设置
最近被CT图像的值弄得很烦,记录一下. CT分割也是个很热门的话题,病灶分割,器官分割等. CT图像大多是两种格式.dcm和nii.gz,当然也有别的,但这里我就不说别的,就说这两种常用的. .dcm ...
- Deeplung:深度学习项目笔记(二)——医学影像学dicom,mhd及raw文件读取与可视化
目录 医学影像学 dicom文件相关 1.1 什么是dicom图像 1.2 dicom图像中有什么 1.3 dicom结构及组成 1.3.1 文件头 1.3.2 数据集 raw文件相关 mhd文件相关 ...
最新文章
- OpenCV中的尺度不变特征变换(SIFT Scale-Invariant Feature Transform)
- 拷贝mp3java_字节流复制mp3文件(带缓冲区)
- boost::fusion::replace_if用法的测试程序
- 深入C++的new(2011-11-15 15:08 )
- SQUEEZENET: ALEXNET-LEVEL ACCURACY WITH 50X FEWER PARAMETERS AND 0.5MB MODEL SIZE
- Inno Setup入门(三)——指定压缩方式
- ArcMap下停靠栏的设计与实现
- 手机如何测光照度_手机摄影技法宝典1.2:准确测光让照片曝光准确
- js 流文件下载zip压缩包
- 国家高新技术企业认定要求及快速通过的方法
- windows插耳机没声音?
- Suit and Tie (在线swap 贪心 思维)
- 分享一次险象迭生的系统迁移【真实案例】
- HDFS基础知识(个人总结)
- Android自学之路,DrawerLayout must be measured with MeasureSpec.EXACTLY.错误
- 关于 Web 可访问性的神话
- 用什么样的方法可以快速计算机,怎么让电脑加速50%_教你一招快速给电脑提速的方法...
- 一种限流算法-令牌桶算法
- 【Python基础】生成.pkl文件,读取.pkl文件的内容
- 探索一下PyScript的妙用
热门文章
- P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks论文笔记
- 【华为OJ】【067-求最小公倍数】
- java转go之初体验(一)
- Kubernetes调度器源码学习(三):Preempt抢占机制、调度失败与重试处理
- 关于dva的put,put.resolve
- 中海达ihand30手簿详细教程_中海达iHand30 手簿使用说明书
- 如何高效的进行版本管理,版本管理的方法
- 【愚公系列】2022年12月 .NET CORE工具案例-多语言离线翻译系统
- Docker系列 搭建个人云盘服务nextcloud
- 小红书koc和kol区别是什么?品牌方如何选择