DICOM医学图像处理:fo-dicom网络传输之 C-Echo and C-Store

背景:

上一篇博文对DICOM中的网络传输进行了介绍。主要參照DCMTK Wiki中的英文原文。通过对照DCMTK与fo-dicom两个开源库对DICOM标准的详细实现,对理解DICOM标准有一个更直观的认识。此篇博文是对上一篇博文的补充。由于专栏前面的演示样例大多是利用DCMTK工具包来进行的,此次借着分析fo-dicom源代码结构的机会,參照fo-dicom的README.md,给出C-ECHO 和C-STORE服务的详细实现。在实现的同一时候给出DICOM3.0标准中的相关介绍,帮助我们理解。

C-ECHO的fo-dicom实现:

1)C-ECHO參数说明:

C-ECHO又叫验证服务(即Verification),是用来验证DICOM服务两端的交流是否畅通。DICOM3.0的第7部分给出了C-ECHO服务的參数。例如以下图1所看到的:

【注意】:这里解说一下DICOM3.0标准的阅读方法。

以DICOM3.0标准的第7、8部分为例,【第7部分】中第9章開始解说DIMSE-C的各种服务。依次为C-STORE、C-FIND、C-GET、C-MOVE、C-ECHO(上图1就是我在该部分的C-ECHO小节中截取的),当中前半部分主要给出了DIMSE-C各种服务的參数。这里不过罗列出DICOM3.0标准的要求,目的是让你明确各个服务參数是否是必要的(分别用M、U、=表示);后半部分開始解说DIMSE-C各种服务的协议及实现流程(即Protocol和Procedures)。在PROTOCOL中给出的是详细的DIMSE-C服务的各种指令在传输过程中的格式,该部分也就是你利用抓包工具可以直接抓取的真实数据流;在Procedures中给出的是SCU和SCP之间的交互流程。通常为了说明服务是由谁发起的,由谁响应。在介绍Protocol的时候对于比較复杂的、可变的区域(Variables
Fields)一般会放在附录中。比如第7部分的附录C和E等。【第8部分】与【第7部分】类似,从第7章開始介绍ACSE的各种服务的參数(例如以下图2所看到的),依次为A-ASSOCIATE、A-RELEASE、A-ABORT、A-P-ABORT、P-DATA;第9章给出的是ACSE中各种服务的结构,即STRUCTURE。该部分与【第7部分】中的PROTOCOL相同,给出的是详细ACSE PDU在传输时刻的数据格式,该部分也是能够通过抓包工具直接获得的;相同对于比較复杂的STRUCTURE介绍也会单独放到附录中,比如第8部分的附录E。

fo-dicom对于DIMSE消息的实现基类是DicomMessage。针对请求和响应分别派生出了DicomRequest和DicomResponse。最后依据不同的DIMSE服务派生对应的类。C-ECHO是当中最简单的,fo-dicom已经给出了SCP和SCU的详细实现。

參照fo-dicom中的README.md文件,给出C-ECHO SCP和SCU的代码,详情例如以下:

2)C-ECHO代码实例:

C-ECHO SCP的代码是直接利用了fo-dicom给出的DicomCEchoProvider类,通过创建DicomServer<DicomCEchoProvider>(12345)对象,开启C-ECHO SCP服务,当中參数12345表示C-ECHO服务的port号。C-ECHO SCU和C-ECHO SCP的代码分别例如以下所看到的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Dicom;
using Dicom.Network;

namespace CEchoSCU
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new DicomClient();
            client.NegotiateAsyncOps();
            client.AddRequest(new DicomCEchoRequest());
            client.Send("127.0.0.1", 12345, false, "SCU", "ANY-SCP");
            Console.ReadLine();

        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Dicom;
using Dicom.Network;
namespace CEchoSCP
{
    class Program
    {
        static void Main(string[] args)
        {
            var server = new DicomServer<DicomCEchoProvider>(12345);
            Console.ReadLine();

        }
    }
}

实际执行结果例如以下:

C-STORE的fo-dicom实现:

1)C-STORE參数说明:

C-STORE就是存储服务。在医疗信息系统中最常见的服务之中的一个。尤其是PACS系统中。与C-ECHO服务同样,DICOM3.0标准第7部分也给出了C-STORE服务的參数列表,例如以下图4所看到的:

该參数列表的目的相同是为了介绍C-STORE服务中各參数的必要性。真正的參数消息格式在兴许的C-STORE PROTOCOL中介绍,例如以下图5所看到的:

图5中给出的不过C-STORE RQ的实际消息格式,该消息由C-STORE服务的SCU(client)流向C-SOTRE服务的SCP(服务端);与之相相应的C-STORE-RSP消息是从SCP流向SCU。DICOM3.0标准中也有C-STORE-RSP的具体介绍,例如以下图6所看到的。

2)C-STORE代码实例:

在fo-dicom的说明文档README.md中仅仅给出了C-STORE的SCU演示样例,例如以下图7所看到的:

上一篇博文对fo-dicom源代码结构分析的基础上可知。实现DIMSE众多服务的SCU端非常easy,首先创建DicomClient实体类,代表一个client。然后通过AddRequest加入不同的请求就可以实现各种DIMSE的client,如图7中C-STORE SCU的实现为:

client.AddRequest(new DicomCStoreRequest(@"test.dcm"));

DicomCStoreRequest类是DicomRequest的派生类,上述代码通过制定DCM文件路径来构建了一个DicomCStoreRequest对象,在DicomCStoreRequest内部通过打开指定的DCM文件提取获得上述參数中的Affected SOP Instance UID等參数。

既然fo-dicom中没有提供线程的C-STORE SCP实现,我们先利用DCMTK的storescp.exe工具来验证一下fo-dicom给出的C-STORE SCU的正确性,測试代码例如以下:

  • SCP端利用storescp.exe,在控制台下输入:storescp.exe –d –od c:\ 12345
  • SCU端利用fo-dicom中的C-STORE SCU。详细代码如上图7所看到的。然后双击生成后的storescu.exe。

最后能够得到例如以下结果,如图8所看到的:

同一时候在C盘根文件夹下能够看到被重命名的test.dcm文件,例如以下图9所看到的:

之所以被重命名我们在之前分析DCMTK开源库源代码时提到过,通常DCMTK会依据SOP Instance UID(-uf,默认的)对接收到的DCM文件进行重命名,当然也能够通过选项设置重命名的方式。比如依照时间(-tn)、特定前缀(-fe)等等,例如以下图10所看到的。

由此说明fo-dicom中给出的C-STORE SCU功能正常。接下来我们尝试利用fo-dicom构建C-STORE SCP。

3)构建C-STORE SCP

打开C-ECHO SCP的实现DicomCEchoProvider.cs文件,我们看到DicomCEchoProvider类通过派生DicomService服务类来实现了Dicom服务的基本框架。然后通过实现IDicomServiceProvider和IDicomCEchoProvider接口,完毕了C-ECHO 的服务端。细致查看DicomCEchoProvider的代码能够发现,事实上就是在接收到A-ASSOCIATE-RQ消息后。判别Presentation Context中的Abstract Syntax。依据实际请求消息来决定是否建立连接,另外当接收到C-ECHO
SCU发起的C-ECHO Request时,向其会送DicomCEchoResponse确认信息就可以。

既然通过实现两个接口函数就能够完毕C-ECHO SCP的构建,那么我们就自己尝试来完毕C-STORE SCP的搭建,仿照DicomCEchoProvider的方式,DicomCStoreProvider的代码例如以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dicom;
using Dicom.Log;
using Dicom.Network;
using System.Threading;
using System.IO;
namespace CStoreSCP
{
    class CStoreSCPProvider : DicomService, IDicomServiceProvider, IDicomCStoreProvider
    {
        public CStoreSCPProvider(Stream stream, Logger log) : base(stream, log) { }

        public DicomCStoreResponse OnCStoreRequest(DicomCStoreRequest request)
        {
            return new DicomCStoreResponse(request,DicomStatus.Success);
        }
        public void OnCStoreRequestException(string tempFileName, Exception e)
        {

        }
        public void OnReceiveAssociationRequest(DicomAssociation association)
        {
            foreach (var pc in association.PresentationContexts)
            {
                if (pc.AbstractSyntax == DicomUID.Verification)
                    pc.SetResult(DicomPresentationContextResult.Accept);
                else
                {
                    //pc.SetResult(DicomPresentationContextResult.RejectAbstractSyntaxNotSupported);
                }
                if (pc.AbstractSyntax == DicomUID.CTImageStorage)
                {
                    pc.SetResult(DicomPresentationContextResult.Accept);
                }
            }
            SendAssociationAccept(association);

        }
        public void OnReceiveAssociationReleaseRequest()
        {
            SendAssociationReleaseResponse();

        }
        public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
        {

        }
        public void OnConnectionClosed(int errorCode)
        {

        }

    }
}

然后通过var server = new DicomServer<CStoreSCPProvider>(12345);Console.ReadLine(); 来构建一个C-STORE SCP应用。

下图11是先执行CStoreSCP.exe,然后执行CStoreSCU.exe得到的结果:

从图11的输出结果能够看出。此次C-STORE SCP和SCU两端的通讯顺利完毕,那么我们发送的C:\test.dcm文件会被CStoreSCP.exe存储到那里呢?由上一篇博文分析我们知道fo-dicom库中将DICOM的服务基本框架放在了DicomService类中。查看当中处理P-DATA服务的核心函数ProcessPDataTF,能够看到例如以下代码:

var file = new DicomFile();
file.FileMetaInfo.MediaStorageSOPClassUID = pc.AbstractSyntax;
file.FileMetaInfo.MediaStorageSOPInstanceUID = _dimse.Command.Get<DicomUID>(DicomTag.AffectedSOPInstanceUID);
file.FileMetaInfo.TransferSyntax = pc.AcceptedTransferSyntax;
file.FileMetaInfo.ImplementationClassUID = Association.RemoteImplemetationClassUID;
file.FileMetaInfo.ImplementationVersionName = Association.RemoteImplementationVersion;
file.FileMetaInfo.SourceApplicationEntityTitle = Association.CallingAE;
_dimseStream = CreateCStoreReceiveStream(file);

转到CreateCStoreReceiveStream函数内部,通过函数的说明就能够知道fo-dicom对C-STORE服务默认情况下是在系统中创建了一个暂时文件,用来接收C-STORE SCU的数据。因此能够判断我们的test.dcm文件应该也在暂时目录中,打开我本机的temp目录。能够看到有一个后缀为tmp的暂时文件。例如以下图12所看到的。

文件大小与我们測试用的test.dcm同样。尝试改动.tmp的扩展名,改动后能够使用DICOM Viewer软件正常打开。因此说明我们的C-STORE SCP顺利成功。

DICOM数据流分析:

C-ECHO服务数据流分析:

1)工具:

在本地測试。为了抓取127.0.0.1回路数据包,须要使用RawCap.exe工具包。

RawCap.exe是控制台程序,在抓取本地回路数据包时非常便捷。

当抓取完毕后我们须要借助于WireShark的强大分析功能,来实现C-ECHO数据流的具体分析。WireShark能够直接打开RawCap.exe抓取的.pcap数据包。

WireShark是功能强大的数据包统计分析工具。当然本身也能够抓取网络数据包(本地回路数据包不方便)。WireShark支持众多协议,当中包含DICOM协议。以下以C-ECHO的数据包为例,简介一下怎样使用WireShark来自己主动识别并解析DICOM数据包。首先打开抓取的本地C-ECHO数据包cecho.pcap。如图13,在Protocol中右键选择"Protocol Preferences “中的"Data Preferences…”,会弹出一个协议设置窗体如图13。在左側列表中找到DICOM协议,勾选图14中红色部分。该部分的意思是除了检測DICOM协议默认port104的数据包的同一时候也检測其它port的数据包。之所以须要选择此项是由于非常多DICOM服务并未使用协议默认的104port。设置完毕后,又一次查看Protocol列,能够看到出现了DICOM字样。如图15所看到的。最上方的带DICOM字样的数据包就是我们抓取到的C-ECHO服务的本地回路数据包。

2)C-ECHO数据流分析:

利用RawCap.exe和WireShark两大强大的工具,我们已经能够直观的看到抓取的DICOM数据包了。接下来我就依照DICOM标准第7部分和第8部分中的内容,逐个数据包来分析一下,通过观察真实的数据包来加深一下对DICOM协议的理解。

从图15中能够看到。最顶部DICOM协议包括6个数据包,各自是连接建立(A-ASSOCIATE RQ/A-ASSOCIATE AC)、数据交互(P-DATA-TF)、连接释放(A-RELEASE RQ/A-RELEASE RP),这与DICOM协议第8部分中介绍的ACSE控制流程相符。

A-ASSOCIATE RQ/A-ASSOCATE AC分析:

双击第一个DICOM数据包,该数据包是A-ASSOCIATE RQ的真实数据流,如图16所看到的:

依照DICOM协议第8部分中第9章对A-ASSOCIATE RQ PDU的描写叙述。我们来逐项对照(DICOM协议可參照图17):第一项1个字节的PDU-type,图中为01H,说明该数据包代表的是A-ASSOCIATE RQ;第二项一个字节的保留,数据流为00H;第三项是四个字节的PDU-length,图中为00 00 00 ff,转换为无符号整数正好为255。这也是整个图中蓝色部分兴许的数据包长度;第四项是两个字节的Protocol-Version,图中为00
01。相应版本号为1;第五项为两字节保留;第六项和第七项是我们熟悉的AE Title,从WireShark的数据流中也能够看出各自是ANY-SCP和ECHOSCU;第8项又是一堆保留字节。用00H填充;第9项是一个可变区域(Variable Fields),该项是复合项。内部包括多个独立的子项。由图16能够看出该复合项内部含有Application ContextPresentation
Context
(2个,ID各自是1、3)、UserInfo三个子项;而UserInfo又是一个复合项,其内部又包括了Max PDU LengthImplentationUIDImplentationVersion三个子项。从WireShark的分析来看,Application Context子项类型为10H、Presentation Context子项类型为20H、UserInfo子项为50H(其内部的嵌套子项的类型分别为,Max
PDU Length-51H、Implentation UID-52H、Implentation Version-55H
)。各个子项的类型与DICOM协议第7、8两部分中的附录D相相应。比如图19中我截取的是Max PDU Length子项的格式。A-ASSOCIATE AC的数据包分析与A-ASSOCIATE RQ类似,仅仅是A-ASSOCIATE AC的数据流更简单一些,这里就不做具体介绍了。(终于数据域DICOM协议的相应结果如图18)。

A-RELEASE RQ/A-RELEASE RP分析:

连接释放的数据包格式简单,以下图20和图21各自是DICOM协议第8部分中给出的连接释放请求和应答数据包的格式:

双击WireShark中的连接释放数据包,能够看到两者的数据包类型分别为05H和06H,这与上图中DICOM协议的规定全然一致。

P-DATA-TF:

在上一篇博文中(http://blog.csdn.net/zssureqh/article/details/41016091)我已经分析了。DICOM协议第7部分中规定的DIMSE消息(Command和Dataset)是通过第8部分中ACSE协议中的P-DATA-TF服务以PDV的形式来传输的

以下就让我们来分析一下DIMSE消息中C-ECHO
RQ 和C-ECHO RSP的格式:

双击WireShark数据包中间两个,从数据流向能够断定一个是C-ECHO RQ消息。一个是C-ECHO RSP消息。

先打开第一个。依照上一篇博文的分析。首先该数据包是一个P-DATA-TF PDU,因此须要符合下图23中的格式。

通过分析最外层的是代表P-DATA-TF类型的04H。然后是由DIMSE消息填充的PDV区域,该项是复合项,第一子项是Item-length,此处为46H;第二子项为Presentation-context-ID,此处为01H;第三子项又是一个复合项。是DICOM标准第4部分中给出的DIMSE消息结构。包含Message Control Header、Command和DataSet三部分。此处的MessageControlHeader为03H,即表示是Command数据而不是DataSet,且是最后一个PDV,即Last
Fragment。详细的相应关系如图24所看到的:

C-STORE服务数据流分析:

1)工具:

依旧使用RawCap.exe+WireShark来解决。

2)C-STORE数据流分析:

依照C-ECHO中的分析方式,相同能够看到DICOM数据包,如图25所看到的:

A-ASSOCIATE RQ/A-ASSOCIATE AC:

对于A-ASSOCIATE RQ/A-ASSOCIATE AC的分析与C-ECHO中基本类似,唯一不同的就是对于C-STORE服务须要不同的Presentation Context描写叙述上下文,如图26所看到的,此处C-STORE须要的是CT Image Storage服务,其SOP Class UID为1.2.840.10008.5.1.4.1.1.2。

A-RELEASE RQ/A-RELEASE RP:

与C-ECHO中的同样,这也说明了博文中的C-ECHO 和C-STORE服务实现成功。连接可以正常释放。

P-DATA-TF:

此处着重分析一下C-STORE服务中的P-DATA-TF数据包,由于传输一个DCM文件须要多个PDU,自然也须要多个PDV。

所以我们通过分析C-STORE的P-DATA-TF数据包能够更形象的学习Message Control Header和DIMSE的知识

相同传输的每一个数据包首先符合P-DATA-TF的格式要求。第一项是PDU类型,即04H。随后是保留项、PDU-length、PDV复合项……,这与C-ECHO中的分析相同。依照上一篇博文的分析,C-STORE PROTOCOL的流程是CSTORE SCU向SCP发送C-STORE RQ消息。可是打开图中的第一个P-DATA数据包时我们看到的却不是C-STORE RQ,而是当中的一个数据片段,例如以下图27所看到的。

依次查看后面的几个P-DATA数据包,都是类似的情况。最后倒数两个各自是C-STORE RQ中DCM文件数据的最后一个数据包(Last Fragment)和SCP向SCU发送的C-STORE RSP,详细分析如图28所看到的:

从最后数据包Command中的(0000,0100)的值域8001H可知该指令就是C-STORE RSP。

看到这里你也许会非常兴奋,由于我们最终也看到了C-STORE服务的真实数据流。可是在上图中的全部DICOM相应的数据包中我们并未找到C-STORE SCU发起的C-STORE RQ数据包,那么C-STORE RQ数据包在哪里呢

让我们将cstore.pcap的全部数据包依照时间排序,出现了大量标记为[TCP segment of a reassembled PDU]的TCP数据包。

打开第一个标记为[TCP segment of a reassembled PDU]的TCP数据包。其内部的真实数据分析例如以下图30所看到的:

至此我们顺利找到了C-STORE SCU端发送的C-STORE RQ消息,之所以没有在WireShark中以DICOM协议显示,可能是因为WireShark在识别多个连续分片的数据时不够智能。博文中的演示样例图和文字较多,细致阅读后应该对DICOM3.0中的协议会有更进一步的了解。通过分析数据包的方式在更直观的学习和掌握DICOM3.0标准的同一时候,对后期排查DICOM网络传输相关错误也会有帮助。

备注:

再次说明一下阅读DICOM3.0标准的方式:

以DICOM3.0标准的第7、8部分为例,【第7部分】中第9章開始解说DIMSE-C的各种服务,依次为C-STORE、C-FIND、C-GET、C-MOVE、C-ECHO(上图1就是我在该部分的C-ECHO小节中截取的),当中前半部分主要给出了DIMSE-C各种服务的參数,这里不过罗列出DICOM3.0标准的要求。目的是让你明确各个服务參数是否是必要的(分别用M、U、=表示);后半部分開始解说DIMSE-C各种服务的协议及实现流程(即Protocol和Procedures)。在PROTOCOL中给出的是详细的DIMSE-C服务的各种指令在传输过程中的格式,该部分也就是你利用抓包工具可以直接抓取的真实数据流;在Procedures中给出的是SCU和SCP之间的交互流程。通常为了说明服务是由谁发起的。由谁响应。在介绍Protocol的时候对于比較复杂的、可变的区域(Variables
Fields)一般会放在附录中。比如第7部分的附录C和E等;【第8部分】与【第7部分】类似。从第7章開始介绍ACSE的各种服务的參数(如图2所看到的),依次为A-ASSOCIATE、A-RELEASE、A-ABORT、A-P-ABORT、P-DATA;第9章给出的是ACSE中各种服务的结构,即STRUCTURE,该部分与【第7部分】中的PROTOCOL相同,给出的是详细ACSE PDU在传输时刻的数据格式,该部分也是能够通过抓包工具直接获得的。相同对于比較复杂的STRUCTURE介绍也会单独放到附录中。比如第8部分的附录E。

实例project及抓取的数据包:

代码:搜索我上传的资源

数据包:搜索我上传的资源

兴许专栏博文介绍:

利用PHP Skel结合DCMTK开发WEB PACS应用

利用oracle直接操作DICOM数据

C#的异步编程模式在fo-dicom中的应用

VMWare三种网络连接模式的实际測试

作者:[email protected]

时间:2014-11-18

时间: 2024-10-01 03:06:29

DICOM医学图像处理:fo-dicom网络传输之 C-Echo and C-Store的相关文章

DICOM医学图像处理:fo-dicom网络传输之C-FIND and C-MOVE

背景: 该系列博文同属于DICOM协议中的"网络传输"部分,前两篇系列文章分别介绍了DCMTK和fo-dicom开源库对DICOM标准的具体实现(http://blog.csdn.net/zssureqh/article/details/41016091),以及给出了fo-dicom库对C-ECHO 和C-STORE的简单实现(http://blog.csdn.net/zssureqh/article/details/41250973).此篇博文是对前一篇的补充,同样采用分析DICOM

DICOM医学图像处理:DICOM存储操作之 “多幅JPG图像数据存入DCM文件”

背景: 续上篇,继续介绍如何将多幅JPG图像数据存入DCM文件.即将有损压缩数据直接写入DCM文件,存储为Multi-frame形式. 多幅JPG图像数据存入DCM文件: 为了避免引起歧义,这里着重说明一下.本博文的描述的场景是:假设我们手中有多张JPG文件,想把JPG文件写入DCM文件,即单个DCM文件包含多幅图像信息的Multi-Frame形式.该问题之前与CSDN博友y317215133y也讨论过,当时我在OFFIS论坛中找到了一个帖子直接给了y317215133y答复.今天重新梳理了一下

DICOM医学图像处理:DICOM网络传输

背景: 专栏取名为DICOM医学图像处理原因是:博主是从医学图像处理算法研究时开始接触DICOM协议的.当初认识有局限性,认为DICOM只是一个简单的文件格式约定,简而言之,我当时认为DICOM协议就是扩展名为DCM文件的格式说明.其实不然,随着对医疗行业的深入,对DICOM协议也有了更全面的认识.而今才发现DCM文件只是DICOM协议一部分中的一小节,仅仅是整个协议中的一个数据结构,而DICOM协议更多的是关于医疗行业各种服务及相关流程的约定,因此其实DICOM协议中最主要的是信息流,是对医院

DICOM医学图像处理:DICOM存储操作之“多幅BMP图像数据存入DCM文件”

背景: 本专栏"DICOM医学图像处理"受众较窄,起初只想作为自己学习积累和工作经验的简单整理.前几天无聊浏览了一下,发现阅读量两极化严重,主要集中在"关于BMP(JPG)与DCM格式转换"和"DICOM 通讯协议",尤其是许久前的第一篇博文DCMTK开源库的学习笔记1:将DCM文件保存成BMP文件或数据流(即数组).因此在2014年底前打算写几篇关于DCM格式转换的文章,此次主要聚焦"如何将BMP.JPG等常规图像保存成DCM文件&q

DICOM医学图像处理:DCMTK的wiki资料学习之PACS调试

背景: 前段时间着重从dcmtk和fo-dicom(mDCM)源码角度进行剖析,期望加深对DICOM协议的理解.知其然,知其所以然.如果"所以然"很不好懂,那我们还是先多多"知其然"吧.搞清楚原理的目的不也是为了更好的运用于实践么?所以理论和实践应该彼此交错进行,理论搞不动了就搞搞应用,应用久了就钻研钻研理论. 以前上DCMTK官网仅仅是浏览关于开源库中各个类的设计模式.依赖关系.最近在打开DCMTK官网的wiki时,才发现OFFIS对DCMTK的介绍是如此的详细.

DICOM医学图像处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求

背景: 上一篇专栏博文中针对PACS终端(或设备终端,如CT设备)与RIS系统之间worklist查询进行了介绍,并着重对比分析了DICOM3.0中各部分对DICOM网络通讯服务的定义.此次通过结合早些时间的博文DICOM医学图像处理:基于DCMTK工具包学习和分析worklist,对DCMTK开源库中提供的storescp.exe和storescu.exe工具的源码进行剖析,从底层深入了解C-STORE服务的触发及响应. 分析思路: storescp.exe和storescu.exe分别充当着

DICOM医学图像处理:开源库mDCM与DCMTK的比较分析(一),JPEG无损压缩DCM图像(续)

背景: 上周通过单步调试,找出了开源库mDCM与DCMTK在对DICOM图像进行JPEG无损压缩时的细小区别,并顺利实现了在C++和C#环境下对DICOM图像的压缩.但是问题接踵而至啊,随着项目的深入,发现在单独的测试工程中可以实现的mDCM版本,在嵌入到项目整体中后,却意外地出现了错误,并未顺利实现DICOM图像的JPEG无损压缩.因此需要继续详细对比分析mDCM与DCMTK两者,期望寻找原因. 问题分析: 开启项目的日志功能后,得到的信息反馈为: No registered codec fo

DICOM医学图像处理:DCMTK在VS2012中的配置

背景: 最近由于项目需要,将原本的开发IDE环境由VS2008升级到了VS2012.本以为编译完成后的DCMTK开源库可以直接从VS2008移植到VS2012.但是通过项目属性添加完包含目录和依赖库后,编译会出现大量的链接错误(大多是跟dcmdata.lib.oflog.lib有关). 解决方法: 重新按照原本的博客前辈柳北风儿(大神目前已经博客转移到网易:http://blog.163.com/[email protected]/),利用CMake工具,选择VS2012本地编译器对DCMTK3

DICOM医学图像处理:Dcmtk与fo-dicom保存文件的不同设计模式之“同步VS异步”+“单线程VS多线程”

一.背景: 最近一直在做DCM相关的编程工作,以前项目使用C++居多,所以使用DCMTK开源库,而目前团队使用C#居多,所以需要转向使用fo-dicom库,由于前一篇专栏文章DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist在调试过程中需要对DIMSE信息进行手动保存,偶然间发现了dcmtk开源库与fo-dicom开源库在保存dcm文件时使用的方式差异很大,因此决定研究一下,期望通过对比分析来看一下孰优孰劣. 二.dcmtk与fo-dicom保存文件函数的源码剖析: