DICOM:DICOM Print服务中PresentationContext协商之 MetaSOPClass与SOPClass对比分析

背景:

最近项目中遇到的实际问题较多,且大多是较隐蔽的、不易被发现的错误。究其根源来看,还是对DICOM3.0协议中的细节掌握不够仔细,因而导致在实际编码过程中,常常想当然。前一篇中剖析了由于DicomClient中的AddRequest与Send函数调用逻辑错误导致的System.ObjectDisposedException异常,接下来要讲的是关于DICOM胶片打印的问题,由于在Association Negotiation中PresentationContext协商失误导致DICOM Print SCU在连接某些型号打印机时无法出片

DICOM Print:

DICOM3.0协议中关于PRINT的部分主要有:第4部分的附录H第17部分的附录BB,在第4部分的附录H中主要讲解的是整体DICOM Print SOP,即服务对象对;而第17部分附录BB中给出的是一个具体的DICOM Print SCU实现过程。因此在利用dcmtk、fo-dicom或者dcm4che开源库来实现自己的DICOM Print服务(SCU或SCP)时应该先仔细阅读第4部分附录H中关于该服务的详细定义与介绍,然后再按照第17部分的附录BB中示例的流程进行实际开发。第17部分附录BB中给出的具体流程如下:

由图中可见,在Association Negotiation阶段并未给出详细的步骤,而这部分恰恰是项目实际部署过程中遇到隐含问题的地方,在介绍问题之前先介绍一个DICOM Print服务中独有的服务。。

DICOM Meta SOP Class与DICOM SOP Class:

Presentation Context:

在DICOM协议底层建立连接时,会用到Presentation Context,如下图所示:

简而言之PresentationContext就是连接上下文,存储用于连接双方进行协商的信息,具体的介绍可参阅专栏中的博文和。DICOM协议规定,在连接请求(Association Negotiation)过程中,由请求发起方设置各个Presentation Context的ID号,该ID号不具有实际意义,类似于数据库中的主键Primary Key,仅用于区别各个Presentation Context,被请求端在接收到请求端发送过来的请求后,并不会修改消息中PresentationContext的ID号,因此理论上而言请求端可以自行设置各个PresentationContext的ID号,且对于各PresentationContext的ID号的排序也没有任何要求。关于PresentationContext的详细介绍可阅读DICOM3.0标准第8部分的7.1.1.13。

如上图所示每个PresentationContext包含三个部分,

  • 第一部分ID号
  • 第二部分AbstractSyntax,这个在博文中有过介绍,要区别于随后提到的TransferSyntax,AbstractSyntax可以简单理解为每项服务的抽象的名称;
  • 第三部分TransferSytanx,该部分要求每一个PresentationContext中服务端和客户端之间**有且仅有一种**TransferSyntax用于彼此间数据交换的编码格式。

【注】:AbstarctSyntax在DICOM3.0标准的第4部分有详细介绍;TransferSyntax在DICOM3.0标准的第5部分有详细介绍,此外在第8部分的附录B中也有相关对比

DICOM UID分类:

UID,全称为Unique Identifiers,用于区别各项事务,确保在多国家、地区、供应商,以及设备间的唯一性。

虽然UID的目的只有一个区别各项事务,确保唯一性。但是由于各自代表的领域不同、服务的对象不同、具体使用的场景不同,开源库在具体实现时会对UID进行分类,用于标记区分各事务。下面以fo-dicom中DicomUID为例进行讲解:

在DicomUID类中,定义了DicomUidType枚举类型,

 public enum DicomUidType {
                    TransferSyntax,
                    SOPClass,
                    MetaSOPClass,
                    SOPInstance,
                    ApplicationContextName,
                    CodingScheme,
                    FrameOfReference,
                    LDAP,
                    Unknown
}

由此推测DICOM协议中的UID大致分成9类,下面对于各种类型进行详细介绍:

1)TransferSyntax,该类UID就是我们之前提到的用于标识客户端与服务端之间消息流传输的各种编码格式。

2)SOPClass ,即常见的服务对象对类型,Service-Object-Pairs Class。主要用于标记各种服务,例如DIMSE-C服务、DIMSE-N服务。

3)MetaSOPClass,是一系列SOP Class的集合,具体参见Meta SOP Class Definitions,Meta SOP Class中最常见的就是两种具体打印服务,即Basic Grayscale Print Management Meta SOP Class和Basic Color Print Management Meta SOP Class。如下图所示:

4)SOPInstance,用于描述现实场景中具体的“实例”,可以脱离于交互上下文、交互环境(Communication Context)而存在,例如后缀为.dcm的医学图像文件等等。

5)ApplicationContextName,该UID是DICOM专属的,用于标识DICOM应用,因此ApplicationContextName类中有且只有一个对象,即

 /// <summary> Application Context Name: DICOM Application Context Name [PS 3.7]</summary>
 public static DicomUID DICOMApplicationContextName = new DicomUID("1.2.840.10008.3.1.1.1" , "DICOM Application Context Name", DicomUidType.ApplicationContextName);

6)CodingScheme,DICOM协议中的编码方案,可以简单的理解为DICOM协议中各种符号含义的约定,具体可参见DICOM3.0第16部分附录D

7)FrameOfReference,用于定位的坐标系,该坐标系是已经公开的、约定俗成的,例如脑图谱中著名的Talairach Brain Atlas Frame of Reference,具体可查阅Wiki百科,如下图所示:

关于FrameOfReference还可阅读国外文献资料,例如The MNI brain and the Talairach atlasBias Between MNI and Talairach Coordinates Analyzed Using the ICBM-I5 Brain Template

8)LDAP,Lightweight Directory Access Protocol,中文称之为“轻型目录访问协议”。具体可搜索资料,我也是一知半解。

9)UnKnown,其他预留扩展使用,或用户自定义。

MetaSOPClass与SOPClass的对比:

综上所述,之前项目的DICOM Print SCU实现中对于DICOM Print部分的PresentationContext的判断逻辑有误,DICOM Printer(即Print SCP)支持的服务分为Verification SOP ClassBasic Grayscale Print Management Meta SOP ClassBasic Color Print Management Meta SOP Class。其中Basic Grayscale Print Management Meta SOP ClassBasic Color Print Management Meta SOP Class是诸多SOPClass的集合,具体如上文截图所示。

因此判断逻辑中首先需要判别的是VerificationSOP ClassBasic Grayscale Print Management Meta SOP ClassBasic Color Print Management Meta SOP Class等最顶层级别的SOPClassUID,而不需要直接判别PrinterSOPClass,原因是:

/// <summary> SOP Class: Printer SOP Class [PS 3.4] </summary>
 public static DicomUID PrinterSOPClass = new DicomUID ("1.2.840.10008.5.1.1.16", "Printer SOP Class" , DicomUidType.SOPClass);

PrinterSOPClass是SOPClass类型的DicomUID,属于SOPClasses集合Basic Grayscale Print Management Meta SOP ClassBasic Color Print Management Meta SOP Class。此刻再倒回头去看一下DICOM协议第17部分附录BB中给出的示例,PrinterSOPClass只是在N-GET服务中使用,用于SCU端获取DICOM Printer打印机的各种参数。

根据上述概念,用类图的形式来表示各概念之间的包含关系。SOP Class和Meta SOP Class都属于Service Class,SOP Class中包含IOD和DIMSE Service。

DICOM Print SCU 与SCP连接协商逻辑:

在之前[冷锋的博文]中介绍过利用DCMTK工具包来简单的模拟实现DICOM 打印的过程,但是之前并未详细分析梳理过相关代码,究其原因是因为身边没有胶片打印机。现在由于实际部署过程中遇到了上述问题——即DICOM打印过程中如何协商PresentationContext???。下载通过分析DCMTK库中具体的源码,给出其中对于DICOM 打印过程中PresentationContext协商的具体实现。

知识点补充:

下面对博文中提到的诸多概念进行简单介绍,并给出各概念在DICOM3.0协议中的具体位置。

至此关于DICOM胶片打印服务的连接建立过程中如何协商PresentationContext的逻辑介绍就完成了。

PS: 我一直阅读的本机DICOM3.0协议是2011版,前几天在跟朋友沟通时发现DICOM官网已经更新到了2015a版本,因此后续的介绍中我会尽量按照最新协议来分析,或者至少给出与2011版本中对应的最新2015a版中的内容,如果在2015a中没有找到博文中对应的内容请及时与我联系。

作者:[email protected]

时间:2015-04-18

时间: 2024-10-26 13:34:53

DICOM:DICOM Print服务中PresentationContext协商之 MetaSOPClass与SOPClass对比分析的相关文章

Java中两种实现多线程方式的对比分析

本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cfe1 Java中有两种实现多线程的方式.一是直接继承Thread类,二是实现Runnable接口.那么这两种实现多线程的方式在应用上有什么区别呢? 为了回答这个问题,我们可以通过编写一段代码来进行分析.我们用代码来模拟铁路售票系统,实现通过四个售票点发售某日某次列车的100张车票,一个售票点用一个线

DICOM:DICOM Print 服务详细介绍

背景: 昨天专栏中发表了一篇关于DICOM Print的博文DICOM:DICOM Print服务中PresentationContext协商之 MetaSOPClass与SOPClass对比分析,文章从部署中遇到的实际情况出发,对DICOM Print中的连接协商(Association Negotiation)进行了剖析,本文可看做是上一篇博文的补充,重新浏览和整理了DICOM3.0标准中对DICOM Print 服务的介绍,加深对DICOM打印的理解. DICOM Print服务数据流:

DICOM:剖析Orthanc中的Web Server,Mongoose之 Flag bit &amp; Event(三)

背景: Orthanc是本专栏中介绍过的一款新型DICOM服务器,具有轻量级.支持REST的特性,可将任意运行Windows和Linux系统的计算机变成DICOM服务器,即miniPACS.Orthanc内嵌多种模块,数据库管理简单,且不依赖于第三方软件.因此通过剖析Orthanc源码可以学习到搭建DICOM系统中的各个环节,例如SQLite嵌入型数据库.GoogleLog日志库.DCMTK医学DICOM库,以及近期要介绍的开源Web Server,Mongoose. 上一篇博文中简单的分析了M

DICOM:DICOM三大开源库对比分析之“数据加载”

背景: 上一篇博文DICOM:DICOM万能编辑工具之Sante DICOM Editor介绍了DICOM万能编辑工具,在日常使用过程中发现,"只要Sante DICOM Editor打不开的数据,基本可以判定此DICOM文件格式错误(准确率达99.9999%^_^)".在感叹Sante DICOM Editor神器牛掰的同时,想了解一下其底层是如何实现的.通过日常使用以及阅读软件帮助手册推断其底层依赖库很可能是dcmtk,就如同本人使用dcmtk.fo-dicom.dcm4che3等

绑定服务调用本地服务中的方法

如果想调用服务中的方法, 通过startService()是做不到的, 这时需要用bindService来解决. 下面的demo是在Activity中调用Service中的自定义方法---methodInService 这个demo可以解决在项目开发中调用service里的数据. 这里在service中使用到了代理模式.这是为了,给service组件和activity组件中间添加一个中间人. 通过代理来传递数据.也就是binder对象.这个代理就是接口IService Service中的代码如下

利用VisualVM监测Azure云服务中的Java应用

在做Java开发的时候,我们需要在上线之前对程序进行压力测试,对程序的性能进行全面的监控,了解JVM的CPU,内存,GC,classes,线程等等信息,或者在程序上线运行的过程当中以便于诊断问题或者对程序做出优化,市面上做Java profiling的工具也比较多,比如商业的JProfiler,JClarity等,也有免费的JDK自带的工具,如VisualVM,JConsole,JMC等等,那么当我们将Java应用程序部署到了Azure Cloud Service中,如何利用这些工具做性能监控和

Win7中如何在服务中启动一个当前用户的进程——函数CreateProcessAsUser()的一次使用记录

这次工作中遇到要从服务中启动一个具有桌面UI交互的应用,这在winXP/2003中只是一个简单创建进程的问题.但在Vista 和 win7中增加了session隔离,这一操作系统的安全举措使得该任务变得复杂了一些. 一.Vista和win7的session隔离 一个用户会有一个独立的session.在Vista 和 win7中session 0被单独出来专门给服务程序用,用户则使用session 1.session 2... 这样在服务中通过CreateProcess()创建的进程启动UI应用用

Win7中如何在服务中启动一个当前用户的进程——一次CreateProcessAsUser()使用记录

这次工作中遇到要从服务中启动一个具有UI交互的桌面应用,这在winXP/2003中只是一个简单创建进程的问题.但在Vista 和 win7中增加了session隔离,这一操作系统的安全举措使得该任务变得复杂了一些. 一.Vista和win7的session隔离 一个用户会有一个独立的session.在Vista 和 win7中session 0被单独出来专门给服务程序用,用户则使用session 1.session 2... 这样在服务中通过CreateProcess()创建的进程启动UI应用用

将WCF寄宿在托管的Windows服务中

在我之前的一篇博客中我介绍了如何发布WCF服务并将该服务寄宿于IIS上,今天我再来介绍一种方式,就是将WCF服务寄宿在Windows服务中,这样做有什么好处呢?当然可以省去部署IIS等一系列的问题,能够让部署更加简单,当然WCF的寄宿方式一般分为以下四种方式,针对每一种方式我来简单介绍以下: 具体的寄宿方式详细信息请参考MSDN:https://msdn.microsoft.com/zh-cn/library/ms733109(v=vs.100).aspx 一.WCF服务寄宿方式: 1):寄宿在