DICOM:基于DCMTK实现C-FIND SCU
来源:互联网 发布:mac内置麦克风没声音 编辑:程序博客网 时间:2024/06/04 19:26
背景:
专栏之前写过许多关于DICOM协议的相关文章,有关于概念解析的理论性文章,也有实例演示的应用性文章。目的只有一个,希望能引导大家快速掌握DICOM协议,并着手进行自定义化开发。
目前DICOM协议实现有多种开源库,例如基于C++的DCMTK、基于C#的fo-dicom、基于Java的dcm4che。由于时间关系博文中的相关实例演示经常会穿插着使用三种开源库,因此具体到某一种库可能博文中并未给出示范工程。例如,近期有网友咨询希望利用DCMTK开源库自己动手实现C-FIND查询请求,并对服务端返回的信息进行定制化处理。因此周末动手编写了一个极简版的示例,代码裁剪于DCMTK开源库的findscu工程,供大家交流学习。
准备知识:
为了更好的理解代码示例,请耐心阅读之前专栏里的相关文章,如果已经对DICOM协议很了解且有过开发经验,或者干脆就想先动手敲代码,想从实践中学习,那么请自行跳到下一节。
在开始工作之前先阅读DICOM医学图像处理:DICOM网路传输了解DICOM协议的含义以及简单的建立规则,随后阅读DICOM医学图像处理:全面解析DICOM3.0标准中的通讯服务模块和DICOM:DICOM3.0网络通信协议(续)进一步了解DICOM协议,以及熟悉DCMTK开源库中对DICOM协议的具体实现。阅读完上述理论概念性文章后,进一步浏览下面两篇实例演示博文DICOM医学图像处理:基于DCMTK工具包学习和分析worklist、DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist 。
DCMTK实现C-FIND SCU:
待一切先验知识储备完成后,就可以进入我们的正题了,网友的需求是:
在阅读DICOM医学图像处理:基于DCMTK工具包学习和分析worklist、DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist 两篇实例博文后,希望利用DCMTK尝试发送C-FIND-RQ请求,然后将返回的C-FIND-RSP消息进行解析和后处理。
经过上述【准备知识】阶段后,想必大家已经了解了C-FIND请求建立的正题过程,因此不罗嗦了直接贴代码,用一个简单的实例来进行实际讲解。
a)网络环境初始化
//1)初始化网络环境 WSAData winSockData; /* we need at least version 1.1 */ WORD winSockVersionNeeded = MAKEWORD( 1, 1 ); WSAStartup(winSockVersionNeeded, &winSockData);
b)DCMTK库初始化
//2)DCMTK环境监测 if(!dcmDataDict.isDictionaryLoaded()) { printf("No data dictionary loaded, check environment variable\n"); }
c)建立DUL连接
//3)网络层ASC初始化 T_ASC_Network* cfindNetwork=NULL; int timeout=50; OFCondition cond=ASC_initializeNetwork(NET_REQUESTOR,0,timeout,&cfindNetwork); if(cond.bad()) { printf("DICOM 底层网络初始化失败\n"); return -1; } //4)创建底层连接,即TCP层 T_ASC_Association* assoc=NULL; T_ASC_Parameters* params=NULL; DIC_NODENAME localHost; DIC_NODENAME peerHost; OFString temp_str; cond=ASC_createAssociationParameters(¶ms,maxReceivePDULength); if(cond.bad()) { printf("DCMTK创建连接失败\n"); return -2; }
d)判别连接
//5)设置DICOM相关属性,Presentation Context ASC_setAPTitles(params, ourTitle, peerTitle, NULL); cond = ASC_setTransportLayerType(params, false); if (cond.bad()) return -3; gethostname(localHost, sizeof(localHost) - 1); sprintf(peerHost, "%s:%d", peer, OFstatic_cast(int, port)); ASC_setPresentationAddresses(params, localHost, peerHost); cond=ASC_addPresentationContext(params,1,abstractSyntax,transferSyntaxs,transferSyntaxNum); if(cond.bad()) return -4; //6)真正创建连接 cond=ASC_requestAssociation(cfindNetwork,params,&assoc); if (cond.bad()) { if (cond == DUL_ASSOCIATIONREJECTED) { T_ASC_RejectParameters rej; ASC_getRejectParameters(params, &rej); DCMNET_ERROR("Association Rejected:" << OFendl << ASC_printRejectParameters(temp_str, &rej)); return -5; } else { DCMNET_ERROR("Association Request Failed: " << DimseCondition::dump(temp_str, cond)); return -6; } } //7)判别返回结果 //7.1)连接检验阶段,验证Presentation Context if(ASC_countAcceptedPresentationContexts(params)==0) { printf("No acceptable Presentation Contexts\n"); return -7; } T_ASC_PresentationContextID presID; T_DIMSE_C_FindRQ req; T_DIMSE_C_FindRSP rsp; DcmFileFormat dcmff; presID=ASC_findAcceptedPresentationContextID(assoc,abstractSyntax); if(presID==0) { printf("No presentation context\n"); return -8; }
e)发送C-FIND-RQ
//8)发起C-FIND请求 //8.1)准备C-FIND-RQ message bzero(OFreinterpret_cast(char*,&req),sizeof(req));//内存初始化为空; strcpy(req.AffectedSOPClassUID,abstractSyntax); req.DataSetType=DIMSE_DATASET_PRESENT; req.Priority=DIMSE_PRIORITY_LOW; //设置要查询的信息为空时,待会儿查询结果中会返回 DcmDataset* dataset=new DcmDataset(); InsertQueryItems(dataset,"A^B^C"); //赋值自定义的回调函数,这就是该回调函数中可以进行相关信息的操作 ZSCFindCallback zsCallback; DcmFindSCUCallback* callback=&zsCallback; callback->setAssociation(assoc); callback->setPresentationContextID(presID); /* as long as no error occured and the counter does not equal 0 */ cond = EC_Normal;
f)设置回调函数,进行自定义处理
class ZSCFindCallback:public DcmFindSCUCallback{public: ZSCFindCallback() { } ~ZSCFindCallback() { } void callback( T_DIMSE_C_FindRQ *request, int responseCount, T_DIMSE_C_FindRSP *rsp, DcmDataset *rspMessage );};
g)获取C-FIND-RSP
while (cond.good()) { DcmDataset *statusDetail = NULL; /* complete preparation of C-FIND-RQ message */ req.MessageID = assoc->nextMsgID++; /* finally conduct transmission of data */ cond = DIMSE_findUser(assoc, presID, &req, dataset, progressCallback, callback, DIMSE_BLOCKING, timeout, &rsp, &statusDetail); //设置了查询采用阻塞模式,DIMSE_BLOCKING //设置连接超时为50 /* *添加异常判别 * */ cond=EC_EndOfStream;//假设异常,返回 }
实例测试:
参照之前DICOM医学图像处理:基于DCMTK工具包学习和分析worklist、DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist博文中的介绍进行测试即可,具体细节不多说,简单介绍一下:
启动Worklist SCP:
按照之前博文介绍,构建worklist数据库,在命令行输入:
wlmscpfs.exe -d -dfr -dfp ./wlistdb 2234
看到以下结果,说明顺利启动worklist服务端。
启动C-Find SCP:
在VS环境下,直接运行dumpCFindResponse工程,看到如下结果:
至此,自己构建的C-Find SCU顺利实现了发送C-FIND-RQ,并自定义处理C-FIND-RSP的目的。
PS:这里只是简单的给出了一个示范,要实际开发自己的C-FIND SCU和C-FIND SCP时需要考虑更多的细节,诸如PresentationContext、TransferSyntax等等。
示例工程下载:
【GitHub:】 dumpCFindResponse
【Baidu:】 dumpCFindResponse
【CSDN:】 dumpCFindResponse资源下载
作者:zssure@163.com
时间:2015-03-28
- DICOM:基于DCMTK实现C-FIND SCU
- dicom文件的显示(基于dcmtk实现)
- dicom文件的显示(基于dcmtk实现)
- dicom文件的显示(基于dcmtk实现)
- dicom文件的显示(基于dcmtk实现)
- 基于DCMTK的DICOM相关程序编写攻略
- 基于DCMTK的DICOM相关程序编写攻略
- 基于DCMTK的DICOM相关程序编写攻略
- VS2010添加DCMTK库,并实现Echo SCU
- DCMTK实现Dicom CT图片读取CT值图像
- 用fo-dicom实现print scu的注意事项
- dicom cfind scu
- DICOM cmove scu
- DICOM医学图像处理:基于DCMTK工具包学习和分析worklist
- 基于DCMTK的DICOM医学图像显示及其调窗方法研究
- 使用DCMTK存储Dicom rt文件
- 【学习DCMTK】VC读取dicom图像
- 1 用dcmtk库解释dicom数据
- 网页课程内容回顾(HTML)
- hdu 1023 Train Problem II(java+卡特兰数)
- 第一次部署oschina的源码,小经验
- OS里关于函数调用机制
- 嵌入式系统概述
- DICOM:基于DCMTK实现C-FIND SCU
- 黑马程序员《常用对象API string类 stringbuffer、stringBuilder》
- [LeetCode 22]Generate Parentheses
- 乐视市值是360两倍说明啥:卖水模式终结 生态战开打
- [LeetCode 90]Subsets II
- Android Tv app 与 mobile app 界面呈现的区别
- [LeetCode 78]Subsets
- WEB工工程中加载资源文件的方法
- 03-27学习情况