背景:

上一篇博文对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。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

由此说明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服务的本地回路数据包。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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)。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenNzdXJlcWg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

双击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三种网络连接模式的实际測试





作者:zssure@163.com

时间:2014-11-18

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

  1. DICOM医学图像处理:DIMSE消息发送与接收“大同小异”之DCMTK fo-dicom mDCM

    背景: 从DICOM网络传输一文开始,相继介绍了C-ECHO.C-FIND.C-STORE.C-MOVE等DIMSE-C服务的简单实现,博文中的代码给出的实例都是基于fo-dicom库来实现的,原因只 ...

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

    转载:http://blog.csdn.net/zssureqh/article/details/39213817 背景: 上一篇专栏博文中针对PACS终端(或设备终端,如CT设备)与RIS系统之间w ...

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

    背景介绍: 近期项目需求,须要使用C#进行最新的UI和相关DICOM3.0医学图像模块的开发.在C++语言下,我使用的是应用最广泛的DCMTK开源库,在本专栏的起初阶段的大多数博文都是对DCMTK开源 ...

  4. DICOM医学图像处理:Orthanc Plugin SDK实现WADO服务

    背景: Orthanc是博主发现的一个很完美的DICOM和HTTP服务端开源软件,前几篇分别介绍了Orthanc的基本使用.Orthanc从0.8.0版本之后给出了Plugin SDK,通过该SDK可 ...

  5. DICOM医学图像处理:WEB PACS初谈二,图像的传输

    背景: 如前一篇专栏博文所述,借助于CGI或FastCGI技术转发浏览器发送过来的用户请求,启动本地的DCMTK和CxImage库响应.然后将处理结果转换成常规图像返回到浏览器来实现Web PACS. ...

  6. [转]DICOM医学图像处理:Deconstructed PACS之Orthanc

    转载:http://blog.csdn.net/zssureqh/article/details/41424027 背景: 此篇博文介绍一个开源的.基于WEB的DICOM Server软件.该开源软件 ...

  7. DICOM医学图像处理:Deconstructed PACS之Orthanc

    背景: 此篇博文介绍一个开源的.基于WEB的DICOM Server软件.该开源软件完全使用C++编写,不依赖于第三方数据库(内置了SQLite数据库)或其他框架,支持RESTful API设计模式. ...

  8. DICOM医学图像处理:WEB PACS初谈四,PHP DICOM Class

    背景: 预告了好久的几篇专栏博文一直没有整理好,主要原因是早前希望搭建的WML服务器计划遇到了问题.起初以为参照DCMTK的官方文档wwwapp.txt结合前两天搭建的WAMP服务器可以顺利的实现WM ...

  9. DICOM医学图像处理:WEB PACS初谈

    背景: 周末看到了一篇原公司同事的文章,讲的是关于新的互联网形势下的PACS系统.正好上一篇专栏文章也提到了有想搭建一个worklist服务器的冲动,所以就翻箱倒柜将原本学生时代做课题时搭建的简易We ...

随机推荐

  1. SVN各种异常解决整理

    错误1:工作副本已锁定 由于周末公司server停机维护,今天在用SVN提交业务时,直接报错: 同一时候给了解决的方法:请运行清理命令 直接返回上级文件夹单击右键.运行清除命令后,再次提交! OK! ...

  2. 编写函数int count_number_string(char str[])和函数int maxnum_string(char str[])

    题目如图: 这里不再赘述 代码: //字符串中统计与查询 //杨鑫 #include <stdio.h> #include <stdlib.h> #include <st ...

  3. bzoj1924: [Sdoi2010]所驼门王的宝藏

    陈年老题又来水一发啊啊啊 构图狗了一点,然后其实强连通缩点dij找最长路就没了. 没调出来有点气,直接打了第9个点的表.... 来逛blog的你教教我呗 #include<cstdio> ...

  4. php面向对象之__isset和__unset

    php面向对象之__isset和__unset 一.简介 __isset和__unset都是对不可访问属性的操作,前者是检验的时候自动调用,后者是销毁的时候自动调用. 比如说在类外访问private的 ...

  5. WEEX SDK集成到工程(Integrate to Android) #25

    WEEX SDK集成到工程(Integrate to Android) #25 https://github.com/weexteam/article/issues/25

  6. Linux就该这么学 20181008(第十三章BIND)

    参考链接https://www.linuxprobe.com Bind提供域名解析服务 DNS Domin Name Server 域名解析服务 功能模式 .正向解析,将域名解析为IP地址 .反向解析 ...

  7. vue.js和node.js的认识

    首先vue.js 是库,不是框架,不是框架,不是框架. Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据. Vue.js 的核心是一个允许你 ...

  8. NLog日志记录

    配置NLog         NLog支持 .Net 4.5 以及以上版本!              首先去下载NLog的DLL下载地址:http://nlog-project.org/downlo ...

  9. form&method【POST~GET】

    <form.../>中method属性指定了该表单是以哪种方式提交请求,有两种方式:GET请求方式和POST请求方式,默认是GET请求方式.两种方式的区别:get方式的请求是在浏览器地址栏 ...

  10. 三种排序方法(c语言)

    #include "stdio.h" void main() {void read_data(int a[],int n); void write_data(int a[],int ...