背景:

上篇博文为引子,介绍了一款神奇的开源PACS系统——Orthanc。本篇开始解读官方Cookbook中的相关内容,对于简单的浏览、访问和上传请阅读前篇博文。在常规的PACS系统中还未出现对于DCM图像的修改和匿名化操作,因此此次重点介绍Orthanc利用REST API实现对DCM医学图像的修改(modification)和匿名化(anonymization)。对于官方Cookbook中的实例进行示范和调试,通过Orthanc源码分析确保示例在本机良好运行。注意:官方Cookbook中的示例在Windows下会有错误,详情见博文。

Orthanc介绍:

取名为Orthanc源自于J.R.R. Tolkien’s(托尔金)的小说。Orthanc是艾辛格(Isengard)要塞中的黑塔,初建于第二世纪,用于储存收纳南方王国的真知晶石——palantíri,一种圆形且能够看见远方的石头,透过palantíri可以跟远方使用palantíri的人进行交流。Orthanc Server正是取palantíri的此层含义,设计出一种可在整个医院DICOM拓扑网络中便捷、透明以及可编程访问医学图像的系统(可参照wiki百科的介绍:http://en.wikipedia.org/wiki/Isengard)。

另外,Orthanc中同时包含了“RTH“,即Radiotherapy。其实Orthanc本身源自于法国de Liège大学中心医院(Centre Hospitalier Universitaire)对于放射治疗服务的研究。

Orthanc之Modification & Anonymization

Anonymization:

Orthanc从0.5.0版本之后引入了对DICOM资源的匿名化操作,可对患者(patients)、检查(studies)、序列(series)和图像(instances)多个级别进行匿名化处理。为了方便示范,此处以instances级别为例进行介绍:

1)按照上篇博文上传两幅测试图像到Orthanc Server,如下图所示:

2)利用curl命令行查看一下上述两个instances,获取ID号,结果如下:

curl http://localhost:8042/instances

此处获取的instance ID号为:c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c

3)按照Orthanc官方Cookbook的说明,进行匿名化操作

输入指令:curl http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/anonymize -X POST -d '{}' > c:\orthanc-anonymize.dcm

但是并未获得如期结果,打开c盘发现orthanc-anonymization.dcm文件大小为0KB。开启curl的verbose模式,

curl –v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/anonymize -X POST -d '{}' > c:\orthanc-anonymize.dcm

查看输出信息如下:

发现Orthanc Server中HTTP 服务返回值为404

通过自己查看官方Cookbook给出的指令,除了对应instance的UID不同外,并未找到问题,暂且跳过,尝试一下Modification。

Modification:

1)上传DCM文件到Orthanc Server,同Anonymization中相同;

2)利用curl http://localhost:8042/instances获取指定instance的ID号;

3)参照官方Cookbook进行Modification处理

输入如下指令,此次为了方便,直接使用curl的verbose模式:

curl –v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/modify –X POST –d ‘{"Replace”:{"PatientName”:"hello”,"PatientID”:"world”}}' >c:\orthanc-modify.dcm

输出结果如下:

目前为止,参照Orthanc官方的Cookbook说明,给出的两个示例都在本机无法顺利完成。因此猜测官网中给出的代码有可能是Linux系统的,在Windows系统下应该做出适当的调整,但是该怎样调整呢?该调整哪一部分呢?请继续往下看……

调试Orthanc官方Cookbook示例:

0)Orthanc REST API资料查询:

在调试之前,我们先要搞清楚出现问题的大致原因,排除一些常见的错误,比如软件版本错误、指令拼写错误等等。上面介绍的Anonymization和Modification都是利用了Orthanc的REST API功能,那么Orthanc各版本对于REST API的支持程度如何呢?我们查看一下官方的说明,如下图所示:

从上图可以看出,Orthanc从0.5.0版本之后就支持多级别的修改和匿名化操作,如上一篇博文所述,我本机安装的是最新的0.8.5版本。因此可以确保软件版本无误,另外在上述示例仿真过程中我们也对比排查了指令拼写错误。

接下来使出我们的杀手锏吧:“启动C:\Orthanc-0.8.5\Orthanc.sln工程,进入调试模式,查看Orthanc的源码”。打开Orthanc.sln解决方案,右键Orthanc工程开启调试模式,在关于REST API的几个核心类中插入断点,初次尝试插入的断点如下:

1)Anonymization源码调试:

重新按照上一节中的步骤,首先利用Orthanc Explorer向调试模式下的Orthanc Server添加DICOM文件,此时直接按F5跳过调试,因为图像加载过程中我们并未遇到问题。(此步操作必须重新添加,因为调试模式下数据的存储目录是C:\Orthanc-0.8.5\OrthancStorage,与二进制安装包默认的C:\OrthancStorage不同,上一节中我们添加的图像在调试状态下是看不到的

输入指令查看ID:

curl http://localhost:8042/instances

开始输入上一节的Anonymization指令:

curl -v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/anonymize -X POST -d '{}' > c:\orthanc-anonymize.dcm

Orthanc工程首次停在了断点RestApi.cpp中的Visit函数内,如下图所示:

利用F11单步调试,随后进入到解析Anonymization请求操作的函数ParseAnonymizationRequest内部,可以看到在该函数内给出了一个示例与我们输入的格式相同

继续单步调试,最后发现在解析Json格式的AnonymizationRequest指令,即我们输入的'{}’,json_reader.cpp中的readToken返回值为tokenError

至此想必我们找到了Anonymization指令出错的原因的:输入的Json格式不正确,虽然我们是按照Orthanc官方的Cookbook来进行的。为了确定Json格式是否有误,在在线Json格式检查网站(http://www.bejson.com/)测试一下,结果为:

按照提示,去掉指令中Json部分的单引号,输入:

curl -v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/anonymize -X POST -d {} > c:\orthanc-anonymize.dcm

curl调试输出的结果为:

利用DICOM看图软件,打开可以发现orthanc-anonymize.dcm文件中的患者姓名已经被隐藏掉了。

【总结】:正确的指令应该是外边不添加单引号,如下所示:

curl -v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/anonymize -X POST -d {} > c:\orthanc-anonymize.dcm

2)Modification源码调试:

既然已经找到了Anonymization中代码出错的问题,让我们去掉Modification中的单引号,尝试一下输入如下指令:

curl -v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/modify -X POST -d {"Replace":{"PatientName":"hello","PatientID":"world"}} >c:\orthanc-modify.dcm

令我们失望的是依然看到了HTTP Server返回的404错误

由于Modification指令中单引号内部还存在着更多的双引号。根据上次的经验,有可能还是Json格式输入输入错误。让我们只保留json_reader.cpp中的readToken断点,直接查看一下解析结果是否是tokenError?重新输入指令,进入到readToken内部,发现函数依然返回tokenError,结果如下图所示:

利用VS自带的查看工具,我们可以看到readToken函数解析的字符串current_,其真实内容是:{Replace:{PatientName:hello,PatientID:world}},其中并未看到我们输入的双引号,将{Replace:{PatientName:hello,PatientID:world}}输入到http://www.bejson.com/中,也得到了错误的结果提示:

这说明我们在命令行中输入的Json指令中的双引号,在被VS读入过程中被忽略了。那么我们利用转义字符将双引号传递进入,输入指令:

curl -v http://localhost:8042/instances/c77324ec-f5e76fc5-c96846bf-2ed4097d-86f9e79c/modify -X POST -d {\"Replace\":{\"PatientName\":\"hello\",\"PatientID\":\"world\"}} >c:\orthanc-modify.dcm

查看结果:

最终运行输出为,

在DCM看图软件中打开orthanc-modify.dcm,可以看到PatientID和PatientName已经修改。

至此,关于Orthanc Modification和Anonymization的调试已经顺利完成,可以松一口气啦,还是调试源代码给力啊^_^。

知识点补充:

Orthanc作为开源项目,获取其源码自然是轻而易举。虽然号称轻型Server系统,但是代码量还是足以吓退大多数人的。初次面对海量的代码无从下手进行调试,下面以上述调试Orthanc官方Cookbook中的Anonymization和Modification示例过程为例,讲解一下如何开始调试Orthanc。

1)如何调试Orthanc中的Http Server

之所以上一节最开始将断点设置在了RestXXX.cpp文件中,是因为本博文中的介绍的Modification和Anonymization使用的是Orthanc提供的REST API服务,因此首先推测错误应该出现在REST API的相关实现函数中。这种方法可以顺利的解决我们上面遇到的问题,并且如你所见我们已经实现了问题的排查。

但是既然调试进入了Orthanc的源码内,就顺道儿搞清楚Orthanc中Http Server的整体流程,也顺便找找究竟是在哪一个地方将curl指令中的双引号忽略的。 再一次输入指令,进入调试状态。断点第一次停在RestApi.cpp中的Visit函数处,在前一节中我们利用“单步调试”顺利的逐步进入到了JSON的解析函数readToken内,“单步调试”是向前追溯的最佳手段,也是VS提供给我们的最直观最有利的错误排查工具。但是为了要了解整个流程,我们此处需要“回溯”,那么VS提供给我们逆流而上的工具是什么呢?那就是“查找所有引用”,如下图所示:

我们可以由RestApi.cpp 转到上一级,即RestApiHierarchy.cpp中的LookupResource函数,如此迭代下去相信可以回溯到整个流程的最顶端。这种方法虽然笨拙了一些,但是比较实用。想必在Windows编程环境下大家还是更喜欢“可视化”的直观操作,即所见即所得。那么单击菜单栏中的“调试”,选择“窗口”中的“调用堆栈”,可以直观的看到在RestApi.cpp中的Visit函数之前的各种函数调用顺序,如下图所示:

至此我们可以看到整个Http Server服务的起始端是mongoose.cpp中的worker_thread函数(在“调用堆栈”中相关函数右键选择“转到源码”可以查看函数的具体位置)。由上图中“调用堆栈”的顺序我们已经可以清晰的看到Orthanc Http Server的整个调用流程。那么我们在worker_thread函数中插入断点,重新输入curl指令,查看一下在整个流程的起始状态下,Orthanc Http Server接收到的数据体是什么格式?如下图所示:

在process_new_connection函数内部读取curl发出的POST请求指令时,连接缓存buf的内容中已经不存在双引号了,因此可以确定curl的-d参数在发送JSON格式数据到Orthanc的Http Server时忽略了双引号。后续可以研究一下curl在windows环境下的使用,尤其是-d参数的设置

2)如何调试Orthanc中的DICOM Server

由于DICOM Server比较熟悉,先验知识比较多,因此调试起来比HTTP Server容易。在Orthanc的main函数中我们可以看到httpServer.Start()和dicomServer.Start(),dicomServer.Start()就是DICOM Server的入口点,由于Orthanc是基于DCMTK开发的,因此后续的流程应该是交由DCMTK来完成的,更详细的细节可参考本专栏前面的DCMTK网络系列文章。预告一下下篇博文会详细介绍利用fo-dicom开源库打造一个简单的DICOM Server服务端,那时再详细的对比分析Orthanc中的DICOM Server,本篇暂且到此为止。

参考资料:

https://code.google.com/p/orthanc/wiki/OrthancCookbook,Cookbook官网链接

https://code.google.com/p/orthanc/wiki/Anonymization,Orthanc的Modification和Anonymization介绍

https://docs.google.com/spreadsheet/pub?key=0Ao5aRMxCX2hldEJadzVUaWFmNW5QTWhrYTI3UHMzdXc&single=true&gid=8&output=html,REST API支持图谱

https://docs.google.com/spreadsheet/pub?key=0Ao5aRMxCX2hldEJadzVUaWFmNW5QTWhrYTI3UHMzdXc&single=true&gid=0&output=html,REST API支持图谱

http://curl.haxx.se/docs/manpage.html,curl中参数介绍

后续专栏博文预告:

fo-dicom搭建简单的DICOM Server

 

 

作者:zssure@163.com

时间:2014-11-29

DICOM医学图像处理:Deconstructed PACS之Orthanc,Modification & Anonymization的更多相关文章

  1. DICOM医学图像处理:深入剖析Orthanc的SQLite,了解WADO & RESTful API

    背景: 上一篇博文简单翻译了Orthanc官网给出的CodeProject上“利用Orthanc Plugin SDK开发WADO插件”的博文,其中提到了Orthanc从0.8.0版本之后支持快速查询 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. BZOJ 2721: [Violet 5]樱花

    (X-N)(Y-N)=N^2 #include<cstdio> using namespace std; const int mod=1e9+7; int n,cnt,isprime[10 ...

  2. PYday15--面向对象的进阶:集成、成员、方法、异常处理

    1.继承 实例: 2.构造方法: 3.反射:以字符串的形式去模块操作其成员. 成员: 最外层是文件,文件里面包含类,通过类可以创建对象,对象可以封装字段和指针.类里面可以有方法,指针可以指向方法. 通 ...

  3. [转载]ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/) 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引 ...

  4. dubbo控制台在tomcat上的部署

    1.下载dubbo-admin的war包,比如dubbo-admin-2.5.4.war 2.因为在tomcat上部署,所以务必确认安装了JDK和tomcat,以及配置好了环境变量. 3.将dubbo ...

  5. cobbler 安装centos7.3时GPT问题(五)

    磁盘分区表MBR和GPT介绍: MBR(Master Boot Record):最大只支持2 TB的盘,最多只支持4个主分区,信息只存储在一个区域. GPT(GUID partition table) ...

  6. 聊聊、Highcharts 动态数据

    最近项目中需要用到图表,找了几个开源框架,最后选择 Highcharts,原因是 Highcharts 功能强大,稳定,方便,而且开源,社区比较成熟. 首先下载 Highcharts,导入项目. 在 ...

  7. 浅析 Node.js 的 vm 模块以及运行不信任代码

    在一些系统中,我们希望给用户提供插入自定义逻辑的能力,除了 RPC 和 REST 之外,运行客户提供的代码也是比较常用的方法,好处是可以极大地减少在网络上的耗时.JavaScript 是一种非常流行而 ...

  8. ICPC南京补题

    由于缺的题目比较多,竟然高达3题,所以再写一篇补题的博客 Lpl and Energy-saving Lamps During tea-drinking, princess, amongst othe ...

  9. linux 系统时间调整

    linux的硬件时间是从COMS中读取的. 系统时间是由操作系统维护的. 先查看时区是否正确 (东八区 +8) #date -R 选择时区: #tzselect 修改了系统时间,还应该跟硬件时间进行同 ...

  10. AWK 用法

     awk 用法:awk ' pattern {action} ' 变量名 含义 ARGC 命令行变元个数 ARGV 命令行变元数组 FILENAME 当前输入文件名 FNR 当前文件中的记录号 FS ...