DICOM醫學圖像處理:DICOM網絡傳輸

背景:
        專欄取名爲DICOM醫學圖像處理原因是:博主是從醫學圖像處理算法研究時開始接觸DICOM協議的。當初認識有侷限性,認爲DICOM只是一個簡單的文件格式約定,簡而言之,我當時認爲DICOM協議就是擴展名爲DCM文件的格式說明。其實不然,隨着對醫療行業的深入,對DICOM協議也有了更全面的認識。而今才發現DCM文件只是DICOM協議一部分中的一小節,僅僅是整個協議中的一個數據結構,而DICOM協議更多的是關於醫療行業各種服務及相關流程的約定,因此其實DICOM協議中最主要的是信息流,是對醫院整體運作流程的約定。依我看來,可以將DICOM分爲兩大類(這裏只是從DICOM相關從業者日常工作角度出發來分類的):1)DICOM醫學圖像處理,即DCM文件中具體數據的處理,說圖像可能有些狹隘,廣義上還包括波形(心電)、視頻(超聲)等等;2)DICOM網絡傳輸,主要描述信息在醫院各系統之間的交互方式及傳輸格式。像我之前的研究就完全屬於第一類“DICOM醫學圖像處理”,一旦解析出DICOM的文件格式其實與常規的圖像處理就沒有差別。如果僅此而已,可以說跟醫療就沒有任何關係,與醫療行業結合緊密的是第二類“DICOM網絡傳輸”,該部分是日常患者到醫院就診等整體流程的抽象,是DICOM標準的核心。因此此次博文就重點介紹“DICOM網絡傳輸”中的第一環節:網絡連接(Association,在OSI中叫做Connection),並結合DCMTK和fo-dicom的源碼進行實例介紹。

DICOM網絡傳輸:
服務端(Server,SCP)/客戶端(Client,SCU):
        DICOM採用C/S模式來描述網絡傳輸:客戶端(Client)連接到服務端(Server)然後使用服務端提供的各項服務(Services)。不同於傳統網絡連接中的Server和Client的,DICOM中的Server叫做Service Class Provider,Client叫做Service Class User。想要建立DICOM連接(Association,傳統OSI模型中叫做Connection),客戶端會向服務端發送連接請求消息,該消息主要描述客戶端此次連接所期望的DICOM服務及相關設置;隨後服務端會查看客戶端發送過來的請求信息,確認自己是否支持客戶端請求的相關服務並給出反饋信息(DICOM中叫做響應信息Response Message)。響應信息主要分爲以下幾類:1)如果服務端支持客戶端請求的某些服務,服務端會發送確認信息(Association Acknowledge),表明此次連接完成;2)否則發送拒絕信息(Association Reject),通知客戶端(SCU)連接失敗。所有與連接相關的信息在DICOM協議中的ACSE(Association Control Service Element)定義。

        一旦網絡連接建立,客戶端(SCU)和服務端(SCP)就可以進行信息交互。DICOM標準中的DIMSE(DICOM Message Service Element)將該類信息分爲11類(詳情可參見DICOM協議中的相關細節,也可參見我之前的博文http://blog.csdn.net/zssureqh/article/details/39098621)。根據與連接信息(ACSE)的不同,提供的DIMSE信息類型也不同。例如傳統一幅DICOM圖像到服務端進行歸檔,使用的是C-STORE DIMSE消息;如果希望通過病人姓名和病人出生日期來查詢病人的檔案,需要使用DIMSE C-FIND消息。

請求連接:
        如上所述,客戶端SCU向服務端SCP發送連接請求,請求服務及相關信息。除此以外,請求消息中還包括以下信息:

請求端實體名稱(Calling AE Title):在DICOM服務中,用於指代客戶端(SCU)的符號,如同我們的姓名一樣;
被請求實體名稱(Called AE Title):在DICOM服務中,用於指代服務端(SCP)的符號,如同我們的姓名一樣;
描述上下文(Presentation Contexts):是一個服務清單(List of Services)。清單容量最多不超過128個,用於描述客戶端希望從服務端獲得的各項服務,每一項服務主要包括SOP Class和List of Transfer Syntaxes。
下面對上述三中信息進行更詳細介紹:

        AE Title:在DICOM網絡中每一個DICOM系統都會被分配一個名稱,即Application Entity Title,簡稱AETitle。AE Title用於標識DICOM網絡中的唯一(Unique)DICOM系統(有點類似於互聯網中的IP地址),因此在一個DICOM網絡環境中,要確保每一個DICOM系統擁有唯一的名稱——這個工作通常由DICOM網絡管理員來完成。AE Title最長不超過16個字符,通常在實際應用過程中都採用大寫字母來表示,當然也可以使用小寫字母及其他ASCII碼。在建立連接過程中,客戶端SCU會發送自己的AE Title(即Calling AE Title)以及服務端的AE Title(即Called AE Title,當然這個只是客戶端期望的,實際情況有可能並非如此)。

        Presentation Contexts:DICOM協議已經有20多年的歷史,從1993年DICOM標準提出以來,新的網絡連接不斷地被添加到DICOM協議中。例如1996年引入的MWL服務,即Modality Worklist Services(關於WML的描述可參見之前的博文)。因此大多數DICOM系統只支持DICOM標準中的部分服務,例如PACS系統往往就不會提供WML服務。不同的DICOM服務用於不同的目的,客戶端(SCU)會向服務端(SCP)發送其希望從服務端獲得的服務,而服務端會查看其提供的各項服務是否是客戶端期望的來決定是否提供。鑑於以上原因,客戶端(SCU)會向服務端發送一系列長度小於128的被稱爲描述上下文(Presentation Contexts)的消息列表,每一個描述上下文代表一種客戶端期望的服務。客戶端用DICOM標識符來標識每種服務,即SOP Class UID(Service Object Pair Class Unique Identifier),在DICOM標準的第4部分有詳細介紹。在連接上下文中,被髮送的SOP Class 也被叫做抽象語義Abstract Syntax(一定要與Transfer Syntaxes中的Syntaxes區分開來,之前在博文http://blog.csdn.net/zssureqh/article/details/39213817#t12的知識儲備中有過簡單的對比介紹。在OFFIS的WIKI中對此的描述原文爲In the context of association negotiation, the field where the SOP class is sent is also called "Abstract Syntax".),因此Abstract Syntax就是SOP Class UID的同義詞。在傳輸SOP Class UID(即Abstract Syntax)的同時,會發送與該服務對應的編碼格式,即Transfer Syntaxes。以乳腺檢查的X光片爲例,通常乳腺X光片很大,需要進行壓縮。客戶端在向服務端發送上下文信息時會提供給服務端一種乳腺X光片的壓縮方式,例如JPEG2000,同時也會提供一種被大多數圖像傳輸服務端接受的非壓縮方式。如下圖所示:

 

        該客戶端SCU向服務端發送了三種上下文信息(最多不超過128個),每一種上下文信息(Presentation Context)包含一種客戶端期望的服務以及相關的多種傳輸方式,例如Presentation Context ID 1中描述了一種數字乳腺X光片存儲服務,同時提供了兩種編碼方式Implicit VR Little Endian和JPEG 2000(無損壓縮)。在客戶端用奇數來標示每種上下文信息(最小編號爲1,最大爲255),通常從1號開始單調遞增,1、3、5、……。至於上下文信息之間的順序以及其內部編碼格式的順序可自由設定。通過上圖可以看出,每種服務都必須提供Implicit VR Little Endian編碼格式,因爲這是DICOM協議中默認的傳輸編碼方式。

接受(拒絕)連接:
        服務端SCP會至少接受一種上下文信息(Presentation Context)以及其他SCU請求的參數(例如AE Titles)。隨後服務端向客戶端發送連接響應消息接受該鏈接請求。鏈接消息響應有三種狀態:
接受
拒絕(短暫的)
拒絕(永久的)
        連接響應消息會直接拷貝連接請求消息中的服務端AE Title(即Called AE Title)和客戶端AE Title(即Calling AE Title)並返回。此外還會返回響應AE Title(即Respponding AE Title),該AE Title與服務端AE Title相同(這是OSI協議中要求的,但是與DICOM協議不同的是,OSI協議中並未要求兩者相同)。
        當消息響應結果爲接受時(即Accepted),服務端SCP會對客戶端SCU請求的各個上下文信息(Presentation Context)進行確認,是接受還是決絕,如下圖所示,DICOM標準第7部分的附錄D中給出了一個示意圖,作爲服務觸發端的DICOM-Service-User,給出了5種描述上下文,ID爲1、3、5、7、9;然而在SCP端只支持其中的三種(ID爲1、3、9),並且對於每一種AbstractSyntax服務端只支持其中的一種TransferSyntax。  
 

        如上圖所示,如果SCU請求的Presentation Context被拒絕,SCP不會進一步發送任何信息;如果接受了某個Presentation Context,SCP會選擇其中的一個傳輸語義添加到返回信息對應的Presentation Context中以通知SCU。如果沒有Presentation Context被接受,那麼會發送拒絕消息,此時結果代碼爲Rejected。當連接建立完成後,開始準備傳輸數據體。
        如果結果狀態碼爲”Rejected(permanent)“表明服務端SCP通知客戶端SCU它的請求被拒絕了,後續也會被拒絕。出現這種情況的原因通常由兩種,一種是請求的AE Title並不存在,也就是說網絡中並不存在該實體;另一種是服務端SCP不支持客戶端SCU請求的任何服務(即SOP Class)。在拒絕情況下,SCP可有選擇的返回Diagnostic狀態碼以通知客戶端被拒絕的原因;最差的情況下,服務端SCP只返回”Calling AE Title not recognized“。在拒絕狀態下,DICOM連接就終止了,SCP和SCU無法傳輸數據;與此同時底層的TCP連接也會關閉直到客戶端SCU再一次發送連接請求。
釋放(終止)連接:
        在連接建立之後,連接雙方開始進行數據交換。如果任何一方想終止連接(服務端SCP也可以),有兩種方式:

發送連接釋放消息;
發送連接終止消息;
        第一種情形,接收到連接釋放消息的一方會向釋放方發送一條確認消息。隨後TCP連接關閉,DICOM連接終止,這是DICOM網絡連接中正常的關閉方式;第二種情況,客戶端發送完放棄消息後,不等到服務端的確認就主動關閉TCP連接。這種關閉是不正常的,通常是客戶單遇到意外情況後發生的,這是DICOM中唯一一種不需要服務端發送響應信息的請求信息。當然還有第三種中斷方式,就是直接關閉TCP連接,這種情況往往是由於硬件錯誤所導致的。

數據交換(Date Exchange)DIMSE:
        利用ACSE消息成功建立連接後,即客戶端發送的請求至少有一種上下文描述的服務被服務端接受,真正的數據開始交換,例如一張或多張CT圖像、worklist查詢、打印請求等。如上所述,DICOM協議規定了11種DIMSE消息,每種都可以作爲客戶端的請求或者服務端的響應。11種DIMSE消息如下:C-CTORE、C-GET、C-MOVE、C-FIND、C-ECHO、N-EVENT-REPORT、N-GET、N-SET、N-ACTON、N-CREATE、N-DELETE。所有的消息都可以被不同的服務使用,根據Presentation Context的描述,你只需要其中的一種或多種。

PDU-Protocol Data Units:
        在DICOM系統連接中,每種DIMSE消息在傳輸過程中會被分割成多個片段,叫做Protocol Data Unit,簡稱PDU。PDU的大小也是連接建立過程中協商的。每一個PDU片段中會包含一個與Presentation Context ID相關的數字。我們可以將每一個Presentation Context看做雙方交流的邏輯通道,通過在PDU中包含Presentation Context ID,接收端才知道PDU屬於哪一個通道,才能將多個PDU片段進行重組。

DIMSE Message Data:
        每種DIMSE消息所傳輸的內容各有不同,請求消息(request)中主要包括:

Message ID:在連接中每個消息的唯一標示
Affected SOP Class UID:DIMSE消息中指定的SOP Class,即Presentation Context中指定的Abstract Syntax。
Affected SOP Instance UID:真正傳輸的實體數據標識符,例如上面例子中提到的乳腺X光片數據
Priority:消息的優先級,分爲HIGH 、NORMAL、LOW三種,但是大多數接收端都忽略。
Data Set:傳輸的數據。
        響應消息(response)內容與上述類似。首先包括一個狀態信息,例如0代表成功;另外與Message ID對應的是Message ID Being Responsed To,通過拷貝並返回請求端的Message ID,使得接收端知道響應消息的目標。

開源庫中相應的實現:
DCMTK:
        DCMTK開源庫更偏重於按照層(Layer)來實現DICOM應用實體(AE)之間的連接(ACSE)及消息傳輸(DIMSE),主要分爲DIMSE(應用層)、ACSE(屬於OSI七層協議中的應用層)和DUL(Dicom Upper Layer層,該層與OSI中的TCP/IP層對接)三大部分。用戶通過使用DCMTK提供的DICOM協議中規定的各層的數據結構和操作函數,按照DICOM標準中規定的流程來實現自己的DICOM服務。

        在dimse.h/dimse.cc中給出了DICOM協議中規定的各種服務對應的結構體,以T_DIMSE_爲前綴,例如T_DIMSE_C_StoreRQ/T_DIMSE_C_StoreRSP、T_DIMSE_FindRQ/T_DIMSE_FindRSP、T_DIMSE_CEchoRQ/T_DIMSE_CEchoRSP等;另外給出了各種服務對應的操作函數的聲明,以DIMSE_爲前綴,例如DIMSE_echoUser/DIMSE_sendEchoResponse、DIMSE_storeUser/DIMSE_storeProvider/DIMSE_sendStoreResponse等等,具體相應的函數定義被分別放在了獨立的文件中,主要有dimecho.cc、dimfind.cc、dimget.cc、dimmove.cc、dimstore.cc。

        在assoc.h/assoc.cc中給出了ACSE應用層的對應結構的封裝,以T_ASC_爲前綴,例如T_ASC_Parameters、T_ASC_Association、T_ASC_PresentationContext等等;另外給出了相應的連接建立或中斷的操作函數,以ASC_爲前綴,例如ASC_initializeNetwork、ASC_dropNetwork、ASC_requestAssociation、ASC_receiveAssociation、ASC_acknowledgeAssociation、ASC_rejectAssociation、ASC_releaseAssociation等等。

        在dul.h/dul.cc中給出了Dicom Upper Layer層的相關數據結構,以DUL_爲前綴,例如DUL_ASSOCIATESERVICEPARAMETERS、DUL_PRESENTATIONCONTEXT、DUL_TRANSFERSYNTAX、DUL_PDV、DUL_PDVLIST;另外給出了DUL層的操作函數,同樣以DUL_爲前綴,例如DUL_InitializeNetwork、DUL_RequestAssociation、DUL_ReleaseAssociation、DUL_ReadPDVs、DUL_WritePDVs、DUL_NextPDV等等。

fo-dicom:
        fo-dicom開源庫更偏重於按照DICOM消息流來封裝,在實現了整體DIMSE消息流框架的基礎上,給用戶預留了各階段的接口,方便用戶繼續自定義實現。

        在PDU.cs中給出了ACSE應用層對應的服務對象,主要有RawPDU、PDU、A-Associate-RQ、A-Associate-AC、A-Associate-RJ、A-Release-RQ、A-Release-RP、A-Abort、PDataTF。

        以DicomMessage爲基類派生出的一系列子類,例如DicomRequest/DicomResponse、DicomCEchoRequest/DicomCEchoResponse、DicomCStoreRequest/DicomCStoreResponse等等;該部分對DICOM協議中規定的各種消息進行了響應的封裝。

        在DicomService類中給出了整個DICOM協議中規定的SCP/SCU之間交互的流程,但是對於不同的ACSE應用層的連接操作和DIMSE層的消息操作都留出了相應的接口,通過調用後續的回調函數來實現用戶自己的意圖。

        以IDicomServiceUser/IDicomServiceProvider、IDicomCStoreProvider、IDicomCEchoProvider等爲基礎的一系列接口類,該部分給出了DicomService中一系列操作的回調函數接口,具體的實現由用戶自己完成。

        以DicomClient/DicomServer爲基礎的實體類,該類是用戶自己搭建SCP和SCU兩端的必須類,可以說DicomClient和DicomServer就是一對簡易實現的DICOM服務的SCU和SCP。例如fo-dicom自帶的實例中var server = new DicomServer<DicomCEchoProvider>(12345);就開啓了一個端口號爲12345的接收C-ECHO服務的SCP服務端;var client = new DicomClient();client.NegotiateAsyncOps();client.AddRequest(new DicomCEchoRequest());就實現了一個簡易的發起C-ECHO請求的SCU客戶端。

DICOM3.0標準分析:
PDU vs PDV:
        DCMTK3.0標準中對於PDU(Protocol Data Unit)的解釋和定義與上面博文中介紹的一致,但是對於PDV在標準中有兩種解釋分別是Protocol Data Value和Presentation Data Value,我更偏向於後者。上面博文中介紹的PDU指的是在DICOM連接建立之上傳遞的消息片段,英文原文是“If such a message is transferred on a DICOM connection, they are cut into pieces, so called Protocol Data Unit (PDUs).”——這裏需要注意的是message,並不僅僅指我們所說的DICOM Message(參見圖1),還包括了ACSE協議中使用的連接消息,例如A-ASSOCIATION-RQ、A-ASSOCIATION-RSP、A-ABORT,該類消息在DICOM3.0協議的第8部分有詳細的介紹(參見圖2)。

        在圖2中P-DATA-TF PDU結構中的Variable Field可變區域纔是PDV,即Presentation Data Value。這裏PDV指的是DICOM Message在具體傳輸過程中被分割的多個片段(該部分在DICOM3.0標準第8部分的附錄E中有詳細介紹,參見圖3,其實就是上文中提到的DIMSE Message Data)。在fo-dicom中的PDU.cs文件中可驗證,其中PDU的子類P-DATA-TF的成員中包含一個PDV的鏈表,即List<PDV>。

        一句話總結:PDU指的是DICOM協議中的傳輸的各種消息(包括ACSE和DIMSE)的片段,PDV專指DICOM Message被分割後的片段,屬於P-DATA-TF類PDU中的Variable Field部分。

 

 

ACSE vs DIMSE:
        ACSE是在DICOM3.0中的第8部分介紹,該部分的標題爲Network Communication Support for Message Exchange,因此可以斷定ACSE主要應用戶連接建立階段。 連接(Association)的建立是兩個DICOM實體(AE)之間進行交互的第一步,AEs在建立的連接上進行數據編碼格式、傳輸方式的協商。DICOM AEs利用ACSE-ASSOCIATE服務來建立連接,在ACSE-ASSOCIATE服務中主要用到的是Application Context、Presentation Context和User Information Items(在DICOM3.0標準第7部分的附錄3中有詳細的介紹)。ACSE服務主要有A-ASSOCIATE、A-RELEASE、A-ABORT、A-P-ABORT、P-DATA五類,對應的PDU有A-ASSOCIATE-RQ、A-ASSOCIATE-AC、A-ASSOCIATE-RJ、P-DATA-TF、A-RELEASE-RQ、A-RELEASE-RP、A-ABORT七種。

        DIMSE是在DICOM3.0中的第7部分介紹,該部分的標題爲Message Exchange,由此說明DIMSE是對DICOM傳輸消息的規定。DIMSE服務類型有C-STORE、C-GET、C-MOVE、C-FIND、C-ECHO、N-EVENT-REPORT、N-GET、N-SET、N-ACTION、N-CREATE、N-DELETE,如下圖。

 

        有上述對比可以看出ACSE是DIMSE的基礎,DIMSE是在ACSE之上實現的。正如PDU vs PDV中提到的,DIMSE Message是在Association建立完成後,通過ACSE中的P-DATA-TF服務來傳輸,各種DIMSE 消息會被分割成PDVs放入到P-DATA-TF的Variable Field。如下圖所示:

 

        最後通過查看fo-dicom中的DicomService.cs中EndPDU和ProcessPDataTF函數可以有一個更形象的理解,在EndPDU函數內部通過讀取PDU的前6個字節來識別PDU屬於ACSE中的哪一種服務,例如A-ASSOCIATE-RQ、A-ASSOCIATE-AC、A-ASSOCIATE-RJ、P-DATA-TF、A-RELEASE-RQ、A-RELEASE-RP、A-ABORT;當PDU屬於P-DATA-TF類型時,進入到ProcessPDataTF函數內部。通過提取P-DATA-TF PDU中的Variable Field中的PDVs來判別是哪一種DIMSE消息,主要有C-STORE-RQ/C-STORE-RSP、C-FIND-RQ/C-FIND-RSP、C-ECHO-RQ/C-ECHO-RSP、C-MOVE-RQ/C-MOVE-RSP等等。

參考資料:
http://support.dcmtk.org/redmine/projects/dcmtk/wiki/DICOM_NetworkingIntroduction#Protocol-Data-Units,本文英文原文

http://medical.nema.org/medical/dicom/current/output/html/part07.html,DICOM3.0標準第7部分

http://medical.nema.org/medical/dicom/current/output/html/part08.html,DICOM3.0標準第8部分

https://github.com/redmoxie/fo-dicom,fo-dicom源碼

http://support.dcmtk.org/redmine/projects/dcmtk/files,DCMTK源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章