Dicom格式文件解析器
dicom读取方法

Dicom格式文件解析器学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题只讲*.dcm 也就是diocm格式文件的读取,读取本身是没啥难度的无非就是字节码流处理。
只不过确实比较繁琐。
分析整体结构先是128字节所谓的导言部分,说俗点就是没啥意义的破数据跳过就是了,然后是dataElement依次排列的方式就是一个dataElement接一个dataElement的方式排到文件结尾通俗的讲dataElement就是指tag 就是破Dicom标准里定义的数据字典。
tag是4个字节表示的前两字节是组号后两字节是偏移号比如0008,0018。
所有dataElement在文件中都是按tag排序的比如0002,0001? 0002,0002? 0003,0011文件整体结构如下:又把论文里的这图贴上来总结的很好。
单个dataElement的结构如下:显示VR:VR为OB?OW?OF?UT?SQ?UN的元素结构显示VR:VR为普通类型时元素结构(少了预留那一行)隐式VR?时元素结构?要问VR是啥东东,值表示法啥叫值表示法啊俺不懂 int string short ushort 懂不就是这个意思,Dicom标准真坑爹非要整个怪怪的概念。
VR总共27个跟c#值类型对应关系我都写好了:1string getVF(string VR, byte[] VF)2 {3string VFStr = ;4switch (VR)5 {6case"SS":7 VFStr = (VF, 0).ToString();8break;9case"US":10 VFStr = (VF, 0).ToString();1112break;13case"SL":14 VFStr = (VF, 0).ToString();1516break;17case"UL":18 VFStr = (VF, 0).ToString();1920break;21case"AT":22 VFStr = (VF, 0).ToString();2324break;25case"FL":26 VFStr = (VF, 0).ToString();2728break;29case"FD":30 VFStr = (VF, 0).ToString();3132break;33case"OB":34 VFStr = (VF, 0);35break;36case"OW":37 VFStr = (VF, 0);38break;39case"SQ":40 VFStr = (VF, 0);41break;42case"OF":43 VFStr = (VF, 0);44break;45case"UT":46 VFStr = (VF, 0);47break;48case"UN":49 VFStr = break;51default:52 VFStr = break;54 }55return VFStr;56 }找个dicom文件在十六进制编辑器下瞧瞧给你整明白:所有dataElement从前到后按tag又可简单分段:几个特殊的tag很重要前面说过了tag就是dicom里定义的字典。
DICOM的名词解释

DICOM的名词解释DICOM(Digital Imaging and Communications in Medicine)即医学数字成像和通信,是一种用于医学图像和相关信息的国际标准。
DICOM被广泛应用于医学影像设备、医疗信息系统和图像处理软件等领域。
本文将介绍DICOM标准中一些常用的名词和概念。
1. DICOM图像DICOM图像是医学成像设备生成的二维或三维图像,如CT扫描、X射线片、核磁共振图像等。
DICOM图像文件通常以.dcm为扩展名,并包含了图像本身的像素数据以及与图像相关的患者信息、设备信息等。
DICOM图像具有跨平台、互操作性强的特点,可以在不同的医疗设备和软件中进行传输、显示和分析。
2. DICOM文件格式DICOM文件格式定义了图像和相关信息在存储和传输中的组织方式。
DICOM文件由一系列的数据元素(Data Element)组成,每个数据元素包含了一个标签、一个值和一些描述信息。
标签用于唯一标识每个数据元素,而值则存储了具体的信息。
DICOM文件采用二进制格式存储,可以通过解析文件头部的元数据来获取图像本身的像素数据。
3. DICOM标准DICOM标准由美国医学影像与生物工程学会(ACR-NEMA)和国际电工委员会(IEC)共同制定,旨在促进医学图像设备和信息系统之间的互操作性。
DICOM 标准规定了医学图像的格式、传输协议、数据元素的定义等内容,确保了不同厂商的设备和软件能够正确读取和解析DICOM图像。
DICOM标准的持续更新和演进,使其成为了医学影像行业的重要基础。
4. DICOM服务DICOM服务定义了医学影像设备和信息系统之间的通信方式和协议。
常见的DICOM服务包括图像查询检索服务(C-FIND)、图像存储服务(C-STORE)、图像传输服务(C-MOVE)等。
这些服务通过网络协议(如TCP/IP)实现,允许不同设备之间的图像传输、共享和查询。
DICOM服务的实现,使得医学影像数据能够在不同地点和时间进行远程交流和访问。
pydicom和SimpleITK分别解析医学影像中dicom文件

pydicom和SimpleITK分别解析医学影像中dicom⽂件⾸先,⽆论是pydicom还是SimpleITK都是需要事先导⼊到python中的库,如果使⽤的是pycharm IDE,可以先创建python3的虚拟环境,然后在虚拟环境下通过file-setting-Project interpreter ,在添加模块⾥⾯直接搜上述两个库的名称,点击安装即可。
pydicom提取单张dicom图像1import pydicom2from matplotlib import pyplot34 ds = pydicom.read_file('C:/Users/****/Desktop/CT000000.dcm')# DICOM⽂件的位置5print(ds.dir()) # 打印所有 DICOM TAG 名6print(ds.dir('Pixe')) # 打印包含 'pat' 的 DICOM TAG7print(ds.PatientName, ds.PatientSex, ds.PatientID, ds.PatientBirthDate, ds.PatientAge) # 打印 DICOM TAG 相应的属性值8print(ds.data_element('PatientName')) # 打印⼀个完整的数据元素,包括 DICOMTAG编码值(Group, Element), VR, Value9print(ds.data_element('PatientID').VR, ds.data_element('PatientID').value)10 pixel_bytes = ds.PixelData # 原始⼆进制⽂件1112 pix = ds.pixel_array # 像素值矩阵13print(pix.shape) # 打印矩阵维度14 pyplot.imshow(pix, cmap=pylab.cm.bone)15 pyplot.show() # cmap 表⽰ colormap,可以是设置成不同值获得不同显⽰效果,打印dicom图⽚注意,此时可能会报错,报错的地⽅是ds.pixel_array,原因是某些格式的dicom⽂件不能⽤pydicom提取,。
DICOM医学影像文件格式解析

DICOM医学影像⽂件格式解析DICOM医学影像⽂件格式解析dicom协议中⽂⽂档可去csdn下载1.DICOMDICOM(DigitalImaging andCommunications inMedicine)是指医疗数字影像传输协定,是⽤于医学影像处理、储存、打印、传输的⼀组通⽤的标准协定。
它包含了⽂件格式的定义以及⽹络通信协议。
DICOM是以TCP/IP为基础的应⽤协定,并以TCP/IP联系各个系统。
两个能接受DICOM格式的医疗仪器间,可通过DICOM格式的⽂件,来接收与交换影像及病⼈资料。
⽬前,DICOM被⼴泛应⽤于放射医疗,⼼⾎管成像以及放射诊疗诊断设备(X射线,CT,核磁共振,超声等),并且在眼科和⽛科等其它医学领域得到越来越深⼊⼴泛的应⽤。
⽬前采⽤的标准是DICOM3.0,每⼀张图像中都携带着⼤量的信息,这些信息具体可以分为以下四类:(a)Patient(b)Study(c)Series(d)Image每⼀个DICOM Tag都是由两个⼗六进制数的组合来确定的,分别为Group和Element。
如(0010,0010)这个Tag表⽰的是Patient’s Name,它存储着这张DICOM图像的患者姓名。
2.DICOM存储格式DICOM⽂件的整体结构如下表所⽰,先是128字节的导⾔部分(没有实际信息),接着是四个字节组成的"DICM"字符串,然后是若⼲DataElement元素依次排列直⾄⽂件结束。
导⾔"DICM"DataElement DataElement...DataElement128 Byte 4 Byte n Byte n Byte n Byte2.1 DataElement的三种结构DataElement是存储⽂件信息的主体,DataElement的总体结构如下表所⽰:Tag VR(值表⽰法)Len(数据长度)数据值(内容)4 Byte 2 Byte 2 Byte Len ByteTag由2 Byte的组号(group)和2 Byte的元素号(element)组成,VR是DICOM特有的值表⽰法,关于值表⽰法的解释见下⽂按照VR的类型以及是否显⽰VR,DataElement⼜分为三种具体的结构。
DICOM图像文件解析及程序设计

DICOM图像文件解析及程序设计魏军;刘荣鑫;宋国兴;李金屏【期刊名称】《济南大学学报(自然科学版)》【年(卷),期】2007(021)003【摘要】分析DICOM标准,建立解析DICOM文件的模型,研究DICOM文件解析及其图像显示的方法.以DICOM3.0标准为对象,提出将DICOM文件划分为概念模型、数据模型、物理模型3个层面;以概念模型、数据模型为指导进行解析程序的设计,将物理模型与程序设计相结合进行解析程序的编程实现;利用线性/非线性两种算法对文件中的医学图像进行显示以及窗宽/窗位的调整.测试结果表明,该DICOM 文件解析程序能够完整解析DICOM3.0标准文件,显示医学图像并支持窗宽/窗位的调整.通过对标准的分析编程实现了DICOM3.0医学图像文件的解析、显示和调整.【总页数】4页(P215-218)【作者】魏军;刘荣鑫;宋国兴;李金屏【作者单位】济南大学控制科学与工程学院山东济南 250022;北京航空航天大学机器人所北京 100083;济南大学信息科学与工程学院山东济南 250022;济南大学信息科学与工程学院山东济南 250022;济南大学信息科学与工程学院山东济南 250022【正文语种】中文【中图分类】TP242.3【相关文献】1.DICOM格式医学图像及其图像信息的显示 [J], 高升;葛云2.DICOM标准医学图像文件解析及工具软件的研制 [J], 邱明辉;刘海一3.DICOM全方向M型心动图系统DICOM图像解析方法研究 [J], 许剑锋;黄立勤;林强4.DICOM文件解析及其消息传输 [J], 张元鲁;王超5.DICOM数据集研究和DICOM图像处理软件的实现 [J], 伍亚军;周正东;戴耀东因版权原因,仅展示原文概要,查看原文内容请购买。
dcm文件怎么打开?dcm文件用什么软件可以打开?

dcm文件怎么打开?dcm文件用什么软件可
以打开?
dcm文件用什么软件可以打开?dcm文件被广泛应用于医疗行业,支持心电图、核磁共振图、超声心动图等等,如果你没有安装特定的打开dcm的软件是无法打开dcm文件的。
那么要使用哪一款软件打开dcm文件呢?其实医学DICOM图像浏览器软件就可以打开。
具体步骤:
1、在本站下载医学DICOM图像浏览器,得到安装包。
2、我们找到下载好的软件安装程序,然后双击安装。
3、接下来的这一步是安装的路径,这里默认是安装在c盘,直接下一步。
4、接下来提示已做好安装程序的准备,也就是我们前期的设置都完成了,直接就可以安装了。
5、接下来就是正在安装这个软件,中间有个进度条会显示安装的进度。
6、进度条走完之后,就直接会提示软件已经安装完成,也就是软件已经安装成功了,那么我们选择完成按钮结束此次的安装过程。
7、然后我们打开刚才安装好的软件,就进入了软件的界面。
8、接下来我们就来试着打开下我们的dcm文件,点击菜单栏的文件选项,选择打开文件,也可以直接选择打开文件的图标。
9、选择打开文件之后,就会弹出选择dcm文件的窗口,这里找
到我们想要打开的dcm文件所在的位置,找到文件然后选择打开即可。
DICOM图像文件解析及程序设计

济南大学学报 (自然科学版 ) JOURNAL OF UN IVERSITY OF J INAN ( Sci. & Tech1)
文章编号 : 1671 - 3559 (2007) 03 - 0215 - 04
D ICOM 图像文件解析及程序设计
Vol. 21 No. 3 Jul. 2007
当概念模型的数据元素映射到数据模型的数据 元素时 , 数据元素的结构即为数据结构 , 它在 D I2 COM 标准中是唯一的 ,结构如图 3。
Tag代表标识 ,其组标识和元素标识唯一确定 一个数据元素 ; VR (Value Rep resentation)代表值表 示法 [5] , 其内容指明值域中值的数据类型 , 例如 “PN ”为姓名类型 ,“AS”为年龄类型 ,“DA ”为日期
(2)值长度可变的显式 VR的元素结构 对于其它 VR 值 , Length域是跟在两个字符长 的 VR 域后的 16位无符号整数 ,即 VR 域与 Length 域各占 16位 。对值域中的内容进行解析时应将 VR 与 Length相结合 。 (3)隐式 VR 的元素结构 当使用不含 VR 域的结构时 ,数据元素由 3 个 连续域构成 : Tag, Length和 ValueField。如果值域有 一个明确长度 ,那么值长度字段应包含相当于值域 长度的值 。 3. 2 数据集 数据集是由与信息对象相关的数据元素集合组 成的交换信息集 。数据集中的每一个属性值都由数 据元素进行表示 。每个元素在数据集中紧密相连 。 由递增数据元素标识 ( Tag)安排的数据元素的集合 是现实世界对象属性值的编码 。数据集结构如图 4 所示 。
针对icom文件数据模型以及物理模型的分析都是围绕着数据元素而展开的模块为了简化信息对象的定义icom标准将每一个复合化信息对象的数据元素与集合中相似的元素分开并将这些数据元素的分组指定为独立的模块信息实体从数据元素划分出独立的模块后可根据同样的性质划分方式将有相似之处的模块组织为信息实体不同的实体可共享相同的模块
DICOM医学图像文件格式解析与信息提取

() 3 完成特殊的工作( 如在胶片上打印图像) ;
() 4 工作流程的管理( 支持 WO K IT和状态 R LS 信息 ) ; () 5 可视图像的质量和一致性 。
简而 言 之 , I O 标 准 是 基 于 内 容 的 医学 图 DC M
ZHo Fe g U n
【bt c】 T ippr rf e r e t IO t dr,n yio t IO l f m tte s o E D As f h DC M f r a, e f A — s il cb e a d l s e i o e h u L
M d i )是美 国放射学会 和美 国电器制造商协会 ein , ce 组织制定的专 门用于医学 图像存储和传输的标准 。 经过十多年的发展 , 该标 准已经被 医疗设备生产商 和医疗界广泛接受 , 为医学 图像信息学领域的国 成
际通 用标 准 。
信息对象可以完成五个方面的功能 : () 1传输和存储完整 的对象 ( 如图像 、 波形和文
据元素一 一对应。它 由组号 和元素 号构成 , 如 例 (0 802 ) 0 0 ,0 0就是组号为 0 00 , x0 8元素号为 OO 2 x 00 的“ 检查 日期” 数据元素 的 T g a 号。D C M 的数据 IO 字典定义 了许多数据元素标记 , 涵盖 了大多数 的应
用需 要 。组号 为偶 数 的 是标 准 数 据元 素 , 体 含 义 具 在 DIOM 的数 据 字 典 中定 义 ; 号 为 奇 数 的为 私 C 组
・
有数据元素 , 由用户在使用过程中定义。
3 ・ 2
第 1 卷・ 5 1 第 期
周峰 : I O 医学 图像文件格式解析与信息提取 DC M
dicom读取方法资料

Dicom格式文件解析器学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题只讲*.dcm 也就是diocm格式文件的读取,读取本身是没啥难度的无非就是字节码数据流处理。
只不过确实比较繁琐。
分析整体结构先是128字节所谓的导言部分,说俗点就是没啥意义的破数据跳过就是了,然后是dataElement依次排列的方式就是一个dataElement接一个dataElement的方式排到文件结尾通俗的讲dataElement就是指tag 就是破Dicom标准里定义的数据字典。
tag是4个字节表示的前两字节是组号后两字节是偏移号比如0008,0018。
所有dataElement在文件中都是按tag排序的比如0002,0001? 0002,0002? 0003,0011文件整体结构如下:又把论文里的这图贴上来总结的很好。
单个dataElement的结构如下:显示VR:VR为OB?OW?OF?UT?SQ?UN的元素结构显示VR:VR为普通类型时元素结构(少了预留那一行)隐式VR?时元素结构要问VR是啥东东,值表示法啥叫值表示法啊俺不懂 int string short ushort 懂不就是这个意思,Dicom标准真坑爹非要整个怪怪的概念。
VR总共27个跟c#值类型对应关系我都写好了:1string getVF(string VR, byte[] VF)2 {3string VFStr = string.Empty;4switch (VR)5 {6case"SS":7 VFStr = BitConverter.ToInt16(VF, 0).ToString();8break;9case"US":10 VFStr = BitConverter.ToUInt16(VF, 0).ToString();1112break;13case"SL":14 VFStr = BitConverter.ToInt32(VF, 0).ToString();1516break;17case"UL":18 VFStr = BitConverter.ToUInt32(VF, 0).ToString();1920break;21case"AT":22 VFStr = BitConverter.ToUInt16(VF, 0).ToString();2324break;25case"FL":26 VFStr = BitConverter.ToSingle(VF, 0).ToString();2728break;29case"FD":30 VFStr = BitConverter.ToDouble(VF, 0).ToString();3132break;33case"OB":34 VFStr = BitConverter.ToString(VF, 0); 35break;36case"OW":37 VFStr = BitConverter.ToString(VF, 0); 38break;39case"SQ":40 VFStr = BitConverter.ToString(VF, 0); 41break;42case"OF":43 VFStr = BitConverter.ToString(VF, 0); 44break;45case"UT":46 VFStr = BitConverter.ToString(VF, 0); 47break;48case"UN":49 VFStr =50break;51default:52 VFStr =53break;54 }55return VFStr;56 }找个dicom文件在十六进制编辑器下瞧瞧给你整明白:所有dataElement从前到后按tag又可简单分段:几个特殊的tag很重要前面说过了tag就是dicom里定义的字典。
DICOM医学影像文件的解析

DICOM医学影像文件的解析作者:龚自霞,成江晨来源:《电脑知识与技术》2011年第28期摘要:通过示例对DICOM医学图像文件的格式进行比较详细的解析,阐述了文件头和数据元素的格式,为设计一个能读取和显示医学影像设备中的DICOM格式图像的工具软件打好基础,同时也为进一步针对医学影像处理应用的研究和开发提供了数据准备。
关键词:DICOM标准;医学图像文件;解析中图分类号:TP391文献标识码:A文章编号:1009-3044(2011)28-6899-02File Format Analysis of DICOM Medical ImageGONG Zi-xia, CHENG Jiang-chen(Bichemical Engineering College of Beijing Union University, Beijing 100023, China)Abstract: Byanalyzingthe file format of DICOMimage file through an example, describingtheformat of the information header and data element of DICOM file, laying the foundation of designing the image tools that can read and display DICOM medical image equipment, and also providing the data preparationfor further processing applications of medical imaging research and development.Key words: DICOM standard; medical image file; analysisDICOM是Digital Imaging and Communication of Medicine的缩写,是美国放射学会和美国电器制造商协会[1]组织制定的专门用于医学图像的存储和传输的标准名称,目前用的主要是DICOM3.0版本,该标准已经被医疗设备生产商和医疗界广泛接受,在医疗仪器中得到普及和应用,同时随着图像化、计算机化的医疗设备的普及和医院管理信息系统,特别是图像存档和通信系统(Pieture Archiving and Communication System,PACS)[2]和远程医疗系统的发展,该标准得到越来越多的应用。
DICOM文件头信息读取及解析

DICOM文件头信息读取及解析尤超【摘要】DICOM as a medical image storage and transmission standard, covers the medical digital image collection, archiving, communication, display and query almost all information exchange protocol, and structured defines medical image equipment manufacturer compatibility statement. In this paper, through the analysis of DICOM file structure, to parse the DICOM file header of the composition and content, the realization of the DICOM file header information is read, and using the obtained inforraiison to read the DICOM file in the data set stored content. This method is to read the DICOM file basic analytic process, this paper reads DICOM file from the program developers integrated platform in the isolated, in combination with the image display program as an independent DICOM file to read the procedures used.%DICOM作为医学图像存储和传输的标准,涵盖了医学数字图像的采集、归档、通信、显示及查询等几乎所有信息交换的协议,并且结构化地定义了医疗图像设备制造厂商的兼容性申明.通过分析DICOM文件的构成,解析DICOM文件头的组成和内容,实现对DICOM 文件头的信息读取,并利用所获得的信息,进一步读取DICOM文件中的数据集存储内容,是读取DICOM文件的基本解析过程,可以将对DICOM文件的读取,从程序开发商的集成平台中分离出来,在结合图像显示程序之后,作为独立的DICOM文件读取程序使用.【期刊名称】《微型电脑应用》【年(卷),期】2012(028)009【总页数】4页(P39-41,44)【关键词】DICOM;DICOM文件;DICOM文件头【作者】尤超【作者单位】上海交通大学,上海,200030【正文语种】中文【中图分类】TP3110 引言DICOM是美国放射学会和美国电器制造商协会组织制定的,专门用于医学图像的存储和传输的标准,它涵盖了医学数字图像的采集、归档、通信、显示及查询等几乎所有信息交换的协议,结构化地定义了医疗图像设备制造厂商的兼容性声明。
dcm2x说明书

dcm2x说明书DCM2X是一种数据格式转换工具,用于将医学影像数据从DICOM格式转换为其他常见的图片格式,如JPEG、PNG或BMP等。
本说明书将详细介绍DCM2X的功能、使用方法和相关注意事项,以帮助用户正确使用该工具。
一、功能介绍:1.DICOM格式转换:DCM2X能够将DICOM格式的医学影像数据转换为其他常见的图片格式,实现不同系统间的数据互通和共享。
2.多种输出格式:DCM2X支持将DICOM数据导出为JPEG、PNG、BMP等多种图片格式,以适应不同用户需求。
3.批量处理:用户可一次性选择和转换多个DICOM影像数据,提高工作效率。
二、使用方法:2.导入DICOM数据:在DCM2X的界面中,用户需要点击"导入"按钮或选择"文件"菜单中的"导入"选项,然后浏览并选择需要转换的DICOM文件所在的文件夹。
用户也可以直接将DICOM文件拖拽到DCM2X界面中进行导入。
3.选择输出格式:在DICOM数据导入成功后,用户需要点击"输出设置"按钮或选择"文件"菜单中的"输出设置"选项,然后选择需要的输出格式(如JPEG、PNG或BMP)。
4.设置输出路径:用户需要点击"输出设置"按钮或选择"文件"菜单中的"输出设置"选项,然后选择保存转换后文件的路径。
用户也可以保留默认路径,将转换后的文件保存在与源DICOM文件相同的路径下。
5.开始转换:在设置输出格式和输出路径后,用户只需点击"开始转换"按钮或选择"文件"菜单中的"开始转换"选项,即可开始转换DICOM文件为指定的图片格式。
转换过程中,用户可以看到转换进度和转换速度。
6.完成转换:当转换完成后,用户将在指定的输出路径或默认路径中找到转换后的图片文件。
Java实现解析dcm医学影像文件并提取文件信息的方法示例

Java实现解析dcm医学影像⽂件并提取⽂件信息的⽅法⽰例本⽂实例讲述了Java实现解析dcm医学影像⽂件并提取⽂件信息的⽅法。
分享给⼤家供⼤家参考,具体如下:⼀、安装⾸先去下载源码,然后执⾏mvn install进⾏本地安装,Maven中央仓库,竟然没有该jar。
安装成功之后如下:然后在POM.XML⽂件中引⼊该jar包:<dependency><groupId>org.dcm4che</groupId><artifactId>dcm4che-core</artifactId><version>3.3.2</version></dependency>⼆、测试类/*** projectName: xxx* fileName: DisplayTag.java* packageName: mon.util* date: 2018-03-26 10:07* copyright(c) 2017-2020 xxx公司*/package mon.util;import java.awt.image.Raster;import java.io.File;import java.io.IOException;import java.sql.Time;import java.util.Arrays;import java.util.Date;import java.util.logging.Level;import java.util.logging.Logger;import org.dcm4che3.data.Attributes;import org.dcm4che3.data.ElementDictionary;import org.dcm4che3.data.Fragments;import org.dcm4che3.data.Sequence;import org.dcm4che3.data.Tag;import org.dcm4che3.data.VR;import org.dcm4che3.io.DicomEncodingOptions;import org.dcm4che3.io.DicomInputStream;import org.dcm4che3.io.DicomOutputStream;import org.dcm4che3.util.SafeClose;import java.awt.image.Raster;import java.io.IOException;import java.util.Arrays;/*** @version: V1.0* @author: fendo* @className: DisplayTag* @packageName: mon.util* @description: Tag解析* @data: 2018-03-26 10:07**/public final class DisplayTag {private static Attributes obj=null, object =null;private static DicomInputStream din;private static double resultFactorDix;private String result = null;private Double result2 = null;private String nom = null;private String nounString = null;private int val2 = 0;private int valeurReturn;private String nounUnit = null;private static double resultFacteurDix = 0;private Double valueSpatial = null;private String nounUnitRatio = null;private DicomInputStream dis;private static final char[] HEX_DIGITS = {'0' , '1' , '2' , '3' , '4' , '5' ,'6' , '7' , '8' , '9' , 'A' , 'B' ,'C' , 'D' , 'E' , 'F'};private DicomEncodingOptions encOpts = DicomEncodingOptions.DEFAULT;private static ElementDictionary dict = ElementDictionary.getStandardElementDictionary();public DisplayTag(File file ){try {setObject(loadDicomObject(file) );} catch (IOException ex) {Logger.getLogger(DisplayTag.class.getName()).log(Level.SEVERE, null, ex);}}/*** Read metadata of Dicom 3.0* @param f : input file* @return Attributes* @throws IOException*/public static Attributes loadDicomObject(File f) throws IOException {if (f == null){return null;}else{DicomInputStream dis = new DicomInputStream(f);//attr.setSpecificCharacterSet("GBK");return dis.readDataset(-1, -1);}}/*** Put attribut* @param obj*/public void setObject(Attributes obj){this.obj = obj;}/*** Giving attribut of metadata* @return*/public static Attributes getObject(){return obj;}/*** Display metadata* @param file : file inout* @throws IOException*/public String readTagDicom(File file) throws IOException{din = new DicomInputStream(file);object = din.readFileMetaInformation() ;String value = object.toString();object = din.readDataset(-1, -1);return value;}/*** Permet d'afficher l'heure d'une valeur dicom en standard international yyyy.mm.dd/ Permit display time in format yyyy.mm.dd* @param Tag : valeur du tag / int tag* @param valueBool : si true Format yyyy.mm.dd sinon format dd.mm.yyyy/ if true then format yyyy.mm.dd else dd.mm.yyyy* @param valueNoun : "dot" mettre la date en format yyyy.mm.dd ou dd.mm.yyyy sinon en format yyyy mm dd ou dd mm yyyy/ "dot" put yyyy.mm.dd or dd.mm.dd or dd.mm.yyyy else yyyy mm or dd mm yyyy * @return afficher le string du tag selon le standard international/ return string Date* @throws IOException*/public String dicomDate(int Tag,boolean valueBool, String valueNoun) throws IOException{if(getObject().contains(Tag)==true ){String tagValue = getObject().getString(Tag);String tagDayFomat = FormatDate(tagValue,valueBool,valueNoun);return tagDayFomat;}else{return null;}}/*** Permet d'afficher l'heure d'une valeur dicom en standard international yyyy.mm.dd/ Permit display a time in metadata for yyyy.mm.dd* @param object* @param Tag : valeur du tag/ value of tag* @param valueBool : si true Format yyyy.mm.dd sinon format dd.mm.yyyy/ if true format yyyy.mm.dd else dd.mm.yyyy* @param valueNoun : "dot" mettre la date en format yyyy.mm.dd ou dd.mm.yyyy sinon en format yyyy mm dd ou dd mm yyyy/dot" put yyyy.mm.dd or dd.mm.dd or dd.mm.yyyy else yyyy mm or dd mm yyyy * @return afficher le string du tag selon le standard international/ return string date* @throws IOException*/public static String dicomDate(Attributes object , int Tag,boolean valueBool, String valueNoun) throws IOException{String tagValue = object.getString(Tag);String tagDayFomat = FormatDate(tagValue,valueBool,valueNoun);return tagDayFomat;}/*** Format tag* @param Numero : String date* @param valueBool : if true Format yyyy.mm.dd else format dd.mm.yyyy* @param valueNoun : "dot" put the date in format yyyy.mm.dd or dd.mm.yyyy else in format yyyy mm dd or dd mm yyyy* @return*/public static String FormatDate(String Numero, boolean valueBool,String valueNoun) {if (Numero.matches("^[0-9]*$")) {//If la chaine de caractère est un nombre ou un chiffreStringBuffer r = new StringBuffer();if (valueBool ==true){//Format yyyy.mm.ddfor (int i = 0, j = Numero.length(); i < j; i++) {r.append(Numero.charAt(i));if ((i == 3)||(i == 5) ){if(valueNoun == null ? "dot" == null : valueNoun.equals("dot")){r.append('.');}else{r.append(' ');}}}return r.toString();}else{for (int i = 6, j =8; i<j; i++) {//joursr.append(Numero.charAt(i));if(i ==7 ){if(valueNoun == null ? "dot" == null : valueNoun.equals("dot")){r.append('.');}else{r.append(' ');}}}for (int i = 4, j =6; i<j; i++) {r.append(Numero.charAt(i));//The first char value of the sequence is at index zero, the next at index one, and so on, as for array indexing.if(i ==5 ){if(valueNoun == null ? "dot" == null : valueNoun.equals("dot")){r.append('.');}else{r.append(' ');}}}for (int i = 0, j =4; i<j; i++) {r.append(Numero.charAt(i));//The first char value of the sequence is at index zero, the next at index one, and so on, as for array indexing.}return r.toString();}}return Numero;}/*** Read value tag of VR = DA** If use setDicomObject(readDicomObject(File f)), and getHeaderDateValue(getDicomObject()) * @param tagNr "0000,0010"* @return*/public Date getHeaderDateValue(String tagNr) {return getHeaderDateValue(toTagInt(tagNr));}/*** Read value tag of VR = DA** @param tagNr see dcm4che2* @return*/public Date getHeaderDateValue(int tagNr) {return getObject().getDate(tagNr);}/*** Converts the string representation of a header number* e.g. 0008,0010 to the corresponding integer as 0x00080010****************************.data.Tag* @param headerNr e.g. 0008,0010* @return 0x00080010 as int*/public static int toTagInt(String headerNr){return Integer.parseInt(headerNr.replaceAll(",", ""), 16);}/*** Read value tag of VR = DA* @param tagNr* @param dicomObj* @return*/public Date getHeaderDateValue(int tagNr,Attributes dicomObj) {return dicomObj.getDate(tagNr);}/*** Read value tag of VR = DA* @param tagNr :"0000,0010"* @param dicomObj* @return*/public Date getHeaderDateValue(String tagNr,Attributes dicomObj) {return getHeaderDateValue(toTagInt(tagNr), dicomObj);}/*** Remove string ^ in file dicom* @param num* @return*/public static String texteDicom(String num) {num = num.replaceAll("\\^+", " ");return num;}/*** Convertor tag to String* Using VM !=1* example result [25, 25]* @param Tag* @return*/public static String getStringTag(Attributes object, int Tag){String tagValue2[] = object.getStrings(Tag);//Conversion table in List to StringString tagValue = Arrays.asList(tagValue2).toString();return tagValue;}/*** Convertor tag to String* Using VM !=1* example result 25/25* @param object* @param Tag* @return*/public static String getStringTag2(Attributes object, int Tag){String tagValue2[] = object.getStrings(Tag);//Conversion table in List to StringString tagValue =DisplayTag.arrayToString(tagValue2,"\\");return tagValue;}/*** Convert an array of strings to one string* Put the 'separator' string between each element* @param a* @param separator* @return*/public static String arrayToString(String[] a, String separator){StringBuffer result = new StringBuffer();if(a.length>0) {result.append(a[0]);for(int i=1;i<a.length;i++){result.append(separator);result.append(a[i]);}}return result.toString();}/*** Permit display time in hh.mm.ss* (0008,0030) AT S Study Time* (0008,0031) AT S Series Time* (0008,0032) AT S Acquisition Time* (0008,0033) AT S Image Time* @param Tag : giving tag* @return* @throws IOException*/public String dicomTime(int Tag) throws IOException{if(getObject().contains(Tag)==true ){String tagValue = getObject().getString(Tag);String tagValueNotDot = formatNotDot(tagValue);String tagTimeFomat = FormatTimes(tagValueNotDot);return tagTimeFomat;} else {return null;}}/*** Permit display time in hh.mm.ss.fac* (0008,0030) AT S Study Time* (0008,0031) AT S Series Time* (0008,0032) AT S Acquisition Time* (0008,0033) AT S Image Time* @param Tag : giving tag* @return* @throws IOException*/public String dicomTimeTotal( int Tag) throws IOException{if(getObject().contains(Tag)==true ){String tagValue = getObject().getString(Tag);String tagTimeFomat = FormatTimes(tagValue);return tagTimeFomat;} else {return null;}}/*** Permit display time in hh.mm.ss* (0008,0030) AT S Study Time* (0008,0031) AT S Series Time* (0008,0032) AT S Acquisition Time* (0008,0033) AT S Image Time* @param object : Metadata* @param Tag : value dicom* @return new value String* @throws IOException*/public String dicomTime2(Attributes object, int Tag) throws IOException{String tagValue = object.getString(Tag);String tagValueNotDot = formatNotDot(tagValue);System.out.println(FormatTime(tagValueNotDot));String tagTimeFomat = FormatTimes(tagValueNotDot);return tagTimeFomat;}/*** Permit display time in hh.mm.ss.frac* (0008,0030) AT S Study Time* (0008,0031) AT S Series Time* (0008,0032) AT S Acquisition Time* (0008,0033) AT S Image Time* @param object : Metadata* @param Tag : value dicom* @return new value String* @throws IOException*/public String dicomTime3(Attributes object, int Tag) throws IOException{String tagValue = object.getString(Tag);String tagTimeFomat = FormatTimes(tagValue);return tagTimeFomat;}/*** reads a int value from the Dicomheader* @param tagNr the Tag to read* @return the value as int*/public int getHeaderIntegerValue(int tagNr) {return getObject().getInt(tagNr,0);}/**** @param tagNr e.g. "0018,0050" to get Slice Thickness<br>* or "0008,0102#0054,0220" to get the Coding Scheme Designator after View Code Sequence * @return int*/public int getHeaderIntegerValue(String tagNr) {return getHeaderIntegerValue(toTagInt(tagNr));}/*** checks if the Header contains the given tag* @param tagNr* @return*/public boolean containsHeaderTag(String tagNr) {return containsHeaderTag(toTagInt(tagNr));}/*** checks if the Header contains the given tag* @param tagNr* @return*/public boolean containsHeaderTag(int tagNr) {return getObject().contains(tagNr);}/*** returns the name of the given Tag* @param tagNr* @return*/public static String getHeaderName(int tagNr) {return dict.keywordOf(tagNr);/*** returns the name of the given Header field* @param tagNr* @return the name of the Field e.g. Patients Name*/public String getHeaderName(String tagNr) {try {return getHeaderName(toTagInt(tagNr));} catch (Exception e) {return "";}}/*** returns the String representation of the given header field * if it exists in the header* @param tagNr* @return*/public String getHeader(int tagNr) {try {String dcmele = getObject().getString(tagNr);return toElementString(dcmele, tagNr);} catch (Exception e) {return "";}}private static String toElementString(String dcmele,int tag) { StringBuffer sb = new StringBuffer();int TAG[] = getObject().tags();StringBuffer append = sb.append(TAG).append(" [").append(getObject().getVR(tag)).append("] ") .append(object.tags()).append(": ").append(dcmele);return sb.toString();}/*** checks wether the header is empty or not* @return*/public boolean isEmpty() {if (getObject() == null || getObject().isEmpty()) {return true;}return false;}/*** Converts the string representation of a header number* e.g. 0008,0010 to the corresponding integer as 0x00080010 ****************************.data.Tag* @param headerNr e.g. 0008,0010* @return 0x00080010 as int*/public static int toTagInt2(String headerNr){return Integer.parseInt(headerNr.replaceAll(",", ""), 16);}/*** Removing comma in String* @param num* @return*/public static String formatNotDot(String num) {num = num.trim().replaceAll("[^0-9\\+]", "");if (num.matches("^0*$")){num = "";}return num;}/*** Format* hh.mm.ss* @param Numero* @return*/public static String FormatTime(String Numero) {if (Numero.matches("^[0-9]*$")) {StringBuilder r = new StringBuilder();for (int i = 0, j = 6; i < j; i++) {r.append(Numero.charAt(i));if ((i % 2 == 1) && (i < (j - 1))){r.append(':');}}return r.toString();}return Numero;}/*** Format* hh.mm.ss.frac* @param Numero* @return*/public static String FormatTimes(String Numero) {if (Numero.matches("^[0-9].*$")) {StringBuilder r = new StringBuilder();for (int i = 0,j=Numero.length();i<j; i++) {r.append(Numero.charAt(i));if ((i % 2 == 1)&(i<5)){r.append(':');}}return r.toString();}return Numero;}* Round double after dot* @param a : value convertor* @param n number of decade* @return new value*/public double floor(double a, int n){double p =Math.pow(10.0,n);return Math.floor((a*p)+0.5)/p;}/*** Giving power* Example:* setFactorPower(10,2)//10^2* @param result3* @param factor* @return* @return*/public static double setFactorPower(double result3, double factor){return resultFactorDix= Math.pow(result3, factor);}/*** Giving getFactorPower*/public static double getFactorPower(){return resultFactorDix;}/*** Giving pixelData* @param dcmObj* @return*/public static int[] lattricePixelData(Attributes dcmObj){int[] data = dcmObj.getInts(Tag.PixelData);return data;}/*** Giving pixel data* @return* @throws IOException*/public int[] lattricePixelData2() throws IOException{int[] data = getObject().getInts(Tag.PixelData);return data;}/*** Giving pixel data* @param dcmObj* @return* @throws IOException*/public byte[] lattricePixelDataBytes(Attributes dcmObj) throws IOException{ byte[] data = dcmObj.getBytes(Tag.PixelData);return data;}/*** Giving pixel data* @return* @throws IOException*/public byte[] lattricePixelDataBytes2() throws IOException{byte[] data = getObject().getBytes(Tag.PixelData);return data;}/*** Extraction PixelData* @param raster of dicom* @return*/private int[][] extractData(Raster raster) {int w = raster.getWidth();int h = raster.getHeight();System.out.printf("w = %d h = %d%n", w, h);//WritableRaster raster = (WritableRaster) getMyImage();int[][] data = new int[h][w];for (int y = 0; y < h; y++) {for (int x = 0; x < w; x++) {data[y][x] =raster.getSample(x, y, 0);}}return data;}/*** Extraction PixelData* @return*/private int[] getPixelData(int[][] data2){int h = data2.length;int w = data2[0].length;int[] array = new int[h*w];for(int y = 0; y < h; y++) {for(int x = 0; x < w; x++) {int index = y*w + x;array[index] = data2[y][x];//ligne}}return array;}/*** Return value table input* @param object* @param PATIENT_ADDITIONAL_TAGS : Table int** example :* public static final int[] tag = {0x00080020,0x00080022,};**FileInputStream fis = new FileInputStream(fileInput);*DicomInputStream dis = new DicomInputStream(fis);*DicomObject obj = dis.readDicomObject();*String nounValue[] =getValue(obj,tag);** @return*/private static String[] getValue(Attributes object, int[] PATIENT_ADDITIONAL_TAGS){ String [] value = new String [PATIENT_ADDITIONAL_TAGS.length];int i =0;while (i<PATIENT_ADDITIONAL_TAGS.length){for (int tag : PATIENT_ADDITIONAL_TAGS) {value[i]=object.getString(tag);i++;}//System.out.print(value[0]+"\n");//System.out.print(value[1]);}return value;}/*** Reading VR = SQ** @param inputFile : File* @param tag : VR =SQ* @return*/public String[] readItem (File inputFile, int tag){DisplayTag dcm = new DisplayTag(inputFile);Sequence seq= dcm.getObject().getSequence(tag);String valueString[] = new String[seq.size()];for (int i = 0; i<seq.size(); i++){Attributes attr = seq.get(i);valueString[i] = attr.toString();}return valueString;}/*** Value inside VR = SQ* @param inputFile : input File* @param tagSQ : tag VR = SQ* @param tag : Tag inside VR= SQ* @return*/public String tagItem(File inputFile, int tagSQ, int tag){String valueString = null;DisplayTag dcm = new DisplayTag(inputFile);Sequence seq= dcm.getObject().getSequence(tagSQ);Attributes attr = seq.get(0);valueString = attr.getString(tag);return valueString;}/*** Les unités spécifiques selon les tags pour vr= SQ/ Unity specical for tags VR= SQ * @param TAG :* - RegionSpatialFormat* - RegionDataType* - PhysicalUnitsXDirection* - PhysicalUnitsXDirection* - PixelComponentPhysicalUnits**** @param result : value string*/public void unit(int TAG, String result){if (TAG == Tag.RegionSpatialFormat ){val2= Integer.valueOf(result).intValue();//convertie en intswitch(val2){case 5:setNounUnit("Graphics");break;case 4:setNounUnit("Wave form(physiological traces, doppler traces,...");break;case 3:setNounUnit("Spectral(CW or PW Doppler");break;case 2:this.setNounUnit("M-Mode(tissue or flow)");break;case 1:this.setNounUnit("2D(tissue or flow");break;case 0:setNounUnit("None or not applicable");break;default:break;}}else if (TAG == Tag.RegionDataType ){val2= Integer.valueOf(result).intValue();//convertie en intswitch(val2){case 12:setNounUnit("Orther Physiological(Amplitude vs. Time)");break;case 11:setNounUnit("d(area)/dt");break;case 10:setNounUnit("Area Trace");break;case 9:setNounUnit("d(Volume)/dt Trace");break;case 8:setNounUnit("Volume Trace");break;case 7:setNounUnit("Doppler Max Trace");break;case 6:this.setNounUnit("Doppler Mode Trace");break;case 5:this.setNounUnit("Doppler Mean Trace");break;case 4:setNounUnit("CW Spectral Doppler");break;case 3:this.setNounUnit("PW Spectral Doppler");break;case 2:this.setNounUnit("Color Flow");break;case 1:this.setNounUnit("Tissue");break;case 0:this.setNounUnit("None or not applicable");break;default:break;}switch (result) {case "A":this.setNounUnit("ECG Trace");break;case "B":this.setNounUnit("Pulse Trace");break;case "C":this.setNounUnit("Phonocardiogram Trace");break;case "D":this.setNounUnit("Gray bar");break;case "E":this.setNounUnit("Color bar");break;case "F":this.setNounUnit("Integrated Backscatter");break;default:return;}}elseif (TAG == Tag.PhysicalUnitsXDirection || TAG == Tag.PhysicalUnitsXDirection || TAG == Tag.PixelComponentPhysicalUnits){ val2= Integer.valueOf(result).intValue();//convertie en intswitch(val2){case 9:setNounUnit("cm*cm.pixel/sec");break;case 8:setNounUnit("cm*cm/pixel");break;case 7:setNounUnit("cm*pixel/sec");break;case 6:this.setNounUnit("dB*pixel/seconds");break;case 5:this.setNounUnit("hertz/pixel");break;case 4:setNounUnit("seconds/pixel");break;case 3:this.setNounUnit("cm/pixel");break;case 2:this.setNounUnit("dB/pixel");break;case 1:this.setNounUnit("percent/pixel");break;case 0:this.setNounUnit("None or not applicable");break;default:break;}switch (result) {case "A":this.setNounUnit("cm*cm*cm/pixel");break;case "B":this.setNounUnit("cm*cm*cm*pixel/sec");break;case "C":this.setNounUnit("degrees");break;}}else if (TAG == Tag.PixelComponentDataType ){val2= Integer.valueOf(result).intValue();//convertie en intswitch(val2){case 9:setNounUnit("Computed Border");break;case 8:setNounUnit("Integrated Backscatter");break;case 7:setNounUnit("Color bar");break;case 6:this.setNounUnit("Gray bar");break;case 5:this.setNounUnit("Color Flow Intensity");break;case 4:setNounUnit("Color Flow Variance");break;case 3:this.setNounUnit("Color Flow Velocity");break;case 2:this.setNounUnit("Spectral doppler");break;case 1:this.setNounUnit("Tissue");break;case 0:this.setNounUnit("None or not applicable");break;default:break;}if("A".equals(result)){this.setNounUnit("Tissue Classification");}}else {this.setNounUnit("None or not applicable");}}/*** Enregistre l'unité des items/ Put unity of items* @param nounUnit* @return this.nounUnit = nounUnit*/public String setNounUnit(String nounUnit){return this.nounUnit = nounUnit;}/*** On obtient l'unité des items./Giving unity of items* @return le nom de l'unité*/public String getNounUnit(){return nounUnit;}/*** Special Ratio Spatial toutes les unites sont en mm/ Giving tag ratio Spatial of mm* @param TAG : entree choisi* - PhysicalUnitsXDirection* - PhysicalUnitsYDirection* -PixelComponentPhysicalUnits** @param result: prend l'unite*/public void unitRatioSpatial(int TAG, String result){if (TAG == Tag.PhysicalUnitsXDirection || TAG == Tag.PhysicalUnitsYDirection || TAG == Tag.PixelComponentPhysicalUnits){ val2= Integer.valueOf(result).intValue();//convertie en intswitch(val2){case 9:Double valueSpatial1 = getValeurTagItemDoubleRatio()* setFacteurPuissance(10,1);setTagItemDoubleRatio(valueSpatial1);//prend la valeursetNounUnitRatio("mm*mm.pixel/sec");break;case 8:Double valueSpatial2 = getValeurTagItemDoubleRatio()* setFacteurPuissance(10,1);setTagItemDoubleRatio(valueSpatial2);//prend la valeursetNounUnitRatio("mm*mm/pixel");break;case 7:setNounUnitRatio("mm*pixel/sec");break;case 6:this.setNounUnitRatio("dB*pixel/seconds");break;case 5:this.setNounUnitRatio("hertz/pixel");break;case 4:setNounUnitRatio("seconds/pixel");break;case 3:this.setNounUnitRatio("mm/pixel");break;case 2:this.setNounUnitRatio("dB/pixel");break;case 1:this.setNounUnitRatio("percent/pixel");break;case 0:this.setNounUnitRatio("None or not applicable");break;default:break;}switch (result) {case "A":Double valueSpatial3 = getValeurTagItemDoubleRatio()* setFacteurPuissance(10,2);setTagItemDoubleRatio(valueSpatial3);//prend la valeurthis.setNounUnitRatio("mm*mm*mm/pixel");break;case "B":Double valueSpatial4 = getValeurTagItemDoubleRatio()* setFacteurPuissance(10,2);setTagItemDoubleRatio(valueSpatial4);//prend la valeurthis.setNounUnit("mm*mm*mm*pixel/sec");break;case "C":this.setNounUnit("degrees");break;}}}/*** Prend la valeur d'un Ratio Spatial/Put value Ratio Spatial* @param valueSpatial* @return*/public Double setTagItemDoubleRatio(double valueSpatial){return this.valueSpatial = valueSpatial;}/*** Donne la valeur du Ratio/Diving value ratio Spatial* @return*/public Double getValeurTagItemDoubleRatio(){return valueSpatial;}/*** Donne les valeurs calculer des puissances/ Put and computing power* @param result3* @param facteur* @return* @return*/public static double setFacteurPuissance(double result3, double facteur){return resultFacteurDix = Math.pow(result3, facteur);}/*** Obtient la valeur de puissance/ Giving value power* @return*/public static double getFacteurPuissance(){return resultFacteurDix;}/*** Enregistre l'unite des items /Put unity unity items* @return this.nounUnit = nounUnit*/public String setNounUnitRatio(String nounUnitRatio){return this.nounUnitRatio = nounUnitRatio;}/*** On obtient l'unite des items./Giving unity items* @return le nom de l'unité*/public String getNounUnitRatio(){return nounUnitRatio;}/*** Prend la valeur interne d'un tag Item/ Put tag Item* @param result* @return*/public String setTagItem(String result){return this.result = result;}/*** Donne la valeur du tag rechercher/Giving a value of tag seek* @return le String de la valeur rechercher du tag dans un item*/public String getValeurTagItem(){return result;}/*** Prend la valeur interne d'un tag Item/ Put the value tag iteù* @return*/public Double setTagItemDouble(double result2){return this.result2 = result2;}/*** Donne la valeur du tag rechercher/Giving the value Tag* @return le Double de la valeur rechercher du tag dans un item*/public Double getValeurTagItemDouble(){return result2;}/*** reads a String value from tag dicom (dcm4che2)* @param tagNr the Tag to read* @return the value as String* Returns the Specific Character Set defined by Attribute Specific Character Set (0008,0005) * of this or the root Data Set, if this is a Nested Data Set containing in a Sequence Eleme */public String getHeaderStringValue(int tagNr) {try {。
DICOM医学图像文件格式解析与应用研究综述

DICOM医学图像文件格式解析与应用研究综述摘要:由于生产医学影像设备的国内外厂商众多,其产品遵守DICOM3.0标准的程度也各不相同,而DICOM3.0是一个不断扩充和扩展的标准,因此,在进行医学影像处理应一用开发时,一般只能针对特定厂商的设备进行数据采集和处理,不大可能开发出一个能读取和显示所有医学影像设备中的DICOM格式图像的工具软件,除非国内外所有生产医学影像设备的制造商都严格遵守DICOM3.0标准的规定。
论文主要探讨了DICOM3.0标准的产生经过及DICOM医学图像文件格式的大致组成。
通过对DICOM图像文件的剖析,基本解决了医学影像应用开发的数据接31问题,为进一步针对医学影像处理应用的研究和开发提供了数据准备。
关键词:DICOM3.0标准PACS系统医学图像文件格式The Overview of research on the File format Analysis and Application of DICOMDanni Huang (school of Tianjin Medical University,07class 2,NO.2007093107)Abstract:Becouse threre are many the production of domestic and foreign manufacturers of medical imaging equipment companies,their products for adherence to standards of the degree DICOM3.0 are different. but DICOM3.0 is expanding and the expansion of a standard. the article is mainly to discusses the generation after DICOM3.0 standard DICOM medical image file format and the general composition. Through analysis of DICOM image files, basically solved the medical imaging application development, data access 31 problem, for further processing applications for medical imaging research and development provides the data preparation.Keywords: DICOM3.0 standardization;PACS system;format of Medical image file一.引言从20世纪90年代初开始,随着计算机技术、通信技术以及网络技术的发展,图像分析和处理以及PACS(PictureArchivingandCommunicationSystem)在临床诊断、远程医疗以及医学教学中发挥着越来越重要的作用。
DICOM标准医学图像文件解析及工具软件的研制

D I CO M 标准医学图像文件解析及工具软件的研制邱明辉1刘海一2摘要 目的:研制一个计算机软件工具,解析符合医学数字成像与通讯(D i g ita l I m ag i ng and Co mm un ica tions i n M ed i c i ne ,D I COM )标准的图像文件。
材料和方法:详细分析基于D ICOM 标准的医学图像文件格式和数据元素结构,在W i n do w s 环境下采用面向对象的设计方法,并用面向对象的程序设计语言VC ++6.0设计解析软件。
结果:本软件能够解析所有D ICO M 格式文件(D I COM 图像文件、D ICOM S R 文件、D ICOM D IR 文件)以及N E MA 格式文件。
结论:借助本解析软件工具,可以帮助PACS 用户迅速了解医学影像设备和PA CS 厂商的图像文件具体内容以便顺利实施PACS 系统。
关键词 D I COM;医学图像;解析;软件工具中图图书资料分类法分类号 TP 315A Soft ware Tool for t he Analysis ofM edical I m age F iles Confor m ed to DI COM StandardQIUM ing hu i ,LIU H ai y i(Co mputer D e p art m ent of PLA G enera lH osp ital ,B eijing 100853)Abstract Purpose :A co m pute r soft w are too l was deve loped for parsi ng m ed i ca l i m ag e fil es confor m ed to the D ICOM (D i g ital I m ag i ng and Comm unicati ons i n M ed ici ne)standard .M ater i als and M ethods :A so ft w are t oo l for ana l yz i ng t he forma t and t he data e l em ent !s struc t u re of medica l i m age fil e based on D I COM standa rd w as desi gned us i ng Ob ject O r i ented progra mm i ng language V i sua lC ++i nW i ndow s env i ron m en t .Resu lts :The so ft ware too lwas able to parse allD ICOM files i nclud i ng i m age files ,D I COM S R (Structured R epo rti ng)files ,D I COM D I R (D ICO M D irectory)files and N E MA files(prev i ous m edical i m age file for m at).Con clusi on :T he parsi ng too l could help PACS use rs in understand i ng i m age file !s ele m ents o fm edical i m ag i ng dev i ce and PA CS and w as useful i n putti ng PACS i nto practice s uccessfull y .K ey word s D ICOM;m ed i ca l i m age ;ana l ysis ;so ft w are tool作者单位 1.100853 北京 解放军总医院计算机室 2.100730 北京 协和医院信息中心D I COM (D i g ital I m aging and Co mm unications i n M ed ici n e)是一种规定数字医学影像和相关信息的格式及其信息交换方法的国际标准。
DICOM影像工作站介绍

DICOM影像工作站介绍DICOM影像工作站,全称为医学数字成像和通信(Digital Imaging and Communications in Medicine,简称DICOM)影像工作站,是医学影像诊断的重要辅助工具。
它是利用DICOM标准协议对医学影像进行浏览、分析和处理的软件系统。
DICOM影像工作站能够实现对患者的多种检查影像进行集成管理,并提供多种功能,方便医生进行详细的诊断和评估。
DICOM影像工作站的最主要功能是影像的浏览和查看。
DICOM格式是医学图像的国际标准,DICOM影像工作站能够读取和解析DICOM格式的图像文件,并将其显示在一台计算机屏幕上。
医生可以通过DICOM影像工作站以自己所需的方式浏览和查看影像,包括放大、缩小、旋转和翻转等。
此外,DICOM影像工作站还能够提供多种窗位窗宽、标定线和测量工具等功能,以便医生对影像进行进一步的分析和处理。
除了基本的浏览和查看功能,DICOM影像工作站还具有一些高级功能,如图像比较、图像融合和图像处理。
通过将不同时间点或不同模态的影像进行比较,医生可以更加准确地判断病情的发展和疾病的变化。
图像融合功能可以将不同的影像叠加在一起,形成一个多模态的影像,进一步提供更全面的信息。
此外,DICOM影像工作站还提供了一些图像处理的功能,如滤波、增强和去噪等,以便医生对影像进行优化和改进。
除了以上功能,DICOM影像工作站还具有数据存储和共享的功能。
DICOM影像工作站可以将医学影像的相关数据进行存储和管理,包括患者信息、检查信息和影像文件等。
通过DICOM网页和网络传输,医生可以方便地将影像和相关的数据共享给其他医生和科室。
这样不仅方便了医生之间的交流和合作,还提高了医学影像的利用效率和准确性。
最后,在实际的医学影像工作中,DICOM影像工作站还可以与其他医疗信息系统进行集成。
通过与病历系统的集成,DICOM影像工作站可以方便地查看和比较患者的影像和病历资料,提供更准确和全面的诊断建议。
dicom读取方法-资料

Dicom格式文件解析器学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题只讲*.dcm 也就是diocm格式文件的读取,读取本身是没啥难度的无非就是字节码数据流处理。
只不过确实比较繁琐。
分析整体结构先是128字节所谓的导言部分,说俗点就是没啥意义的破数据跳过就是了,然后是dataElement依次排列的方式就是一个dataElement接一个dataElement的方式排到文件结尾通俗的讲dataElement就是指tag 就是破Dicom标准里定义的数据字典。
tag是4个字节表示的前两字节是组号后两字节是偏移号比如0008,0018。
所有dataElement在文件中都是按tag排序的比如0002,0001 0002,0002 0003,0011文件整体结构如下:又把论文里的这图贴上来总结的很好。
单个dataElement的结构如下:显示VR:VR为OB OW OF UT SQ UN的元素结构显示VR:VR为普通类型时元素结构(少了预留那一行)隐式VR 时元素结构要问VR是啥东东,值表示法啥叫值表示法啊俺不懂 int string short ushort 懂不就是这个意思,Dicom标准真坑爹非要整个怪怪的概念。
VR总共27个跟c#值类型对应关系我都写好了:1string getVF(string VR, byte[] VF)2 {3string VFStr = string.Empty;4switch (VR)5 {6case"SS":7 VFStr = BitConverter.ToInt16(VF, 0).ToString();8break;9case"US":10 VFStr = BitConverter.ToUInt16(VF, 0).ToString();1112break;13case"SL":14 VFStr = BitConverter.ToInt32(VF, 0).ToString();1516break;17case"UL":18 VFStr = BitConverter.ToUInt32(VF, 0).ToString();1920break;21case"AT":22 VFStr = BitConverter.ToUInt16(VF, 0).ToString();2324break;25case"FL":26 VFStr = BitConverter.ToSingle(VF, 0).ToString();2728break;29case"FD":30 VFStr = BitConverter.ToDouble(VF, 0).ToString();3132break;33case"OB":34 VFStr = BitConverter.ToString(VF, 0); 35break;36case"OW":37 VFStr = BitConverter.ToString(VF, 0); 38break;39case"SQ":40 VFStr = BitConverter.ToString(VF, 0); 41break;42case"OF":43 VFStr = BitConverter.ToString(VF, 0); 44break;45case"UT":46 VFStr = BitConverter.ToString(VF, 0); 47break;48case"UN":49 VFStr = Encoding.Default.GetString(VF); 50break;51default:52 VFStr = Encoding.Default.GetString(VF); 53break;54 }55return VFStr;56 }找个dicom文件在十六进制编辑器下瞧瞧给你整明白:所有dataElement从前到后按tag又可简单分段:几个特殊的tag很重要前面说过了tag就是dicom里定义的字典。
放射科常用影像学软件的操作与分析

放射科常用影像学软件的操作与分析在放射科学领域,影像学软件是医生们进行诊断和分析的重要工具。
通过这些软件,医生可以对医学影像进行处理、分析和解读,从而提供准确的诊断结果。
本文将介绍几种常用的放射科影像学软件,并详细说明其操作步骤与分析方法。
一、DICOM影像格式与PACS系统1. DICOM影像格式DICOM(Digital Imaging and Communications in Medicine)是医学图像领域中最常见的文件格式,具有跨平台、可扩展和数据完整性等特点。
DICOM文件可包含各种医学图像,如CT扫描、MRI和X射线等。
2. PACS系统PACS(Picture Archiving and Communication System)是一种集成了DICOM影像及相关信息的医学图像存档和传输系统。
通过PACS系统,医生可以方便地查看和管理患者的医学图像,提高工作效率和诊断准确性。
二、常用影像学软件1. OsiriXOsiriX是一款免费的医学影像软件,被广泛应用于放射学、心脏学和神经学等领域。
它支持多种影像格式,如DICOM、JPEG和PDF等,并提供强大的图像处理和分析功能。
2. MIMviewerMIMviewer是一款功能强大的医学影像软件,主要用于医学图像的处理、分析和导航。
它支持各种影像学模态,如PET、SPECT和CT 等,并具有体积测量、肿瘤分析和配准等高级功能。
3. Syngo.viaSyngo.via是西门子医疗公司开发的一款高级医学影像软件。
它提供了丰富的图像处理选项和先进的自动化工具,可用于辅助医生快速准确地诊断各类疾病。
三、影像学软件的操作步骤1. 导入影像数据首先,打开相应的影像学软件,在菜单栏中选择“导入”或“打开”选项,在弹出的文件浏览器中选择要导入的DICOM文件夹或单个DICOM文件。
软件将自动解析并显示影像数据。
2. 调整图像参数根据需要,可以对图像进行亮度和对比度的调整,以优化图像显示效果。
dicom读取方法-资料

Dicom格式文件解析器学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题只讲*.dcm 也就是diocm格式文件的读取,读取本身是没啥难度的无非就是字节码数据流处理。
只不过确实比较繁琐。
分析整体结构先是128字节所谓的导言部分,说俗点就是没啥意义的破数据跳过就是了,然后是dataElement依次排列的方式就是一个dataElement接一个dataElement的方式排到文件结尾通俗的讲dataElement就是指tag 就是破Dicom标准里定义的数据字典。
tag是4个字节表示的前两字节是组号后两字节是偏移号比如0008,0018。
所有dataElement在文件中都是按tag排序的比如0002,0001 0002,0002 0003,0011文件整体结构如下:又把论文里的这图贴上来总结的很好。
单个dataElement的结构如下:显示VR:VR为OB OW OF UT SQ UN的元素结构显示VR:VR为普通类型时元素结构(少了预留那一行)隐式VR 时元素结构要问VR是啥东东,值表示法啥叫值表示法啊俺不懂 int string short ushort 懂不就是这个意思,Dicom标准真坑爹非要整个怪怪的概念。
VR总共27个跟c#值类型对应关系我都写好了:1string getVF(string VR, byte[] VF)2 {3string VFStr = string.Empty;4switch (VR)5 {6case"SS":7 VFStr = BitConverter.ToInt16(VF, 0).ToString();8break;9case"US":10 VFStr = BitConverter.ToUInt16(VF, 0).ToString(); 1112break;13case"SL":14 VFStr = BitConverter.ToInt32(VF, 0).ToString();1516break;17case"UL":18 VFStr = BitConverter.ToUInt32(VF, 0).ToString(); 1920break;21case"AT":22 VFStr = BitConverter.ToUInt16(VF, 0).ToString(); 2324break;25case"FL":26 VFStr = BitConverter.ToSingle(VF, 0).ToString(); 2728break;29case"FD":30 VFStr = BitConverter.ToDouble(VF, 0).ToString(); 3132break;33case"OB":34 VFStr = BitConverter.ToString(VF, 0);35break;36case"OW":37 VFStr = BitConverter.ToString(VF, 0);38break;39case"SQ":40 VFStr = BitConverter.ToString(VF, 0); 41break;42case"OF":43 VFStr = BitConverter.ToString(VF, 0); 44break;45case"UT":46 VFStr = BitConverter.ToString(VF, 0); 47break;48case"UN":49 VFStr = Encoding.Default.GetString(VF); 50break;51default:52 VFStr = Encoding.Default.GetString(VF); 53break;54 }55return VFStr;56 }找个dicom文件在十六进制编辑器下瞧瞧给你整明白:所有dataElement从前到后按tag又可简单分段:几个特殊的tag很重要前面说过了tag就是dicom里定义的字典。
DICOM文件头信息读取及解析

摘 要 :DIOM 作 为医学图像 存储和传输的标准 ,涵盖 了医学数字图像的采集、归档、通信、显示及查询等 几乎所有信息 C
交换 的协 议 , 并且 结构 化 地 定 义 了医 疗 图像 设 备 制 造 厂 商 的 兼 容性 申 明 。通 过 分 析 D C I OM 文件 的构 成 ,解 析 DI O 文 件 C M 头 的 组 成 和 内容 ,实 现 对 DI OM 文件 头 的信 息读 取 ,并 利 用 所 获得 的信 息 ,进 一 步 读 取 DI O 文 件 中的 数据 集存 储 内 容 , C C M 是 读 取 DI O 文件 的基 本解 析 过 程 ,可 以将 对 DI OM 文件 的读 取 ,从 程 序 开 发 商 的 集 成 平 台 中分 离 出来 ,在 结 合 图像 显 C M C 示程 序 之 后 ,作 为 独 立 的 DI O 文件 读 取 程 序 使 用 。 C M 关键 字 :DI M ;DI 0 文 件 ;D C M 文件 头 CO C M I0 中 图 分类 号 :T 3 1 P l 文 献 标 志 码 :A
f c u e o ai i t tt me t I h sp p r t r u h t e a ay i fDI a t r rc mp t l y s e n . n t i a e , h o g h n l sso COM l t cu e t a s e DI bi a i f e s u t r , o p re t COM l e d ro e r h i f e h a e f h t
A bsr t t ac :DI COM sa m e i a m a tr g d ta m ison sa da d o r he m e c ld g tli a e c l ci n,a c vi , a d c li ge so a e an r ns s i t n r ,c ve s t dia i ia m g ole to r hi ng c om m u c ton iply a uey l os l i f m ai n e h ng r oc l a tu t r d d in sm e c li a qu p e tm a — nia i ,d s a nd q r am ta l n or to xc a e p ot o , nd sr c u e ef e dia m gee i m n nn
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Dicom格式文件解析器学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题只讲*.dcm也就是diocm格式文件的读取,读取本身是没啥难度的无非就是字节码数据流处理。
只不过确实比较繁琐。
分析又把论文里的这图贴上来总结的很好。
单个dataElement的结构如下:隐式VR?时元素结构要问VR是啥东东,值表示法啥叫值表示法啊俺不懂intstringshortushort懂不就是这个意思,Dicom标准真坑爹非要整个怪怪的概念。
VR总共27个跟c#值类型对应关系我都写好了:1string getVF(string VR,byte[]VF)2{345{6case78break9case10111213case14151617case18192021case22232425case262728break;29case"FD":30VFStr=BitConverter.ToDouble(VF,0).ToString();3132break;33case"OB":34VFStr=BitConverter.ToString(VF,0);35break;36case"OW":37VFStr=BitConverter.ToString(VF,0);38break;39case"SQ":40VFStr=BitConverter.ToString(VF,0);41break;42case"OF":43VFStr=BitConverter.ToString(VF,0);44break;45case"UT":46VFStr=BitConverter.ToString(VF,0);4748case495051525354}5556}找个所有dataElement从前到后按tag又可简单分段:几个特殊的tag很重要前面说过了tag就是dicom里定义的字典。
文件元dataElement和跟像素数据相关的dataElement都很重要,其他的很多如果全部照顾完的话估计得写上千行switch语句来确定关键的12{34{5case67break8case91011case121314case151617case181920case21return"SQ";22break;23case"0008,1111":24return"SQ";25break;26case"0008,0020"://检查日期27return"DA";28break;29case"0008,0060"://成像仪器32case"0008,0070"://成像仪厂商33return"LO";34break;35case"0008,0080":36return"LO";37break;38case"0010,0010"://病人姓名39return"PN";4041case424344case454647case484950case515253case545556case575859case606162case636465case"0020,0013"://影像编号66return"IS";67break;68case"0028,0002"://像素采样1为灰度3为彩色69return"US";70break;71case"0028,0004"://图像模式MONOCHROME2为灰度72return"CS";73break;74case"0028,0010"://row高77case"0028,0011"://col宽78return"US";79break;80case"0028,0100"://单个采样数据长度81return"US";82break;83case"0028,0101"://实际长度84return"US";8586case878889case909192case939495case969798case99100101102103104105106107108109110case"7fe0,0010"://像素数据开始处111return"OW";112break;113default:114return"UN";115break;116}117}最关键的两个tag:0002,0010普通tag的读取方式little字节序还是big字节序?隐式VR还是显示VR。
由它的值决定1switch(VFStr)2{3case://显示little4isLitteEndian=true;5isExplicitVR=true;6break;7case:891011case121314151617}整理第一步第二步并根据0002,就确定两个东西而已1字节序这个基本上都是little字节序。
举个例子吧十进制数35280用十六进制表示是0xff00?但是存储到文件中你用十六进制编辑器打开你看到的是这个样子00ff这就是little字节序。
平常我们用的x86PC在window s下都是little字节序包括AMD的CPU。
别太较真较真的话这个问题又可以写篇博客了。
2确定从0002以后的dataElement的VR是显示还是隐式。
说来说去0002,0010的值就那么固定几个并且只能是那么几个这些都在那个北美放射学会定义的dicom标准的第六章有说明:上面的那段代码其实就是这个表格的实现,讲到这里你会觉得多么的坑爹啊是的dicom面向对象的破概念非常烦的。
第三步:读取普通tag直到搜寻到7fe0,0010这个最巨体的存储图像数据的dataElement它一个顶别人几十个上百个。
我们在前一步已经把VR是显示还是隐式确定通过前面的图,也就是字节码在这种号称16位的+1000,空即把1000密度1000一句话,从2047个等级的灰度里选取一个范围放到0~255的灰度环境里显示。
怎样把12位灰度影射到8位灰度显示出来呢,还怎么显示上面方法都给说明了基本上算半成品了。
联想到角度制弧度制,设要求的8位灰度值为x已知的12位灰度值为y那么:x/255=y/2047那么x=255y/2047原理不多讲等比中项十字相乘法这个是初中的知识哈。
初中没读过的童鞋飘过。
原理过程讲完了代码走起1class DicomHandler2{3string fileName="";4Dictionary<string,string>tags=new Dictionary<string,string>();//dicom文件中的标签5BinaryReaderdicomFile;//dicom文件流67//文件元信息/////////////8910long1112long13bool14bool1516//17int1819int2021{22if23242526//271282829if(30{31MessageBox.Show("没有dicom标识头,文件格式错误");32return;33}343536tagRead();3738IDictionaryEnumeratorenor=tags.GetEnumerator();39while(enor.MoveNext())40{41if9)42{43"\r\n";44'\0','');45}46else47'\0','')+"\r\n";48}49dicomFile.Close();50}5152{5354}555657{5859{60case616263case646566case6768697071}72}7374{75if(fileName==string.Empty)76returnfalse;7778int dataLen,validLen;//数据长度有效位79int imgNum;//帧数8081rows=int.Parse(tags["0028,0010"].Substring(5)); 82cols=int.Parse(tags["0028,0011"].Substring(5)); 8384colors=int.Parse(tags["0028,0002"].Substring(5));85dataLen=int.Parse(tags["0028,0100"].Substring(5));86validLen=int.Parse(tags["0028,0101"].Substring(5));8788gdiImg=new Bitmap(cols,rows);8990BinaryReaderdicomFile=new BinaryReader(File.OpenRead(fileName)); 91929394long reads=0;95for(96{97for(98{99if100101102103104105if106{107int108109110//111//1112int113int114115if116117118119120{121grayGDI=(int)((gray-grayStart)*255/windowWith);122}123124if(grayGDI>255)125grayGDI=255;126elseif(grayGDI<0)127grayGDI=0;128c=Color.FromArgb(grayGDI,grayGDI,grayGDI);129}130elseif(colors==3)131{132c=Color.FromArgb(pixData[0],pixData[1],pixData[2]);133}134135gdiImg.SetPixel(j,i,c);136}137}138139dicomFile.Close();140141}142143{144145int146147148149{150//151152153154155156//157//158一步被阻159if160{161VR=162163if164{1652,SeekOrigin.Current);166Len=dicomFile.ReadUInt32();167}168else169Len=dicomFile.ReadUInt16();170}171elseif(tag=="fffe,e000"||tag=="fffe,e00d"||tag=="fffe,e0dd")//文件夹标签172{173VR="**";174Len=dicomFile.ReadUInt32();175}176elseif(isExplicitVR==true)//有无VR的情况177{178VR=newstring(dicomFile.ReadChars(2));179180if(VR=="OB"||VR=="OW"||VR=="SQ"||VR=="OF"||VR=="UT"||VR=="UN")181{1822,SeekOrigin.Current);183Len=dicomFile.ReadUInt32();184}185186187}188189{190191192}193//194一步被195196197if198{199200201202VR=203204}205)//206{207if(enDir==false)208{209enDir=true;210folderData.Remove(0,folderData.Length);211folderTag=tag;212}213else214{215leve++;//VF不赋值216}217}218elseif((tag=="fffe,e00d"&&Len==UInt32.MinValue)||(tag=="fffe,e0dd"&&Len==UInt32.M inValue))//文件夹结束标签219{220if(enDir==true)221{222enDir=false;223}224else225{226227}228}229230231232233234235236tag237//238if239{240241242}243244{245246{247248249250break;251case://显示big252isLitteEndian=false;253isExplicitVR=true;254break;255case://隐式little256isLitteEndian=true;257isExplicitVR=false;258break;259default:260break;261}262}263for(int i=1;i<=leve;i++)264tag="--"+tag;265//------------------------------------数据搜集代码266if((VR=="SQ"&&Len==UInt32.MaxValue)||(tag=="fffe,e000"&&Len==UInt32.MaxValue)||le ve>0)//文件夹标签代码267{268folderData.AppendLine(tag+"("+VR+"):"+VFStr);269}270271{272273274}275276277}278}279}1if2345678910this.Text="DicomViewer-"+openFileDialog1.FileName;111213backgroundWorker1.RunWorkerAsync();这里处理gdi位图的时候直接用的setPix处理速度比较慢所以用了backgroundWorker,实际应用中请使用内存缓冲跟指针的方式否则效率低了是得不到客户的认可的哦,gdi位图操作可使用lockBits加指针的方式,12位的灰度像素数据可以第一次读取后缓存到内存中以方便后面调窗的快速读取优化这点代码也不难哈对指针什么的熟点就行了,前几章都有。