專利名稱:具有傳輸裝置的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu)及交換消息的方法
技術(shù)領(lǐng)域:
本發(fā)明涉及一種醫(yī)學(xué)系統(tǒng)結(jié)構(gòu)以及一種用于在網(wǎng)絡(luò)節(jié)點(diǎn)間交換消息的方法,該醫(yī)學(xué)系統(tǒng)結(jié)構(gòu)具有至少一種用于采集檢查圖像的模態(tài)(Modalitaet);用于處理檢查圖像的、配屬于各模態(tài)的計算機(jī)處理場;,用于在客戶應(yīng)用和服務(wù)器應(yīng)用之間傳輸數(shù)據(jù)、檢查圖像和消息的裝置;用于數(shù)據(jù)和檢查圖像的存儲裝置;以及用于對數(shù)據(jù)和檢查圖像進(jìn)行后處理的另一計算機(jī)處理場所。
背景技術(shù):
在由H.Morneburg出版的“Bildgebende Systeme fuer die medizinischeDiagnostik”(用于醫(yī)學(xué)診斷的成像系統(tǒng))一書,第3版,1995,第684頁中公開了所謂PACS(Picture Archival and Communication Systeme,圖片檔案和通信系統(tǒng))的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),其中,為了調(diào)用患者數(shù)據(jù)和由模態(tài)產(chǎn)生的圖像,圖像觀察和圖像處理場所(所謂工作站)通過一個圖像通信網(wǎng)絡(luò)相互連接。借助于工作站由專家對圖像進(jìn)行診斷。
在這種系統(tǒng)的共同作用中出現(xiàn)下列技術(shù)問題a)在網(wǎng)絡(luò)通信期間在DICOM節(jié)點(diǎn)的前向、后向以及與其它制造商的產(chǎn)品之間產(chǎn)生DICOM兼容問題,并可以通過配置解決。
新的系統(tǒng)必須考慮到,老系統(tǒng)或者其它產(chǎn)品如何作用。因此,需要昂貴的“修補(bǔ)”和許多測試開銷。
b)患者數(shù)據(jù)的匿名化和其它對于安全重要的要求,必須在沒有對現(xiàn)有DICOM產(chǎn)品變動的條件下可以通過配置解決。該匿名化當(dāng)前必須在該產(chǎn)品中硬編碼地加入。
c)來自和發(fā)往購買的模擬器和測試工具的“DICOM消息”,當(dāng)前不是在運(yùn)行時間針對客戶地構(gòu)造,例如,一個HIS/RIS模擬器可以將DICOM字段用零填充,但不能空地繼續(xù)發(fā)送,而老系統(tǒng)將未知的字段作為空發(fā)送。
這點(diǎn)只能通過開發(fā)擴(kuò)展的模擬器或者測試工具的版本來克服。
發(fā)明內(nèi)容
本發(fā)明要解決的技術(shù)問題是,提供一種本文開始部分所述類型醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),以及這樣一種方法,即,按照一種簡單的方式實(shí)現(xiàn)對不同既成事實(shí)和要求的簡單適應(yīng),這些既成事實(shí)和要求例如是不同的、有可能是不同制造商的組件。
按照本發(fā)明,上述技術(shù)問題是這樣解決的,即,為用于傳輸數(shù)據(jù)、檢查圖像和消息的裝置設(shè)置一個代理服務(wù)器(Proxy-Server),該代理服務(wù)器按照固定的變換規(guī)則起到在客戶應(yīng)用和服務(wù)器應(yīng)用之間變換消息的作用。由此實(shí)現(xiàn)了,網(wǎng)絡(luò)在兩個節(jié)點(diǎn)之間采集消息,對該消息的內(nèi)容按照可配置的規(guī)則處理,并然后進(jìn)一步傳遞。
按照優(yōu)選的方式,代理服務(wù)器在交換數(shù)據(jù)、檢查圖像和消息時可以采用DICOM標(biāo)準(zhǔn)。
按照本發(fā)明,可以為代理服務(wù)器配置一個用于變換規(guī)則的存儲器。
如果代理服務(wù)器是一個分離的軟件應(yīng)用,則是具有優(yōu)點(diǎn)的。
按照本發(fā)明,代理服務(wù)器可以在同一個節(jié)點(diǎn)或者在一個網(wǎng)絡(luò)節(jié)點(diǎn)上運(yùn)行。
按照本發(fā)明,對于方法的技術(shù)問題是這樣解決的,即,消息的內(nèi)容在其被傳輸時,借助于一個轉(zhuǎn)換程序按照變換規(guī)則被處理,其中,進(jìn)行在客戶應(yīng)用和服務(wù)器應(yīng)用之間的消息交換。
按照優(yōu)選的方式,該應(yīng)用可以是DICOM應(yīng)用。
如果變換規(guī)則是可以配置的,從而使得可以對不同既成事實(shí)和要求容易實(shí)現(xiàn)匹配,則是具有優(yōu)點(diǎn)的。
按照本發(fā)明,可以通過一個代理服務(wù)器實(shí)施消息的轉(zhuǎn)換,該代理服務(wù)器訪問存儲的變換規(guī)則,其中,消息的接收、處理和進(jìn)一步傳遞對于DICOM節(jié)點(diǎn)是透明的。
下面對照附圖所示的實(shí)施方式對本發(fā)明作進(jìn)一步的說明。圖中,圖1表示一個醫(yī)院網(wǎng)絡(luò)的系統(tǒng)結(jié)構(gòu)的例子,
圖2示意地表示在DICOM客戶應(yīng)用和DICOM服務(wù)器應(yīng)用之間的一種公知的通信,并且圖3表示按照本發(fā)明的,在DICOM客戶應(yīng)用和DICOM服務(wù)器應(yīng)用之間的通信。
具體實(shí)施例方式
圖1中示例地表示了一個醫(yī)院網(wǎng)絡(luò)的系統(tǒng)結(jié)構(gòu)。模態(tài)1至4用于采集醫(yī)學(xué)圖像,它們作為產(chǎn)生圖像的系統(tǒng)例如包括用于計算機(jī)斷層造影的CT單元1、用于磁共振的MR單元2、用于數(shù)字減法血管造影術(shù)(Subtraktionsangiographie)的DSA單元3和用于數(shù)字放射線照相術(shù)的X光單元4。按這些模態(tài)1至4上連接了模態(tài)或工作站的操作面板5至8,通過這些操作面板可以對采集的醫(yī)療圖像進(jìn)行處理并在本地存儲。也可以輸入屬于圖像的患者數(shù)據(jù)。
操作面板5至8通過一個作為LAN/WAN高速鏈路(Backbone)的通信網(wǎng)絡(luò)9連接,以便分發(fā)所產(chǎn)生的圖像和進(jìn)行通信。這樣,例如可以將在模態(tài)1至4產(chǎn)生的圖像和在操作面板5至8上進(jìn)一步處理的圖像,存儲到中央圖像存儲和圖像檔案系統(tǒng)10中,或者傳遞至其它工作站。
在通信網(wǎng)絡(luò)9上連接著作為診斷面板的另一顯示工作站11,它具有本地圖像存儲器。這種顯示工作站11例如是基于一個或者多個快速處理器的非常快速的小型計算機(jī)。在該顯示工作站11中,可以將所采集的和在圖像檔案系統(tǒng)10中存儲的圖像,事后為了診斷而調(diào)用,并存放在本地存儲器中,從該本地存儲器圖像可以直接地提供給在顯示工作站11上工作的診斷人員。
此外,在通信網(wǎng)絡(luò)9上連接著服務(wù)器12,例如患者數(shù)據(jù)服務(wù)器、文件服務(wù)器、程序服務(wù)器和/或EPR服務(wù)器。
這里,通過通信網(wǎng)絡(luò)9的圖像和數(shù)據(jù)交換按照DICOM標(biāo)準(zhǔn)(一種用于在計算機(jī)之間傳輸圖像和其它醫(yī)學(xué)信息的工業(yè)標(biāo)準(zhǔn))進(jìn)行,由此使得可以在不同制造商的診斷和治療設(shè)備之間進(jìn)行數(shù)字通信。在通信網(wǎng)絡(luò)9上可以連接一個網(wǎng)絡(luò)接口13,通過該接口內(nèi)部通信網(wǎng)絡(luò)9與一個全球數(shù)據(jù)網(wǎng)絡(luò),例如萬維網(wǎng)連接,使得可以將標(biāo)準(zhǔn)化的數(shù)據(jù)與全球范圍的不同網(wǎng)絡(luò)進(jìn)行交換。
另外,在通信網(wǎng)絡(luò)9可以連接一個RIS和/或KIS服務(wù)器14,通過該服務(wù)器操作面板5至8借助于通信網(wǎng)絡(luò)9按照TCP/IP協(xié)議進(jìn)行通信。
在圖2中示意地表示在一個DICOM客戶(例如模態(tài)1至4)上的應(yīng)用15和在一個DICOM服務(wù)器(例如服務(wù)器14)上的應(yīng)用16之間的一種正常的通信。在第一連接中對多個消息17進(jìn)行了交換,該消息直接地從DICOM客戶到DICOM服務(wù)器并返回。
在圖3中則表示一種按照本發(fā)明的在DICOM客戶應(yīng)用15和DICOM服務(wù)器應(yīng)用16之間的通信。從DICOM客戶到DICOM服務(wù)器并返回的消息17,首先被送至一個所謂的代理服務(wù)器18,該代理服務(wù)器將消息按照存放在存儲器19中的變換規(guī)則進(jìn)行變換。
代理服務(wù)器18是一個組件,它為本地網(wǎng)絡(luò)(LAN)管理因特網(wǎng)中的數(shù)據(jù)交換。
該代理服務(wù)器18可以是一個分離的軟件應(yīng)用。它可以在同一個節(jié)點(diǎn)或者在一個網(wǎng)絡(luò)節(jié)點(diǎn)上運(yùn)行。它是基于規(guī)則的并可以非常動態(tài)地進(jìn)行配置。它是沒有語義的。
通過代理服務(wù)器18在通信網(wǎng)絡(luò)9對DICOM節(jié)點(diǎn)之間的數(shù)據(jù)進(jìn)行采集,對數(shù)據(jù)的內(nèi)容按照可配置的規(guī)則進(jìn)行處理,并然后將其進(jìn)一步傳遞給接收者。數(shù)據(jù)的接收、處理和進(jìn)一步傳遞對于DICOM節(jié)點(diǎn),類似于HTTP代理服務(wù)器,是完全透明的。
該處理通過有力的“正規(guī)表達(dá)式模式匹配(Regular Expression PatternMatching)”算法獲得高的表達(dá)力,該算法起源于數(shù)學(xué)家S.Kleene并例如在Jeffrey E.F.Friedl的“Mastering Regular Expressions-Powerful techniques forPerl and other tools”一書中有描述。該算法被用來使字符串的模板唯一并按照強(qiáng)烈的代數(shù)基礎(chǔ)進(jìn)行描述。該“正規(guī)表達(dá)式(Regular Expression)”模板在配置數(shù)據(jù)中是明顯的(ausfaktorisieren),不需要對原代碼進(jìn)翻譯,以便能夠?qū)Υ矸?wù)器進(jìn)行改編程序。
按照本發(fā)明的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu)具有以下突出的特點(diǎn)·在老一代基于DICOM的產(chǎn)品和新產(chǎn)品之間的透明的代理服務(wù)器·在不同制造商的DICOM產(chǎn)品或者解釋之間的透明的代理服務(wù)器·對于其它網(wǎng)絡(luò)或者DICOM節(jié)點(diǎn)的安全防火墻·對于DICOM模擬器或者協(xié)同性測試工具的擴(kuò)展。
附錄1在本說明書中使用的縮寫如下DICOM Digital Imaging and Communications in MedicineDICOM標(biāo)準(zhǔn)是一種工業(yè)標(biāo)準(zhǔn),用于在計算機(jī)之間傳輸圖像和其它醫(yī)學(xué)信息,以便可以在不同制造商的診斷和治療設(shè)備之間進(jìn)行數(shù)字通信。
EPRElectronic-Patient-Record(Elektronische Patienten Akte)電子患者檔案HISHospital Information System醫(yī)院信息系統(tǒng)(KIS)(Krankenhaus Information System)對于一般醫(yī)院管理的系統(tǒng),具有下列的主要特征患者管理、會計和帳單業(yè)務(wù)、人員管理等等。
HTTP HyperText Transfer Protocol對例如網(wǎng)絡(luò)瀏覽者的客戶對在萬維網(wǎng)中服務(wù)器一側(cè)存儲的信息的訪問進(jìn)行定義。HTTP定義了,如何組織和傳輸消息,以及網(wǎng)絡(luò)服務(wù)器和網(wǎng)絡(luò)瀏覽者應(yīng)該執(zhí)行哪些動作作為地不同命令的回答。
LANLocal Area Network本地網(wǎng)絡(luò),有一組計算機(jī)和其它設(shè)備組成,這些設(shè)備分布在一個相對有限的區(qū)域并通過命令線連接,每個設(shè)備可以和在網(wǎng)絡(luò)中與另一個設(shè)備交互作用。
PACS Picture Archival and Communication System計算機(jī)支持的圖像信息系統(tǒng),用于優(yōu)化患者供給、放射部門的工作流程、醫(yī)院中圖像分配、為研究和教學(xué)提供圖像、以及圖像歸檔。
RISRadiologie Informationssystem,放射信息系統(tǒng)(Radiology Information System)用于在放射部門內(nèi)進(jìn)行數(shù)據(jù)管理的信息系統(tǒng),該系統(tǒng)例如支持患者入院、編制工作清單、報告事務(wù)、報告管理、會計和帳單業(yè)務(wù)等。
TCP/IP Transmission Control Protocol/Internet Protocol
(Ubertragungssteuerungsprotokoll/Internetprotokoll)該用于計算機(jī)之間通信的協(xié)議集成在UNIX操作系統(tǒng)中,并是用于通過網(wǎng)絡(luò)(包括因特網(wǎng))傳輸數(shù)據(jù)的實(shí)際標(biāo)準(zhǔn)。
WANWeitbereichsnetz,廣域網(wǎng)(wide area network)一種用于連接地理上遠(yuǎn)遠(yuǎn)分離區(qū)域的通信網(wǎng)絡(luò)。一個廣域網(wǎng)可以有多個本地網(wǎng)絡(luò)組成。一個廣域網(wǎng)的例子是因特網(wǎng)。
附錄2<pre listing-type="program-listing">// ----------------------------------------------------------//Schematic example code for a tool converting from an//ascii based file using the minimal language//(set-content-from-string,set-content-from-file,//open-item,close-item)with some cosmetic extensions// ----------------------------------------------------------#include<stdio.h>#include<string.h>// include some-dicom-toolkit-header-files// for dicom stream build and dicom constrains checking// ----------------------------------------------------------// Globals#define BIGSTRSIZE 1000#define BIGPNAMESIZE 500#define BUFFERSIZE 1024*1024*10#define VRSIZE 3#define SET_FROM_STR′s′#define SET_FROM_FUN′f′#define OPEN_ITEM′O′#define CLOSE_ITEM ′C′#define TOOLKIT_DUMP ′D′#define DEBUGTOGGLE ′!′#define COMMENT_BEGIN′#′#define QUIT ′q′// Toolkit data structures should be added herechar appName[10]=″foobar″;char*fileName;<dp n="d7"/>int lineNo=0;//line number in input command filetypedef struct line_t{int cmd;unsigned long tag;char value[BIGSTRSIZE];unsigned long slot1; //DICOM group valuechar slot2[BIGPNAMESIZE]; // DICOM private tagOwnerCodeunsigned long slot3; // DICOM element value or DICOMprivate tagElementBytechar slot4[VRSIZE]; //DICOM private tagvalue rep-resentation}line_t;line_t line;char callbackdata=0x1;// Stack for message id#define STACKMAXVAL 10000int msgId_sp=0;int msgId_val[STACKMAXVAL];// ----------------------------------------------------------// Functionsvoid pushmsgId(int v){ if (msgId_sp<STACKMAXVAL)msgId_val[msgId_sp++]=v; elsefprintf(stderr,″Schematic-example-code at cmdline %d Stack overflow\n″,lineNo);}<dp n="d8"/>int popmsgId(void){ if (msgId_sp>0) return msgId_val[--msgId_sp]; else { fprintf(stderr,″Schematic-example-code at cmdline %d Stack underflow\n″,lineNo); return 0; }}void ErrExit(char*errMsg,int errNum){ if (errNum==NORMAL_COMPLETION) {fprintf(stderr,″Schematic-example-code at cmdline %d %s\n″,lineNo,errMsg); } else {fprintf(stderr,″Schematic-example-code at cmdline %d%s with TOOLKIT error%s\n″,lineNo,errMsg,Er- ror_Message( (STATUS) errNum)); } status=Release Application( &amp;appID); exit(-1);}static STATUS simpleCallBack(int msgID,unsigned longtag,int firstCall,void* userInfo,int* dataLen,void**dataBuffer,int* isLast){static char buffer[BUFFERSIZE];size_t byte_pos;FILE*stream;<dp n="d9"/>char errMsg[100];int ch;*isLast=1;if( (stream=fopen(line.value,″rb″))==NULL) { sprintf(errMsg,″Failed toopen file′%s′\n″, line.value); ErrExit(errMsg,NORMAL_COMPLETION);}byte_pos=0;ch=fgetc(stream);while(feof(stream)==0){ buffer[byte_pos]=ch; ch=fgetc(stream); byte_pos++;}//byte_pos points one ahead of last filled pos in buffer and equals number of bytesif(fclose(stream)) { sprintf(errMsg,″Failed to close file′%s′\n″, line.value); ErrExit(errMsg,NORMAL_COMPLETION);}//if odd number of bytes report errorif((byte_pos %2)==1) { ErrExit(″Odd number of bytes read.\n″,NORMAL_COMPLETION);}<dp n="d10"/>*dataBuffer=buffer;*dataLen=(int)byte_pos;return NORMAL_COMPLETION;}VR str2vr(char*str){ if((str
==′A′)&amp;&amp;(str[1]==′E′)){return AE;} if((str
==′A′)&amp;&amp;(str[1]==′S′)){return AS;} if((str
==′C′)&amp;&amp;(str[1]==′S′)){return CS;} if((str
==′D′)&amp;&amp;(str[1]==′A′)){return DA;} if((str
==′D′)&amp;&amp;(str[1]==′S′)){return DS;} if((str
==′D′)&amp;&amp;(str[1]==′T′)){return DT;} if((str
==′I′)&amp;&amp;(str[1]==′S′)){return IS;} if((str
==′L′)&amp;&amp;(str[1]==′O′)){return LO;} if((str
==′L′)&amp;&amp;(str[1]==′T′)){return LT;} if((str
==′P′)&amp;&amp;(str[1]==′N′)){return PN;} if((str
==′S′)&amp;&amp;(str[1]==′H′)){return SH;} if((str
==′S′)&amp;&amp;(str[1]==′T′)){return ST;} if((str
==′T′)&amp;&amp;(str[1]==′M′)){return TM;} if((str
==′U′)&amp;&amp;(str[1]==′T′)){return UT;} if((str
==′U′)&amp;&amp;(str[1]==′I′)){return UI;} if((str
==′S′)&amp;&amp;(str[1]==′S′)){return SS;} if((str
==′U′)&amp;&amp;(str[1]==′S′)){return US;} if((str
==′A′)&amp;&amp;(str[1]==′T′)){return AT;} if((str
==′S′)&amp;&amp;(str[1]==′L′)){return SL;} if((str
==′U′)&amp;&amp;(str[1]==′L′)){return UL;} if((str
==′F′)&amp;&amp;(str[1]==′L′)){return FL;} if((str
==′F′)&amp;&amp;(str[1]==′D′)){return FD;} if((str
==′O′)&amp;&amp;(str[1]==′B′)){return OB;} if((str
==′O′)&amp;&amp;(str[1]==′w′)){return OW;} if((str
==′O′)&amp;&amp;(str[1]==′L′)){return OL;} if((str
==′S′)&amp;&amp;(str[1]==′Q′)){return SQ;}<dp n="d11"/> return UNKNOWN_VR;}void trim_rest_of_line(void){ int c; c=getchar(); while(c?。健鋅n′) { if(c==EOF) {return;}c=getchar();}}void trim(void){ int c; c=getchar(); while((c==′′)|| (c==′\t′)) {c=getchar(); } ungetc(c,stdin);}int parseLine(line_t*line){enum{CMD,TAG,VALUE}state=CMD;int c,i;char tagAsStr[BIGSTRSIZE];<dp n="d12"/>// clear return dataline->cmd=0;line->tag=0;for(i=0;i<BIGSTRSIZE;i++) { line->value[i]=′\O′;}line->Slot1=0;line->slot3=0;for(i=0;i<BIGPNAMESIZE;i++) {line->slot2[i]=′\O′;}for(i=0;i<VRSIZE;i++) {line->slot4[i]=′\O′;}for(i=0;i<BIGSTRSIZE;i++) {tagAsStr[i]=′\O′;}trim();// get the commandc=getchar();line->cmd=c;if((c==EOF)||(c==QUIT)) { return EOF;}<dp n="d13"/>if (c==COMMENT_BEGIN) { trim_rest_of_line(); return COMMENT_BEGIN;}if (c==TOOLKIT_DUMP) { trim_rest_of_line(); return TOOLKIT_DUMP;}if (c==DEBUGTOGGLE) { trim_rest_of_line(); return DEBUGTOGGLE;}if (!((c==SET_FROM_STR)|| (c==SET_FROM_FUN)|| (c==TOOLKIT_DUMP)|| (c==OPEN_ITEM)|| (c==CLOSE_ITEM))) { ErrExit(″Failed to parse line,unexpected cmd\n″,NORMAL_COMPLETION);}trim();// get the first slot of the tag.// Tag format//(0008,0090)//(0009,SIEMENS CM VAO CMS,11)if ((c=getchar())?。健?′){ ErrExit(″Failed to parse line,tag must begin with a parantesis\n″,NORMAL_COMPLETION);}<dp n="d14"/>for(i=0;i<4; i++){ c=getchar(); if {((c>=′0′)&amp;&amp;(c<=′9′))|| ((c>=′A′)&amp;&amp;(c<=′F′))) { tagAsStr[i]=c;} else{ ErrExit(″Failed to parse line,invalidtag\n″,NORMAL_COMPLETION};}}if (sscanf(tagAsStr,″%X″,&amp;line->slot1)?。?) { ErrExit(″sscanf failed\n″,NORMAL_COMPLETION);}for(i=0;i<BIGSTRSIZE;i++) { tagAsStr[i]=′\O′;}if ((c=getchar())?。健?,′)( ErrExit(″Failed to parse line, missing comma after groupelement in tag\n″,NORMAL_COMPLETION);}// get the second slot// if a comma follows its private if endpatantesis its a normal tag,else errorc=getchar();i=0;while (!((c==′,′)|| (c==′)′))) {<dp n="d15"/> if ((c==′\n′)|| (c==EOF)) { ErrExit(″Failed to parse line,unexpected end in tag\n″,NORMAL_COMPLETION); } tagAsStr[i++]=c; c=getchar();}if (c==′)′) {// nonprivate tag for(i=0;i<4;i++){if (!(((tagAsStr[i]>=′0′)&amp;&amp;(tagAsStr [i]<=′9′)) ||((tagAsStr[i]>=′A′)&amp;&amp;(tagAsStr[i]<=′F′)))) { ErrExit(″Failed to parse line,invalid hex value in sec-ond part of nonprivate tag\n″,NOAMAL_COMPLETION);} } if (sscanf(tagAsStr,″%X″,&amp;line->slot3)!=1) {ErrExit(″sscanf failed,expected hex as second and last part of tag\n″,NORMAL_COMPLETION); }}else{// private tag strcpy(line->slot2,tagAsStr); if(c!=′,′) { ErrExit(″Failed to parse line,comma after slot2 miss-ing in private tag\n″,NORMAL_COMPLETION); }<dp n="d16"/> for(i=0;i<BIGSTRSIZE;i++) {tagAsStr[i]=′\O′; } //slot3 c=getchar(); i=0; while(c?。健洌? {if((c==′\n′)||(c==EOF)) { ErrExit(″Failed to parse line,unexpected end in slot3 in private tag\n″,NORMAL_COMPLETION);}tagAsStr[i++]=c;c=getchar(); } //slot4 line->slot4
=getchar(); line->slot4[1]=getchar(); if((c=getchar())?。健?′) {ErrExit(″Failed to parse line,missing ending parante-sis in private tag\n″,NORMAL_COMPLETION); } if (sscanf(tagAsStr,″%X″,&amp;line->slot3)!=1){ErrExit(″sscanf failed\n″,NORMAL_COMPLETION); }}if ((line->cmd==SET_FROM_STR)||(line->cmd== SET_FROM_FUN)){<dp n="d17"/>c=getchar();if(!((c==′′)||(c==′\t′))){ ErrExit(″Failed to parse line,delimiter before valuenot space or tab\n″,NORMAL_COMPLETION);} } else {trim(); } //get the value c=getchar(); i=0; while (!((c==EOF)|| (c==′\n′))) { line->value[i++]=c; c=getchar(); } return c;// EOF or ′\n′}intmain(int argc,char * argv[]){ int outer_msgId; bool debugging=FALSE; if (argc?。?){ fprintf(stderr,″\nSchematic-example-code UsageSche- matic-example-code filename <commands\n\n″); fprintf(stderr,″List of commands\n\n″);<dp n="d18"/>fprintf(stderr,″\t′s′ for SET_FROM_ STR\n″);fprintf(stderr,″\t′f′ for SET_FROM_FUN\n″);fprintf(stderr,″\t′O′ for OPEN_ITEM\n″);fprintf(stderr,″\t′C′ for CLOSE_ITEM\n″);fprintf(stderr,″\t′D′ for TOOLKIT_DUMP \n″);fprintf(stderr,″\t′!′for DEBUGTOGGLE \n″);fprintf(stderr,″\t′#′for COMMENT_BEGIN \n″);fprintf(stderr,″\t′q′for QUIT\n″);return-1; }fileName=argv[1];status=Library_Initialization(NULL,NULL,NULL);if(status?。絅ORMAL_COMPLETION) ErrExit(″Library_Initialization″,status);status=Register_Application(&amp;appID,appName);if(status?。絅ORMAL_COMPLETION) ErrExit(″Register_Application″,status);//status=Create_File(&amp;msgId,fileName,″DICOMDIR″,C_STORE_RQ);status=Create_Empty_File(&amp;msgId,fileName);if(status?。絅ORMAL_COMPLETION) ErrExit(″Create_File″,status);top_msgId=msgId;while(parseLine(&amp;line)?。紼OF) { lineNo++; if((line.cmd==QUIT)|| (line.cmd==COMMENT_BEGIN)|| (line.cmd==DEEUGTOGGLE)||<dp n="d19"/>(line.cmd==EOF)) { if(debugging) {fprintf(stdout,″Schematic-exsmple-code at cmdline %dparsed cmd= \″%c\″OK!\n″,lineNo,line.cmd); } } else { if (line.s lot2
==′\O′){ if (debugging) {fprintf(stdout,″Schematic-example-code at cmdline %dparsed cmd= \″%c\″tag=(%4X,%4X)value\″%s\″OK!\n″,lineNo,line.cmd,line.slot1,line.slot3,line.value);}line.tag=(line.slot1<<16)+line.slot3; }else{if(debugging) { fprintf(stdout,″Schematic-example-code at cmdline %dparsed cmd=\″%c\″tag=(%4X,%s,%4X,%s)value\″%s\″OK!\n″,lineNo,line.cmd,line.slot1,line.slot2,line.slot3,line.slot4,line.value,lineNo);}}}switch(line.cmd){case SET FROM_STR<dp n="d20"/> if (line.s lot2
==′\O′} //standard tag {if (strcmp(line.value,″″)==0){ status=Set_Next_Value_To_NULL(msgId,line.tag);if (status==INCOMpATIBLE_VR){ status=Set Next_Value_From_String(msgId,line.tag,″″); } } else { status=Set_Next_Value_From_String(msgId,line.tag, line.value); }if((status!=NORMAL_COMPLETION)&amp;&amp;(status?。?INVALID_CHARS_IN_VALUE)&amp;&amp;(status!= INVALID_VALUE_FOR_VR)) ErrExit(″Set_Next_Value_From_String″,status); } else //private tag {unsigned long aValLength;status=Get_pValue_Length(msgId, line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3, 1,&amp;aValLength);if((status==NULL_VALUE)||(status==EMPTY_VALUE)){status=NORMAL_COMPLETION;<dp n="d21"/> } if (!((status==NORMAL_COMPLETION)|| (status==INVALID_PRIVATE_CODE)|| (status==INVALID_TAG))) {ErrExit(″Get_pValue_Length″,status); } // CASE no owner element;no data element if(status==INVALID_PRIVATE_CODE) {status=Add_Private_Block(msgId,line.slot2,(unsigned char)line.slot1);if(status==NORMAL_COMPLETION) {status=Add_Private_Attribute(msgId,line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3, str2vr(line.slot4));if(status?。絅ORMAL_COMPLETION) { ErrExit(″Add_Private_Attribute failed″,status);} } else {ErrExit(″Add_Private_Block failed″,status);} } else if(status==INVALID_TAG) {//CASE owner element exist;no data elementdo 2.status=Add_Private_Attribute(msgId,line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3, str2vr(line.slot 4));if (status!=NORMAL_COMPLETION) { ErrExit(″Add_Private_Attribute\n″,status);} } else if (status==NORMAL_COMPLETION) {<dp n="d22"/> //CASE owner element exist;data element existdo 3. status=Set_pValue_Representation(msgId,line.slot2,(unsigned short)line.slot1,(unsigned char)line.slot3,str2vr(line.slot4)); if(!((status==NORMAL_COMPLETION)||(status==VR_ALREADY_VALID))) {ErrExit(″Set_pValue_Representation″,status); }} else { ErrExit(″Other error while doing private attribute″, status);}// We have possibly built a private structure,now set the private valueif(strcmp(line.value,″″)==0){ status=Set_Next_pValue_To_NULL(msgId, line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3);if(status==INCOMPATIBLE_VR){ status=Set_Next_pValue_From_String(msgId, line.slot2, (unsi gned short)line.slot1, (unsigned char)line.slot3,″″); }}else{ status=Set_Next_pValue_From_String(msgId, line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3,<dp n="d23"/> line.value);}if((status!=NORMAL_COMPLETION)&amp;&amp;(status?。絀NVALID_CHARS_IN_VALUE)&amp;&amp;(status!=INVALID_VALUE_FOR_VR)){ ErrExit(″Set_Next_pValue_From_String″,status);} } break;case SET_FROM_FUN if (line.slot2
==′\O′){//standard tagstatus=Set_ValLe_From_Function(msgId,line.tag,NULL, simpleCallBack);if(status?。絅ORMAL_COMPLETION)ErrExit(″Set_Value_From_Function″,status);} else {unsigned long aValLength;status=Get_pValue_Length(msgId, line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3, 1, &amp;aValLength);if(!((status==NORMAL_COMPLETION)|| (status==INVALID_PRIVATE_CODE)|| (status==INVALID_TAG))) { ErrExit(″Get_pValue_Length″,status);}// CASE no owner element;no data element<dp n="d24"/>if (status==INVALID_PRIVATE_CODE) { status=Add_Private_Block(msgId,line.slot2,(unsigned char)line.slot1); if (status==NORMAL_COMPLETION) {status=Add_Private_Attribute(msgId,line.slot2,(unsigned short)line.slot1,(unsigned char)line.slot3,str2vr(line.slot4));if (status!=NORMAL_COMPLETION) { ErrExit(″Add_Private_Attribute failed″,status);} } else {ErrExit(″Add_Private_Block failed″,status); }} else if(status==INVALID_TAG) { //CASE owner element exist;no data elementdo 2. status=Add_Private_Attribute(msgId,line.slot2, (unsigned short)line.slot1, (unsigned char)line.slot3, str2vr(line.slot4)); if (status?。絅ORMAL_COMPLETION) { ErrExit(″Add_Private_Attribute\n″,status); }} else if(status==NORMAL_COMPLETION) { // CASE owner element exist;data element existdo 3. status=Set_pValue_Representation(msgId,line.slot2,(unsigned short)line.slot1,(unsigned char)line.slot3,str2vr(line.slot 4)); if(!((status==NORMAL_COMpLETION)|| (status==VR_ALREADY_VALID))) { ErrExit(″Set_pValue_Representation″,status);<dp n="d25"/>} } else {ErrExit(″Other error while doing private attribute″, status);}//We have possibly built a private structure,now setthe private valueif ((status=Set_pValue_From_Function(msgId,line.slot2,(unsigned short)line.slot1,(unsigned char)line.slot3,NULL,simpleCallBack))?。? NORMAL_COMPLETION) {ErrExit(″Set_pValue_From_Function″,status); }}break; case CLOSE_ITEMouter_msgId=popmsgId();Set_Next_Value_From_Int(outer_msgId,line.tag,msgId);msgId=outer_msgId;if (status?。絅ORMAL_COMPLETION) ErrExit(″Set_Value_from_int″,status);break; case TOOLKIT_DUMPList_File(msgId,NULL);if(status?。絅ORMAL_COMPLETION) ErrExit(″List_File″,status);break; Case OPEN_ITEM pushmsgId(msgId);status=Open_Item(&amp;msgId,line.value);if(status?。絅ORMAL_COMPLETION)<dp n="d26"/>ErrExit(″Open_Item″,status); break;case COMMENT_BEGIN//do nothing for commentsbreak; case DEBUGTOGGLEif(debugging) { debugging=FALSE;} else { debugging=TRUE;}break; defaultfprintf(stderr,″Schematic-example-code at cmdline %d\″%c\″″,lineNo,line.cmd);ErrExit(″Unexpected value″,NORMAL_COMPLETION);break; }}if(debugging) { fprintf(stdout,″Schematic-example-codeWriting dicomoutput to%s\n″,fileName);}long aStatus=UNDEFINED;TransferSyntax aSyntax;const int aBufferSize=128;char aBuffer[aBufferSize];status=Get_Value_To_String(msgId,0x00020010,aBuffer-Size,aBuffer);if(status==NORMAL_COMPLETION)<dp n="d27"/> {aSyntax.setFromUidString(aBuffer); } else {status=File_To_Message(msgId);if(status?。絅ORMAL_COMPLETION){ ErrExit(″File_To_Message″,status);}aSyntax.setFromString(″STREAM_IMPLICIT_LITTLE_ENDIAN″); } aStatus=encodeDicomList(msgId,fileName,aSyntax); if(aStatus?。絊UCCESS) {fprintf(stderr,″Schematic-example-code at cmdline %d %s\n″,lineNo,″encodeDicomList()failed″); } return 0;} //main</pre>
權(quán)利要求
1.一種醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),該醫(yī)學(xué)系統(tǒng)結(jié)構(gòu)具有至少一個用于采集檢查圖像的模態(tài)(1至4);用于處理檢查圖像的、配屬于各模態(tài)(1至4)的計算機(jī)處理場所(5至8);用于在客戶應(yīng)用(15)和服務(wù)器應(yīng)用(16)之間傳輸數(shù)據(jù)、檢查圖像和消息的裝置(9);用于數(shù)據(jù)和檢查圖像的存儲裝置(10);以及用于對數(shù)據(jù)和檢查圖像進(jìn)行后處理的另一計算機(jī)處理場所(11),其中,為所述裝置(9)設(shè)置了一個代理服務(wù)器(18),該代理服務(wù)器按照固定的變換規(guī)則起到在客戶應(yīng)用(15)和服務(wù)器應(yīng)用(16)之間變換消息的作用。
2.根據(jù)權(quán)利要求1所述的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),其特征在于,所述數(shù)據(jù)、檢查圖像和消息的交換是按照DICOM標(biāo)準(zhǔn)進(jìn)行的。
3.根據(jù)權(quán)利要求1或2所述的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),其特征在于,為所述代理服務(wù)器(18)設(shè)置了一個用于變換規(guī)則的存儲器(19)。
4.根據(jù)權(quán)利要求1至3中任一項(xiàng)所述的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),其特征在于,所述代理服務(wù)器(18)是一個分離的軟件應(yīng)用。
5.根據(jù)權(quán)利要求1至4中任一項(xiàng)所述的醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),其特征在于,所述代理服務(wù)器(18)在同一個節(jié)點(diǎn)或者在一個網(wǎng)絡(luò)節(jié)點(diǎn)上運(yùn)行。
6.一種用于在網(wǎng)絡(luò)(9)的節(jié)點(diǎn)之間進(jìn)行消息(17)交換的方法,其特征在于,所述消息的內(nèi)容在其被傳輸時借助于一個轉(zhuǎn)換程序按照變換規(guī)則被處理。
7.根據(jù)權(quán)利要求6所述的方法,其特征在于,所述消息的交換在客戶應(yīng)用(15)和服務(wù)器應(yīng)用(16)之間進(jìn)行。
8.根據(jù)權(quán)利要求6或7所述的方法,其特征在于,所述應(yīng)用(15,16)是DICOM應(yīng)用。
9.根據(jù)權(quán)利要求6至8中任一項(xiàng)所述的方法,其特征在于,所述變換規(guī)則是可以配置的。
10.根據(jù)權(quán)利要求6至9中任一項(xiàng)所述的方法,其特征在于,所述消息的轉(zhuǎn)換通過一個代理服務(wù)器(18)實(shí)施,該代理服務(wù)器訪問存儲的變換規(guī)則。
11.根據(jù)權(quán)利要求6至10中任一項(xiàng)所述的方法,其特征在于,所述消息的接收、處理和進(jìn)一步傳遞對DICOM節(jié)點(diǎn)是透明的。
全文摘要
本發(fā)明涉及一種醫(yī)學(xué)系統(tǒng)結(jié)構(gòu),其具有至少一個用于采集檢查圖像的模態(tài)(1至4);用于處理檢查圖像的、配屬于各模態(tài)(1至4)的計算機(jī)處理場所(5至8);用于在客戶應(yīng)用(15)和服務(wù)器應(yīng)用(16)之間傳輸數(shù)據(jù)、檢查圖像和消息的裝置(9);用于數(shù)據(jù)和檢查圖像的存儲裝置(10);以及用于對數(shù)據(jù)和檢查圖像進(jìn)行后處理的另一計算機(jī)處理場所(11),其中,為所述裝置(9)設(shè)置了一個代理服務(wù)器(18),該代理服務(wù)器按照固定的變換規(guī)則起到在客戶應(yīng)用(15)和服務(wù)器應(yīng)用(16)之間變換消息的作用。本發(fā)明還涉及在網(wǎng)絡(luò)(9)的節(jié)點(diǎn)之間進(jìn)行消息(17)交換的方法,其中,消息的內(nèi)容在傳輸時借助一個轉(zhuǎn)換程序按照變換規(guī)則處理。
文檔編號G06F19/00GK1494305SQ0315978
公開日2004年5月5日 申請日期2003年9月25日 優(yōu)先權(quán)日2002年9月25日
發(fā)明者比約恩·諾爾特, 比約恩 諾爾特 申請人:西門子公司