2019独角兽企业重金招聘Python工程师标准>>>

背景:

Orthanc是博主发现的一个很完美的DICOM和HTTP服务端开源软件,前几篇分别介绍了Orthanc的基本使用。Orthanc从0.8.0版本之后给出了Plugin SDK,通过该SDK可以利用Orthanc内建的REST API实现WADO服务,下面就参照官网给出的说明介绍一下如何使用SDK实现WADO服务,并且对官网的实例进行更新,采用最新的方式直接实现WADO服务。

官方说明中文翻译:

1)简介

DICOM标准定义了文件格式以及医学影像网络传输协议。WADO,即Web Access to DICOM Persistent Objects,是DICOM3.0标准中制定的一种基于网络web服务访问医学图像的协议(具体在DICOM3.0第18部分)。通过WADO协议,专业的医生可以使用常见的浏览器(目前Orthanc貌似不支持IE)预览和下载医学图像。

本博文所附代码给出了一个实现简单WADO服务的示例。该示例可以返回原始的DICOM图像,或者JPEG格式图像;并可以作为Orthanc的插件来运行。借助于Orthanc的框架,可以通过简单的几行代码实现WADO服务。

2)背景:

Orthanc是一款开源的、轻型的、独立的,并支持脚本化的DICOM服务端。Orthanc主要用来精简临床就医流程和简化医学图像的管理。另外通过兼容常见的JSON、PNG格式和RESTful API,使得DICOM标准在计算机图像领域得到更广泛的应用。Orthanc隐藏了DICOM文件格式和DICOM协议的复杂性,因此医院普通的网络管理人员以及专业的医学图像自动分析软件开发人员都可以使用。Orthanc可以作为一个健壮的医学影像处理中心,为各个医院提供服务。

从0.8.0(2014 7月份发布)开始,Orthanc给外部开发人员 提供了插件开发SDK。利用SDK开发的动态库形式的插件可以被导入到Orthanc服务中,插件通过注册回调函数来响应浏览器的HTTP请求。回调函数反过来可以访问Orthanc数据库提取目标DICOM文件的信息。Orthanc Plugin SDK以C语言头文件形式给出,链接如下:https://code.google.com/p/orthanc/source/browse/Plugins/OrthancCPlugin/OrthancCPlugin.h?name=Orthanc-0.8.0,说明文档:http://www.codeproject.com/KB/webservices/797118/OrthancPluginDocumentation.zip

3)DICOM 和 WADO

本小节只概括介绍WADO协议,详细介绍参见DICOM3.0标准的第18部分。

DICOM协议里规定了如下标准:一个患者(Patient)可以做多次检查(Studies)。每一个检查(Study)包含一系列医学图像,即序列(Series)。举个例子:标准的PET-CT检查(Study)会包含两组序列,CT 序列和PET 序列。序列中通常对应人体的二维/三维/四维影像。每种影像会被分割成多个文件存储,即Instance(也就是我们看到的包含单幅图像的单个后缀为DCM的文件)。

通常,一个DICOM实例(Instance)可以看做是二维图像与存储了患者元信息(人口统计学信息,如姓名、年龄、身高、体重等等)结构的组合。患者元信息通常是包含了DICOM标签对应值的数组。每个标签由两个十六进制数表示。非常重要的是,每一级的检查(Study)、序列(Series)和图像(Instance)要求全局唯一。

例如(0x0020,0x000d)代表的是Study Instance UID,定义检查(Study)的唯一性;

…………

一个WADO请求就是一个简单的HTTP GET请求,请求中包含了Study、Series和Instance标识符。例如:

http://localhost/wado?studyUID=1.2.840.113845.11.1000000001951524609.20121203131451.1457891&seriesUID=1.2.840.113619.2.278.3.262930758.589.1354512768.115&objectUID=1.2.840.113619.2.278.3.262930758.589.1354512768.116.1&requestType=WADO

该WADO请求的响应会是与studyUID/seriesUID/objectUID对应的DICOM图像的JPEG格式。如果希望直接获取DICOM格式文件,应在WADO请求中添加contentType=application%2Fdicom,如下所示:

http://localhost/wado?studyUID=1.2.840.113845.11.1000000001951524609.20121203131451.1457891&seriesUID=1.2.840.113619.2.278.3.262930758.589.1354512768.115&objectUID=1.2.840.113619.2.278.3.262930758.589.1354512768.116.1&contentType=application%2Fdicom&requestType=WADO

官方说明就简单的翻译到这里,下面采用结合具体事例的方式来进行。

Orthanc WADO Plugin的编辑及使用:

该示例代码依赖于下面四部分:Orthanc Plugin SDK(0.8.0版本之后);CImg Library(用于将DICOM图像转换成PNG格式);JsonCpp库,用于解析Orthanc服务返回的Json格式的文件;CMake,用于编译源码。

1)Orthanc WADO Plugin的编译:

下载官方说明中的源码(http://www.codeproject.com/KB/webservices/797118/WadoPluginSources.zip),解压后按照README.txt中的说明编译安装Orthanc WADO Plugin:

第一步:进入cmd命令行模式,创建编译目录,输入指令:mkdir Build

第二步:进入Build目录

第三步:启动Cmake,开始编译,输入cmake ..\WadoPluginSources(注:这里..意思是返回WadoPluginSources源码中CmakeList.txt所在的目录,README.txt中的写法是错误的

第四步:打开Build目录下的WadoPlugin.sln工程,利用VS进行编译,会在Build\Debug目录下看到WadoPlugin.dll,说明WADO插件生成成功。

2)Orthanc WADO Plugin的安装:

源码包中README.txt给出的安装说明有误,应该将WadoPlugin.dll全路径名添加到Configuration.json文件中Plugin对应的字段内,如下图所示:

注意:在Windows系统中输入的WadoPlugin.dll的路径应该使用上图中的【/】,或者输入"c:\\WadoPluginSources\\Build\\Debug\\WadoPlugin.dll”。否则会出现错误。

3)Orthanc WADO Plugin启动:

修改完Configuration.json文件后,准到Orthanc.exe所在目录,例如我本机为:C:\Orthanc-0.8.5\Debug>Orthanc.exe ../../Orthanc/Configuration.json。【注意:后面跟的是添加了WadoPlugin.dll的Configuration.json的路径,如果输入Orthanc.exe --config=Configuration.json,是生成默认Configuration.json的结果,而并不会启动WadoPlugin服务)。

4)实例测试:

按照前几篇博文方式,上传两幅测试图像,结果如下:

其中已知test1的各级UID为:

StudyInstanceUID=1.3.6.1.4.1.30071.6.176694098609799.4240639413125000;

SeriesInstanceUID=1.3.6.1.4.1.30071.6.176694098609799.4240639413125000.1;

SOPInstanceUID=2.16.840.114421.81623.9430067258.9493139258;

构造WADO请求,查询test1图像,请求连接为:http://localhost:8042/wado?studyUID=1.3.6.1.4.1.30071.6.176694098609799.4240639413125000&seriesUID=1.3.6.1.4.1.30071.6.176694098609799.4240639413125000.1&objectUID=2.16.840.114421.81623.9430067258.9493139258&requestType=WADO

浏览器结果如下所示,与test1.dcm原文件相同。

新版Orthanc WADO Plugin:

1)官方说明:

官方说明中有这样一段:(http://www.codeproject.com/Articles/797118/Implementing-a-WADO-Server-using-Orthanc)

当从WADO HTTP请求中解析出study/series/instance标识符后,需要在Orthance数据库中进行查询。为了实现查询定位,官方博文中给出的代码实例直接借用了Orthanc内建的RESTful API服务(而不是直接响应WADO HTTP 请求)。

首先需要定位study级,代码如下:

static bool LocateStudy(Json::Value& study,const std::string& studyUID)
{// Retrieve the list of the studies that are stored in OrthancJson::Value listOfStudies;if (!OrthancContext::GetInstance().RestApiDoGet(listOfStudies, "/studies")){return false;}// Retrieve information about each of these studiesfor (Json::Value::ArrayIndex i = 0; i < listOfStudies.size(); i++){std::string studyUri = "/studies/" + listOfStudies[i].asString();if (OrthancContext::GetInstance().RestApiDoGet(study, studyUri)){// If the "StudyInstanceUID" of this study matches, we are doneif (study["MainDicomTags"]["StudyInstanceUID"].asString() == studyUID){return true;}}}return false;
}

LocateStudy函数内部先构造出/studies形式的RESTful API的uri请求,查询出Orthanc中的所有study的UUID,然后再循环遍历每一个获得的studyUUID,构造出/studies/{id}形式的RESTful API请求,逐个对比返回JSON结果中的StudyInstanceUID标签,实现study定位;

其次定位sereis级,代码如下:

static bool LocateSeries(Json::Value& series,const Json::Value& parentStudy,const std::string& seriesUID)
{// Loop over the child series of the located studyconst Json::Value& listOfSeries = parentStudy["Series"];for (Json::Value::ArrayIndex j = 0; j < listOfSeries.size(); j++){std::string seriesUri = "/series/" + listOfSeries[j].asString();// If the "SeriesInstanceUID" of this series matches, we are doneif (OrthancContext::GetInstance().RestApiDoGet(series, seriesUri) &&series["MainDicomTags"]["SeriesInstanceUID"].asString() == seriesUID){return true;}}return false;
}

与study级类同;

最后是Instance级,代码如下:

static bool LocateInstance(Json::Value& instance,const Json::Value& parentSeries,const std::string& objectUID)
{// Loop over the child instances of the located seriesconst Json::Value& listOfInstances = parentSeries["Instances"];for (Json::Value::ArrayIndex k = 0; k < listOfInstances.size(); k++){std::string instanceUri = "/instances/" + listOfInstances[k].asString();// If the "SOPInstanceUID" of this series matches "objectUID", we are doneif (OrthancContext::GetInstance().RestApiDoGet(instance, instanceUri) &&instance["MainDicomTags"]["SOPInstanceUID"].asString() == objectUID){return true;}}return false;
}

上述定位流程复杂,从0.8.0版本之后Orthanc提供了直接访问数据库中DICOM索引的函数,OrthancPluginLookupPatient(),OrthancPluginLookupStudy(), OrthancPluginLookupStudyWithAccessionNumber(), OrthancPluginLookupSeries()and OrthancPluginLookupInstance()。利用该类函数就需不要先定位study、再定位series、最后定位instance如此繁琐了,修改后的代码如下:

//2014-12-07:zssure
//利用新的Orthanc插件的接口,直接定位Instance
//http://www.codeproject.com/Articles/797118/Implementing-a-WADO-Server-using-Orthanc
static bool LocateInstance(Json::Value& instance, const std::string& objectUID)
{char* instanceId = OrthancPluginLookupInstance(OrthancContext::GetInstance().GetContext(), objectUID.c_str());if (instanceId == NULL){return false;}std::string instanceUri = "/instances/" + std::string(instanceId);OrthancPluginFreeString(OrthancContext::GetInstance().GetContext(), instanceId);return (OrthancContext::GetInstance().RestApiDoGet(instance, instanceUri) &&instance["MainDicomTags"]["SOPInstanceUID"].asString() == objectUID);
}
//zssure:end

2)新版Wado Plugin修改:

按照官方的说明Orthanc Plugin SDK是以C头文件格式给出,因此直接利用Orthanc-0.8.5中的OrthancCPlugin.h文件替换掉WadoPluginSources中的OrthancCPlugin.h后,发现WadoPlugin.cpp中我们新添加的LocateInstance函数中的GetContext()无法识别:

打开OrthancContext.h文件发现,文件中并不存在GetContext()函数,因此需要手动添加公有函数:

public:
OrthancPluginContext* GetContext()
{
return context_;
}

修改完成后可以识别GetContext()函数了,但是编译后出现如下错误:

将#include "../../Resources/ThirdParty/VisualStudio/stdint.h"代码修改为#include "stdint.h"后即可消除上述错误。重新生成后可获得新版WadoPlugin.dll插件。重新输入WADO Request,得到测试结果如下:

至此Orthanc WADO Plugin的开发就讲解完成了。

后续博文介绍:

fo-dicom搭建简单的DICOM Server






作者:zssure@163.com

时间:2014-12-10

转载于:https://my.oschina.net/zssure/blog/354784

DICOM医学图像处理:Orthanc Plugin SDK实现WADO服务相关推荐

  1. DICOM医学图像处理:二零一四▪DICOM专栏一览

    题记 二零一四刚过,新年伊始就发生了"外滩踩踏"恶性事件,告诫我们要珍爱生命,为自己更为家人-- 回顾去年,有些许收获.有些许感慨-- 曾经听过一个段子说两个在公司工作多年的老员工 ...

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

    2019独角兽企业重金招聘Python工程师标准>>> 一.背景: 最近一直在做DCM相关的编程工作,以前项目使用C++居多,所以使用DCMTK开源库,而目前团队使用C#居多,所以需 ...

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

    背景: 本专栏"DICOM医学图像处理"受众较窄,起初只想作为自己学习积累和工作经验的简单整理.前几天无聊浏览了一下,发现阅读量两极化严重,主要集中在"关于BMP(JPG ...

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

    背景: 续上篇,继续介绍如何将多幅JPG图像数据存入DCM文件.即将有损压缩数据直接写入DCM文件,存储为Multi-frame形式. 多幅JPG图像数据存入DCM文件: 为了避免引起歧义,这里着重说 ...

  5. 【转】DICOM医学图像处理:DICOM网络传输

    背景: 专栏取名为DICOM医学图像处理原因是:博主是从医学图像处理算法研究时开始接触DICOM协议的.当初认识有局限性,认为DICOM只是一个简单的文件格式约定,简而言之,我当时认为DICOM协议就 ...

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

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

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

    背景: 上篇博文为引子,介绍了一款神奇的开源PACS系统--Orthanc.本篇开始解读官方Cookbook中的相关内容,对于简单的浏览.访问和上传请阅读前篇博文.在常规的PACS系统中还未出现对于D ...

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

    转自:https://www.cnblogs.com/mfrbuaa/p/4004114.html 有修订 背景介绍: 近期项目需求,需要使用C#进行最新的UI和相关DICOM3.0医学图像模块的开发 ...

  9. DICOM医学图像处理:BMP转DCM、DCM转BMP、多张BMP转DCM、JPG转DCM,,多张JPG转DCM。

    使用DCMTK库实现BMP转DCM的互相转换以及JPEG转DCM.使用DCMTK库其中在编译的时候错了好几次,在这有编译好的库给大家分享在此附上连接只需要1积分(DCMTK编译好的库-C/C++其他资 ...

  10. 【转】DICOM医学图像处理:基于DCMTK工具包学习和分析worklist

    转自:https://blog.csdn.net/zssureqh/article/details/38775315 背景: DICOM3.0协议中有介绍关于worklist的部分.简而言之,work ...

最新文章

  1. ​【安全牛学习笔记】WPS及其他工具WPS
  2. Nginx虚拟机主机根据不同的域名使用不同的root路径
  3. docker快速入门教程
  4. 将地址转换为链接的正则表达式(regex url href)
  5. 利用百度的词法分析区分数据
  6. jzoj5354-导弹拦截【dp,最大匹配,最少路径覆盖】
  7. 一次频繁Full GC的排查过程,根源居然是它...
  8. 【渝粤教育】国家开放大学2019年春季 3896人文英语1 参考试题
  9. python 子串是否在字符串中_python七种方法判断字符串是否包含子串
  10. java导出excel_纯干货:Java开源报表工具JasperReport使用
  11. CCIE学习(40)—— OSPF设计与LSA类型(三)
  12. NVIDIA GPU简史、命名规则及基础知识
  13. 连续优化、离散优化、组合优化、整数优化和凸优化
  14. html 半个字符,半角字符什么意思
  15. 将图片转换成caffe的数据格式
  16. 零时科技:DeFi 项目 Lendf.Me 遭黑客攻击复盘分析
  17. 合伙开公司要如何规避风险
  18. PZT-JH20/8高压电极化装置(20KV以下压电陶瓷同时极化1-8片)
  19. 你们中国人真TM假,微信居然能撤回…
  20. bzoj 2844 albus就是要第一个出场

热门文章

  1. [iOS] 使用xib做为应用程序入口 with Code
  2. ViewModel中C# Property自动添加OnPropertyChanged处理的小工具, 以及相应Python知识点...
  3. centOS 安装远程桌面
  4. c#textBox控件限制只允许输入数字及小数点
  5. x86汇编语言复习笔记
  6. jmeter无法启动的解决办法
  7. PHP error_log 新认知
  8. JAVA设计模式之3-抽象工厂模式
  9. JQuery淡入淡出 banner切换特效
  10. 让Apache日志不记录图片等指定扩展名文件的设置方法