dicom java_[医疗信息化][DICOM教程]1.使用Java的DICOM基础-理解DICOM文件-DICOM Basics using Java - Making Sense of the ...

[医疗信息化][DICOM教程]1.使用Java的DICOM基础-理解DICOM文件-DICOM Basics using Java - Making Sense of the DICOM File

使用Java的DICOM基础-理解DICOM文件

内容

介绍

这是我有关DICOM标准的系列文章的一部分。在我们开始本教程之前,请快速浏览一下我之前的文章“ DICOM标准简介”,以简短,快速地介绍该标准。请注意,本教程假定您知道Java(或任何等效的面向对象的语言,如C#或C ++)。

我以为我将以DICOM文件格式的非常高级的介绍开始有关DICOM的编程教程系列。请方便地使用此链接的官方DICOM标准文档,因为我在本教程中介绍的许多内容都在此处进行了详细说明。

正如您在我的入门DICOM教程中所回忆的那样,DICOM文件通常使用标签的概念(将在后面进行解释)像其他图像格式(例如TIFF)一样,在同一文件中包含图像数据和有关患者的数据。但是,以DICOM词典的形式存储在DICOM文件中的信息比其他标准结构化和多样化得多。该词典(请参阅本文档的第23页,以了解其全面程度),其中包含数千个标签,可帮助我们对信息进行编码,例如何时何地拍摄图像,其所属人物,转介医师甚至诊断信息以及核心图像数据。这样可以最大程度地减少将某些关键医疗信息分配给错误患者的风险。

大多数DICOM文件(有时带有'.dcm'扩展名-参见本文的脚注)通常包含图像数据,有时甚至可能包含多个图像(或在DICOM中通常称为“帧”)以启用以下功能:称为电影循环,使DICOM观看者可以将整个图像序列可视化为电影。但是,DICOM文件并不一定像大多数人所想的那样是关于图像的,它还可以用于存储其他信息,例如报告,ECG信号甚至音频(我们将在后面介绍)。

“写作是大自然的一种让您知道自己的想法多么草率的方式”〜理查德·金登(Richard Guindon)

在以下各节中,我们将首先了解DICOM文件的基本结构(和语法),该文件使可能在不同操作系统和设备上运行的应用程序可以轻松地相互交换图像和与图像有关的信息。然后,我们将使用免费提供但功能非常强大的DICOM工具箱,称为PixelMed Java DICOM工具箱。来解析实际的DICOM文件,并查看其中的内容与我们所涵盖的概念有关,从而有助于加深我们对所涵盖概念的理解。请注意,DICOM文件比我在这里讨论的要多得多,但是对于像我这样的大多数使用工具箱或库来处理DICOM文件的开发人员来说,本教程和后面的其他信息应包括足以快速启动并运行。但是,如果您有兴趣从头开始编写自己的DICOM解析器,则应详细阅读本文档。

DICOM文件内部的外观

每个DICOM文件都由三个主要部分组成,现在我们来看一下每个部分在整体方案中所扮演的角色。

第一部分,文件头,由128字节的文件前导码和4字节的前缀组成。这种方法在您可能已经看到/使用过的许多其他图像标准(例如TIFF)中非常普遍。4字节前缀由大写字符“ DICM”组成(注意,它不是“ DICOM”,而是“ DICM”)。该标准不关心前导码应如何构造以及应在其中存储什么。根据我的理解,使用文件序言是为了确保处理应用程序像处理其他几种现有图像文件格式一样处理DICOM文件的兼容性或一致性。该标准并不关心您在其中存储的内容或使用方式。因此,从理论上讲,如果您选择解析DICOM文件,则您的应用程序可以完全跳过此数据。

在查看DICOM文件的下一部分之前,需要先谈谈传输语法的概念及其在DICOM标准中的作用。如果您从我以前的教程中回想起,即使设备运行在不同的操作系统上,DICOM标准也使设备之间能够相互传输信息。不同的操作系统和设备在存储二进制数据时遵循不同的格式来存储数据,例如字节顺序。由于需要大量网络来交换由CT或MR等扫描方式生成的大图像,因此该标准还规定在必要时/在使用压缩时交换图像数据。在我的DICOM入门教程中,我们还了解了隐式和显式VR编码也是如此。必须首先理解并达成所有三个标准(VR编码的类型,字节排序的类型和所使用的压缩),以确保两个交换信息的DICOM系统在它们之间的任何通信期间都能相互理解。传输语法是一组编码规则,可通过使用UID来帮助指定此条件,我们在DICOM入门教程中也了解到。例如,隐式VR小端(由UID值1.2.840.10008.1.2表示),显式VR小端(值-1.2.840.10008.1.2.1),显式VR大端(值-1.2.840.10008 .1.2.2)和JPEG无损(值-1.2.840.10008.1.2.4.57)是DICOM处理可用的一些传输语法。在我的DICOM系列的后续教程中讨论图像像素数据处理时,我将更详细地介绍这些内容。

既然我们已经了解了传输语法的简要含义(还有更多内容,包括演示上下文,我将在以后的教程中介绍),让我们看一下文件的下一部分,即文件元信息标头。本节紧随文件头之后,由一个数据集组成,该数据集由一系列标记信息(称为“ Dicom元素”)组成,该序列指定诸如传输语法(如上所解释)之类的详细信息以及有关设备或实现的其他信息创建此文件的对象以及为谁创建此信息的对象(接收应用程序)。有关详细信息,请参见本文档的第32页。

本节之后的内容是DICOM文件的第三部分也是最后一部分,它是数据对象。DICOM文件的此部分也以数据集的形式指定,该数据集由一系列标签组成,这些标签又可以嵌套并自身携带其他子标签。这些标签有助于携带有关SOP实例的信息(请参阅我的入门教程对于SOP意味着什么),例如研究,系列,其所属的患者以及其他有关图像的细节,例如图像像素数据,扫描位置数据等。研究,系列和患者信息通常用于在大多数PACS系统中为图像建立索引,以便更快地检索数据。我的下面的插图有望提供整个文件结构的概要,还显示了各个DICOM元素(每个元素包括标签和相关信息)如何成为整个结构的一部分。

b606f6cbaa9b93322cc602b32439ca34.png

例如,在上面的插图中所示的数据对象部分中的三个DICOM元素的第一个中,“(0008,0070)”表示属于组号0008的标签,其属性号为0070,“ LO”表示数据类型或值表示(VR),DICOM称之为它(LO表示长字符串数据类型),“ PHILIPS”是标记的实际值,“#8”有助于指定值8的长度(请注意,DICOM始终使用偶数个字符对文本进行编码,因此即使PHILIPS值只有7个字符长,也会使用一个额外的填充字符-稍后将对此进行详细说明,1表示值的多重性此处(可以重复一些数据),“制造商”是DICOM词典中指定的实际标签名称。组合的组和属性编号,VR,值,值多重性和标签名称称为DICOM元素。自DICOM字典以来(请参阅第23页及以后)隐式定义与每个标签关联的VR,VR是多余的,有时会被省略。尽管如此,一种常见的做法和建议是在将DICOM对象序列化为文件或在网络上交换DICOM信息时明确指定VR。当我在以后的教程中更详细地讨论传输语法时,将更详细地介绍隐式传输语法(省略VR)和显式传输语法(其中VR与标记一起指定)。现在,我们可以更好地了解什么是IOD(信息对象定义)。让我们继续。

这些术语在DICOM中到底意味着什么-SCU,SCP,SOP和IOD?

DICOM定义了服务和服务使用或对其进行操作的数据的概念。服务的示例可以是CT存储服务,它负责将从CT模态生成的图像存储到PACS服务器。服务分为两部分,服务的使用者也称为服务类用户或SCU,服务的提供者也称为服务类提供者或SCP。例如,在CT存储操作中,生成图像的模态用作C存储SCU并将要存储的数据传输到PACS服务器播放的C-Store SCP。在DICOM标准中,服务类和那些服务所涉及的对象的组合称为服务对象对或SOP。SOP的抽象定义称为SOP类,它们由唯一的标识符(称为UID)定义,我稍后将介绍(请参阅此链接以获取SOP列表)。因此,由1.2.840.10008.5.1.4.1.1.2的SOP类UID标识的SOP CT图像存储可帮助识别这是CT图像存储操作。在所涉及的机器之间进行此操作期间,会交换命令(称为DIMSE(我将在后面介绍)以及一些数据,其中包括图像像素信息以及其他识别信息,例如患者,研究,系列和设备信息。这些操作的具体细节一起被称为SOP实例。这些SOP实例中的每个实例也由唯一标识符标识,但由负责传输它们的应用程序生成。这些标识符称为SOP实例UID。此SOP涉及的实际数据由IOD(信息对象定义)定义,该IOD指定了要成功完成处理需要呈现哪些DICOM模块(模块本质上是DICOM元素组)。

IOD对象本身分为称为信息实体(缩写为IE)的子组,而信息实体又分为信息模块的小组。信息模块由我们已经看到的一系列DICOM元素组成。DICOM定义了有关强制性模块,有条件性模块和可选模块的规则。IOD本身分为归一化IOD和复合IOD。标准化IOD仅表示与一个实体有关的数据,而复合IOD表示来自彼此相关的各种实体的混合物的数据,如下图所示。总之,这本质上是DICOM信息模型的整体结构。综上所述,您现在将看到,到目前为止,我们处理的任何DICOM文件实际上都是IOD(信息的序列化版本)的实例,该IOD还在任何成像工作流程中在两台机器之间传输。在我们正在研究的情况下,该操作有助于将CT模态生成的图像存储到PACS服务器上。DICOM IOD和编码要比这里介绍的更多,但是在讨论创建DICOM文件和目录时,我们将处理这些领域。我不想让你无聊

3cecc2f1417a8bb2cdc40f572885eb4f.png

PixelMed Java DICOM工具包-快速概述

为了说明我计划在本教程系列中涵盖的DICOM的许多方面,我将使用一个称为PixelMed Java DICOM Toolkit的免费可用且功能强大的DICOM工具包。这是一个完全独立的DICOM工具包,为DICOM文件和目录处理,图像查看以及与DICOM网络相关的操作提供功能。该工具包对于商业或非营利性用途都是完全免费的。它有充分的文档记录,还为用户提供了一个小型讨论论坛和一个邮件列表。该工具包中包含的功能列表非常全面。请记住,在我的教程中使用此工具包绝不表示我对实现生产应用程序的官方认可。每种情况都是独特的,只有您最终处于最佳位置才能做出决定。本文也不是该工具包的教程,我在这里的重点只是将DICOM理论与实际(尽管简单)的实现方式联系起来。因此,如果您的目标是学习如何使用PixelMed库,我鼓励您访问其网站或查看讨论论坛或StackOverflow讨论页面以寻求帮助。

在我们开始之前...

与之前的编程示例非常相似,我将使用最简单的最少代码和方法来帮助说明本教程中介绍的概念。这意味着我在这里编写的代码最适合于简单地显示我试图解释的概念,并且不一定是在现实生活中和生产应用程序中部署的最有效的代码。

首先,您需要在计算机上配置一些东西,包括Java开发环境以及PixelMed工具包,然后才能运行示例(如果您想自己尝试一下)。

从此处下载并安装Eclipse Java IDE(或使用您喜欢的任何其他IDE)

从此处下载PixelMed工具包库

确保Java项目的类路径中包含PixelMed.jar库(某些示例可能需要其他运行时依赖项,例如可以在PixelMed软件下载中找到的JAI Image IO工具。寻找一个名为pixelmedjavadicom_dependencyrelease.YYYYMMDD.tar的tar压缩文件。 .bz2或类似名称)

您可以在GitHub上找到本教程中使用的源代码

您可以下载更多的DICOM图像从这个网站,如果你想和

列出要控制台的DICOM文件的各种标签

使用PixelMed工具包读取和提取DICOM标签信息非常简单。此操作仅需要两个类,即AttributeList和Attribute。该AttributeList中的类提供了读取(和写入)整个DICOM对象从文件或流的属性列表的方法。此类的构造函数采用您要处理的DICOM文件的路径。另一方面,Attribute类负责读取和写入DICOM属性。下面显示了使用这些类来显示我们感兴趣的DICOM元素。

package com.saravanansubramanian.dicom.pixelmedtutorial;

import com.pixelmed.dicom.Attribute;

import com.pixelmed.dicom.AttributeList;

import com.pixelmed.dicom.AttributeTag;

import com.pixelmed.dicom.TagFromName;

public class DumpDicomTagsToConsole {

private static AttributeList list = new AttributeList();

public static void main(String[] args) {

String dicomFile = "D:\\JavaProjects\\Sample Images\\MR-MONO2-16-head";

try {

list.read(dicomFile);

System.out.println("Study Instance UID:" + getTagInformation(TagFromName.StudyInstanceUID));

System.out.println("Series Instance UID:" + getTagInformation(TagFromName.SeriesInstanceUID));

System.out.println("SOP Class UID:" + getTagInformation(TagFromName.SOPClassUID));

System.out.println("SOP Instance UID:" + getTagInformation(TagFromName.SOPInstanceUID));

System.out.println("Transfer Syntax UID:" + getTagInformation(TagFromName.TransferSyntaxUID));

} catch (Exception e) {

e.printStackTrace(); //in real life, do something about this exception

}

}

private static String getTagInformation(AttributeTag attrTag) {

return Attribute.getDelimitedStringValuesOrEmptyString(list, attrTag);

}

}

运行以上代码的输出如下所示:

Study Instance UID:1.2.840.113619.2.1.3352.2053053415.834484316

Series Instance UID:1.2.840.113619.2.1.3352.1136944889.4.834485379

SOP Class UID:1.2.840.10008.5.1.4.1.1.4

SOP Instance UID:1.2.840.113619.2.1.3352.1015047400.4.3.834485381

Transfer Syntax UID:1.2.840.10008.1.2

将所有DICOM文件的标签列出到控制台

列出DICOM文件的全部属性很好,但是有时候,您只是想只显示DICOM文件中包含的特定标签,包括组和属性号,值表示(VR),值,值长度,值多重性和我在本教程前面介绍的标签名称信息。通过使用PixelMed库中包含的AttributeList类的toString方法,可以轻松实现此过程。该操作的代码说明如下所示。

package com.saravanansubramanian.dicom.pixelmedtutorial;

import com.pixelmed.dicom.AttributeList;

public class DumpDicomFileContentsToConsole {

public static void main(String[] args) {

String dicomFile = "D:\\JavaProjects\\Sample Images\\MR-MONO2-16-head";

try {

AttributeList list = new AttributeList();

list.read(dicomFile);

System.out.println(list.toString());

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行以上代码的输出如下所示:

(0x0002,0x0000) FileMetaInformationGroupLength VR=

  • VL=<0x4> [0xba]

(0x0002,0x0001) FileMetaInformationVersion VR= VL=<0x2> []

(0x0002,0x0010) TransferSyntaxUID VR= VL=<0x12> <1.2.840.10008.1.2 >

(0x0002,0x0012) ImplementationClassUID VR= VL=<0x18> <1.2.276.0.7230010.3.1.2 >

(0x0002,0x0013) ImplementationVersionName VR= VL=<0x10>

(0x0008,0x0000) VR= VL=<0x4> [B@681a9515

(0x0008,0x0008) ImageType VR= VL=<0x10>

(0x0008,0x0016) SOPClassUID VR= VL=<0x1a> <1.2.840.10008.5.1.4.1.1.4 >

(0x0008,0x0018) SOPInstanceUID VR= VL=<0x30> <1.2.840.113619.2.1.3352.1015047400.4.3.834485381>

(0x0008,0x0020) StudyDate VR= VL=<0xa> <1996.06.11>

(0x0008,0x0021) SeriesDate VR= VL=<0xa> <1996.06.11>

(0x0008,0x0023) ContentDate VR= VL=<0xa> <1996.06.11>

(0x0008,0x0030) StudyTime VR= VL=<0x8> <09:11:56>

(0x0008,0x0031) SeriesTime VR= VL=<0x8> <09:29:39>

(0x0008,0x0033) ContentTime VR= VL=<0x8> <09:29:41>

(0x0008,0x0060) Modality VR= VL=<0x2>

(0x0008,0x0070) Manufacturer VR= VL=<0x12>

(0x0008,0x0080) InstitutionName VR= VL=<0x20>

(0x000

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值