转自:https://zssure.blog.csdn.net/article/details/45119841
背景:
最近项目中遇到的实际问题较多,且大多是较隐蔽的、不易被发现的错误。究其根源来看,还是对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 atlas和Bias 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 Class、Basic Grayscale Print Management Meta SOP Class 和 Basic Color Print Management Meta SOP Class。其中Basic Grayscale Print Management Meta SOP Class 和 Basic Color Print Management Meta SOP Class是诸多SOPClass的集合,具体如上文截图所示。
因此判断逻辑中首先需要判别的是VerificationSOP Class、 Basic Grayscale Print Management Meta SOP Class 和 Basic 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 Class 或 Basic 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中没有找到博文中对应的内容请及时与我联系。
作者:zssure@163.com
时间:2015-04-18