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. 参考资料

  1. Pydicom User Guide
  2. 【医学影像】窗宽窗位与其处理方法

使用pydicom实现Dicom文件读取与CT图像窗宽窗位调整相关推荐

  1. python nii 图像读取,转换成CT 值,设置窗宽窗位,保存成png 图像

    import numpy as np import os # 遍历文件夹 import nibabel as nib # nii格式一般都会用到这个包 import imageio # 转换成图像ce ...

  2. CT图像之Hu值变换与窗宽窗位调整

    今天通过分析实验结果,完善了之前的预处理代码,借此博文分享给大家,另外 点击此处可以查看预处理的完整代码,欢迎大家一起来完善. 最重要的是,欢迎大家的批评指正,您的建议和意见将会是我成长源泉. 接下来 ...

  3. matlab设置固定的窗宽窗位,python实现CT窗宽窗位的调整(即指定HU值保存图像)...

    最近一直在做实验,所以好久没有更新了,先把上周做的一些小的实验贴出来供大家分享. 在医生诊断时,是会将CT图像调整成不同的窗来处理的.比如说肺部CT吧,肺窗(窗宽为2000,窗位为-400)用于看小的 ...

  4. CT图像中的窗宽和窗位

    通常我们称CT图像为DICOM(Digital Imaging and Communications in Medicine)图像,但是DICOM不是一个图像或者文件格式,它是包含了传输.存储.检索. ...

  5. CT值以及窗宽窗位(未完待续)

    1 常见人体组织的CT值(HU) 常见人体组织的CT值(HU)组织 CT值 组织 CT值骨组织 >400 肝脏 50-70 钙值 80-300 脾脏 35-60 血块 64-84 胰腺 30-5 ...

  6. DICOM文件读取及PNG格式图片展示

    import globimport pydicom import matplotlib.pyplot as plt import numpy as np import os import multip ...

  7. matlab设置固定的窗宽窗位,【经验谈】如何设定窗宽窗位,附正常人体组织CT值...

    让学习成为一种习惯! 医学影像服务中心拥有500病例征象+讲座 一般CT机可显示的CT值范围为-1000-+1000共2000个密度等级,而人的肉眼仅能识别16个灰阶,若把2000个CT值分成16个灰 ...

  8. CT图像分割dicom文件与nii.gz文件预处理----窗宽(window width)和窗位(window level)的设置

    最近被CT图像的值弄得很烦,记录一下. CT分割也是个很热门的话题,病灶分割,器官分割等. CT图像大多是两种格式.dcm和nii.gz,当然也有别的,但这里我就不说别的,就说这两种常用的. .dcm ...

  9. Deeplung:深度学习项目笔记(二)——医学影像学dicom,mhd及raw文件读取与可视化

    目录 医学影像学 dicom文件相关 1.1 什么是dicom图像 1.2 dicom图像中有什么 1.3 dicom结构及组成 1.3.1 文件头 1.3.2 数据集 raw文件相关 mhd文件相关 ...

最新文章

  1. OpenCV中的尺度不变特征变换(SIFT Scale-Invariant Feature Transform)
  2. 拷贝mp3java_字节流复制mp3文件(带缓冲区)
  3. boost::fusion::replace_if用法的测试程序
  4. 深入C++的new(2011-11-15 15:08 )
  5. SQUEEZENET: ALEXNET-LEVEL ACCURACY WITH 50X FEWER PARAMETERS AND 0.5MB MODEL SIZE
  6. Inno Setup入门(三)——指定压缩方式
  7. ArcMap下停靠栏的设计与实现
  8. 手机如何测光照度_手机摄影技法宝典1.2:准确测光让照片曝光准确
  9. js 流文件下载zip压缩包
  10. 国家高新技术企业认定要求及快速通过的方法
  11. windows插耳机没声音?
  12. Suit and Tie (在线swap 贪心 思维)
  13. 分享一次险象迭生的系统迁移【真实案例】
  14. HDFS基础知识(个人总结)
  15. Android自学之路,DrawerLayout must be measured with MeasureSpec.EXACTLY.错误
  16. 关于 Web 可访问性的神话
  17. 用什么样的方法可以快速计算机,怎么让电脑加速50%_教你一招快速给电脑提速的方法...
  18. 一种限流算法-令牌桶算法
  19. 【Python基础】生成.pkl文件,读取.pkl文件的内容
  20. 探索一下PyScript的妙用

热门文章

  1. P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks论文笔记
  2. 【华为OJ】【067-求最小公倍数】
  3. java转go之初体验(一)
  4. Kubernetes调度器源码学习(三):Preempt抢占机制、调度失败与重试处理
  5. 关于dva的put,put.resolve
  6. 中海达ihand30手簿详细教程_中海达iHand30 手簿使用说明书
  7. 如何高效的进行版本管理,版本管理的方法
  8. 【愚公系列】2022年12月 .NET CORE工具案例-多语言离线翻译系统
  9. Docker系列 搭建个人云盘服务nextcloud
  10. 小红书koc和kol区别是什么?品牌方如何选择