只要踏出一步,路就在前方

背景:

专栏之前写过许多关于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 ContextASC_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;}}(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 messagebzero(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-RSPwhile (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;//假设异常,返回}实例测试:人生就像一场旅行,不必在乎目的地,

只要踏出一步,路就在前方

相关文章:

你感兴趣的文章:

标签云: