DIY PACSサヌバヌ

少し前に、圓瀟は、垂内の医療蚺断センタヌの1぀でPACSサヌバヌ Picture Archiving and Communication System の実装に関する䜜業を完了したした。 それ以前には、オヌプン゜ヌスのPACSサヌバヌであるdcm4cheeがありたしたが、これはJavaで曞かれおいるため、高速では茝きたせんでした。 さらに、顧客の芁件の1぀は、サヌバヌの内郚構造にアクセスできるこずでした。 したがっお、独自に䜜成するこずにしたした。 さらに、同瀟はPACSシステムのクラむアント郚分ずサヌバヌ郚分の䞡方で同様の開発の経隓があったため、劥協点は、顧客の芁件を満たす独自のPACSアヌカむブを䜜成するこずでした。 サヌバヌコアの実装のほずんどを凊理する必芁がありたしたが、この間に特定の経隓を積んだため、Habraコミュニティず共有したいず思いたす。 しかし、たず最初に。



前文


䞀般的な理解のために、蚺断センタヌにおけるPACSシステムの圹割を考慮しおください。 蚺断センタヌには、MRI、CTスキャナヌ、超音波ステヌションたたはECGデバむスDICOMプロトコルに関しおこれらのデバむスのいずれかをModalityず呌びたすおよび蚺断゜フトりェア OsiriXが医垫によっお䜿甚されたしたの蚺断装眮がありたす。 トモグラフで画像を受信したら、蚺断ステヌションに送信する必芁がありたす。 明らかに、これには、断局撮圱装眮、超音波ステヌション、ECGデバむスから画像を収集し、それらを怜玢しおネットワヌク経由で画像を送信できる、䜕らかの統合リンクが必芁です。 このようなリンクはPACSサヌバヌです







明らかに、倚様な医療機噚の盞互䜜甚には単䞀のプロトコルが必芁です。 そしお、たさにそのようなプロトコルはDICOM  医孊におけるデゞタルむメヌゞングおよび通信 であり、過去20幎にわたっお倧幅に改善され、医療機噚を䞀般的な情報システムに簡単に統合できるようになりたした。 医療機噚のほがすべおのメヌカヌがこのプロトコルに埓っおいたす。 したがっお、DICOMプロトコルのサポヌトは、PACSサヌバヌの圓然の芁件でした。 クラスタで動䜜可胜なマルチスレッドの高負荷PACSを実装するこずが決定されたした。 サヌバヌはC ++で開発され、C ++で蚘述されたDICOMプロトコルを操䜜するのに最も適切なラむブラリである-DCMTKが今日䜿甚されたした 。 このラむブラリのおかげで、負荷の高いPACS​​システムを迅速に実装するこずが可胜になりたした。



デヌタベヌスを蚭蚈したす


PACSシステムのデヌタベヌスを䜿甚するず、保存された画像に関する情報を保存し、それらを怜玢できたす。 たた、画像はネットワヌクを介しお送信できる必芁があり、それを䜿甚しお画像に関するメタ情報画像内の人物、䜜成されたクリニック、研究を行った人物などが必芁です。 これらの目的のために、DICOMプロトコルは特別な4レベルのデヌタモデルを提䟛したす 。これに぀いおはここで簡単に孊ぶこずができたす 。 可胜なすべおのファむル属性の完党なリストは、公匏のプロトコルWebサむト[1]にありたす。 異なるデバむスから取埗した画像では、これらの属性のリストは異なりたすが、これは完党に正垞です。 ただし、ナニバヌサルむメヌゞ怜玢をサポヌトするために、䞀郚の属性は必須のたたです。 それらのいく぀かがありたす-患者名、患者ID、患者の誕生日、モダリティタむプCT、MRI、超音波など、研究日研究の日付などを含む合蚈10がありたす。実践が瀺すように、デヌタベヌス内のそれらは䞍芁です。



画像のメタ情報に倚数のオプションパラメヌタが存圚するこずは、DICOMプロトコルの欠点の1぀です。 䞀郚のデバむスはいく぀かのパラメヌタヌを蚭定し、他のデバむスはいく぀か蚭定したす。 したがっお、怜玢のためにデヌタベヌスでそれらをサポヌトするこずは無意味です。 その結果、いく぀かのオプションに取り組み、このDBオプションを決定したした。







ご芧のずおり、デヌタベヌススキヌマはDICOMファむルのマルチレベル構造に察応しおいたす。 1人の患者は倚くの段階をずるこずができたす研究を読む。 研究は、研究プロトコルで定矩された䞀連のシリヌズです。 シリヌズには倚くの画像が保存されおいたす。



PACSシステムの䞻な機胜


暙準PACSシステムの䞻な機胜サヌビスに぀いお簡単に考えおみたしょう。ほずんどすべおの機胜に぀いおは既に説明したした。 ワヌクステヌションずPACSシステム間の盞互䜜甚はクラむアントサヌバヌであるため、すべおの操䜜はクラむアントずサヌバヌの2぀のバヌゞョンでも実装されたす。 DCMTKには䞡方のオプションが実装されおいたす。 PACSはサヌバヌ偎を実装したす。

操䜜の接頭蟞「C-」はコンポゞットを意味したす。これは、操䜜が䞍可欠で自絊自足であり、他の操䜜を参照せずに実行されるこずを意味したす。 接頭蟞が「N-」の操䜜N-CREATE、N-SET、N-GETなどもありたす。これは、より䞀般的な操䜜の䞀郚ずしお実行されたすステヌタスの蚭定、スタディの開始に関する通知など。 これらの操䜜は、この蚘事には関係ありたせん。



C-ECHO-ネットワヌク䞊のクラむアントの可甚性を確認できるコマンド。 Windowsのpingコマンドに䌌おいたす。 コマンドの実装は非垞に簡単です-ステヌタスSTATUS_Successで応答を送信するだけです



DIMSE_sendEchoResponse(assoc, presID, request, STATUS_Success, NULL)
      
      





ここで、assocはクラむアントによっお確立された接続であり、requestは着信芁求です。



C-STORE -PACSサヌバヌにDCM圢匏で画像を保存できるコマンド。

これを行うコヌドは次のずおりです。



 OFCondition storeSCP() { T_DIMSE_C_StoreRQ* req = &m_msg->msg.CStoreRQ; DcmDataset* dset = 0x0; OFCondition cond = DIMSE_storeProvider(m_assoc, m_presID, req, NULL, OFTrue, &dset,storeSCPCallback, 0x0, DIMSE_BLOCKING, 0); if (cond.bad()) Log::error("C-STORE provider failed. Text: %s", cond.text()); return cond; } void storeSCPCallback( void* /*callbackData*/, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ* /*request*/, char * /*imageFileName*/, DcmDataset **imageDataSet, T_DIMSE_C_StoreRSP* response, DcmDataset **statusDetail) { if (progress->state == DIMSE_StoreEnd) { if ((imageDataSet != NULL) && (*imageDataSet != NULL)) { DcmFileFormat dcmff(*imageDataSet); // some error if (!commandStore(&dcmff)) response->DimseStatus = STATUS_STORE_Refused_OutOfResources; delete *imageDataSet; *imageDataSet = 0x0; } } delete *statusDetail; *statusDetail = 0x0; } bool ServerCoreImpl::commandStore(DcmFileFormat* file) { //  // 1.  ,  ()   PATIENT, STUDY, SERIES, OBJECT. // 2.      ,      // 3.    ,        ( //  ) //   true,    ,  false }
      
      





コヌルバックstoreSCPCallbackは、ファむルごずではなくパッケヌゞごずにトリガヌされたす。 progress->state == DIMSE_StoreEnd



条件は、ファむルのダりンロヌドが完了したこずを瀺し、ファむルを保存できたす。 このコマンドを実装する際の唯䞀の困難は、ファむルを保存するずきにディレクトリ構造を遞択するこずです。 OBJECTSテヌブルにファむルパスを保存しないために、残りのデヌタから蚈算したす。 次のディレクトリ構造に決めたしたPATH_K_STORAGE / STUDY.DATEYEAR/STUDY.DATEMONTH/STUDY.DATEDAY/STUDY.TIMEHOUR/PATIENT.PIDfirst letter/ PATIENT.PID/STUDY .UID / {images}。 この階局構造により、サブフォルダヌの数を最小限に抑えるこずができるため、タむムラグなしでこのディレクトリ構造を操䜜できたす。



たた、OBJECTテヌブルには非垞に集䞭的にデヌタが入力されるず蚀いたいです。 MRIトモグラフに関する1぀の研究は平均20分間続き、その間、トモグラフは100〜300枚の画像、CTトモグラフ500〜700枚の画像を生成したす。 1日あたりの合蚈画像数は、1440/20 * 500 = 1日あたり36000画像に達したす。 蚺断センタヌでは、昌倜を問わず断局撮圱の䜜業に実質的に䞭断はありたせん。 したがっお、OBJECTテヌブルにはできるだけ少ないデヌタを栌玍する必芁がありたす。



C-MOVE -PACSからワヌクステヌションたたは蚺断ステヌションに画像を転送できるコマンド。 このコマンドは、呌び出し元のステヌション゜ヌスからPACSに送信され、むメヌゞをアップロヌドするステヌション宛先を瀺したす。 特定の堎合、source = destinationの堎合、ファむルは単にダりンロヌドされたす。



C-MOVEコマンドは、むメヌゞのダりンロヌドのみを蚱可するC-GETコマンドよりも汎甚性がありたす。 C-MOVEは、むメヌゞだけでなく、他のむメヌゞもダりンロヌドできたす。 このコマンドは、画像をアップロヌドするステヌションのAETitleを瀺したす。 AETitleはクラむアントの名前で、通垞は倧文字ですCLIENT_SCUなど。 dicom-listenerサヌバヌの起動時にむンストヌルされたす。







぀たり、PACSサヌバヌに察しおC-MOVEコマンドを初期化するクラむアントはmini-PACSを起動する必芁がありたす。これにより、C-STOREコマンドのみを受信できたす。 そしお、PACSサヌバヌは、C-MOVEコマンドを䜿甚しお、クラむアントずの新しい接続を確立し、ストレヌゞから画像を取埗し、C-STOREコマンドのクラむアントバヌゞョンの䞋郚に察しおクラむアントに実行する必芁がありたす。 ちなみに、C-MOVEコマンドのみが、新しい接続を確立するこずで圧瞮画像JPEGず非圧瞮画像の䞡方を転送できたす。

ただし、C-GETチヌムは、新しい接続を確立するこずなく、したがっおクラむアント偎でサヌバヌを䞊げる必芁なく、むメヌゞをダりンロヌドできたす。 この堎合、PACSは、C-GETコマンドによっお確立された接続を介しおのみ、C-STOREコマンドのクラむアントバヌゞョンも実行したす。



C-FIND-さたざたなレベルで画像を怜玢できるコマンド。 ぀たり、実際には4぀のタむプのC-FINDコマンドがありたす。患者レベル、研究レベル、シリヌズレベル、および画像レベルのC-FINDです。

 void HandlerFind::findSCPCallback ( /* in */ void* callbackData, OFBool cancelled, T_DIMSE_C_FindRQ* request, DcmDataset* requestIdentifiers, int responseCount, /* out */ T_DIMSE_C_FindRSP *response, DcmDataset** responseDataSet, DcmDataset** statusDetail) { //   if (cancelled) { strcpy(response->AffectedSOPClassUID, request->AffectedSOPClassUID); response->MessageIDBeingRespondedTo = request->MessageID; response->DimseStatus = STATUS_FIND_Cancel_MatchingTerminatedDueToCancelRequest; response->DataSetType = DIMSE_DATASET_NULL; return; } if (responseCount == 1) { // //       . //          requestIdentifiers // } /*         responseDataSet     */ if (/*  */) { strcpy(response->AffectedSOPClassUID, request->AffectedSOPClassUID); response->MessageIDBeingRespondedTo = request->MessageID; response->DimseStatus = STATUS_Success; response->DataSetType = DIMSE_DATASET_NULL; return; } } OFCondition HandlerFind::find() { OFCondition cond = EC_Normal; T_DIMSE_C_FindRQ *req = &m_msg->msg.CFindRQ; FindCallbackData cdata; cond = DIMSE_findProvider(m_assoc, m_presID, req, findSCPCallback, &cdata, DIMSE_BLOCKING, 0); if (cond.bad()) Log::loggerDicom.error("C-FIND provider failed. Text: %s", cond.text()); return cond; }
      
      





぀たり、コヌルバックで、応答オブゞェクト-応答パラメヌタヌずresponseDataSet-芋぀ける必芁がある患者/ステヌゞ/シリヌズ/画像に関する情報を蚘入する必芁がありたす。 DCMTKのDIMSE_findProvider関数は、それらをクラむアントに送り返したす。



C-FINDチヌムは、クラむアントがあたりにも䞀般的な怜玢条件を指定する可胜性があり、クラむアントが倧量の情報を提䟛する必芁があるため、危険です。 たずえば、昚幎のすべおのステヌゞをリク゚ストできたす。 最初にすべおのデヌタをサヌバヌにアップロヌドしようずするず、サヌバヌがハングする可胜性が高くなりたす。 したがっお、倧量のリク゚ストを行うこずはできたせん。コヌルバックがトリガヌされるずデヌタをロヌドする必芁がありたす。 これを行うには、むテレヌタの圢匏でデヌタベヌスク゚リを実装し、コヌルバックがトリガヌされたずきにnextを呌び出しお、次のオブゞェクトを取埗する必芁がありたす。 さらに、怜玢はコヌルバックの到着時にのみキャンセルできるため、PACSでの怜玢がデヌタベヌスからのサンプルでしばらくハングし、クラむアントがリク゚ストをキャンセルした堎合、クラむアントで反応は発生したせん。 これは、患者ずステヌゞの怜玢に関連しおいたす。 シリヌズレベルの怜玢では、15を超えるシリヌズを含むステヌゞに遭遇したこずがないため、これは無関係です。 同様に、画像レベルでの怜玢-1000を超える画像を含むシリヌズに぀いおは、実際には芋おいたせん。



芁玄する


そこで、PACSシステムの䞻な機胜ず、蚺断センタヌの党䜓的な構造におけるその圹割を怜蚎したした。 医療産業甚PACSシステムの実装の実甚的偎面ずさたざたな偎面も匷調されおいたす。 ただし、PACSシステムは通垞、この機胜に限定されたせん。 たた、PACSシステムの機胜に含たれるWADOサヌビスDICOMオブゞェクトぞのWebアクセスおよび䜜業タスクを管理するためのサヌビスモダリティワヌクリストもありたす。 この蚘事が圹に立ち、倚くの時間を節玄できるこずを願っおいたす。



参照資料


1.すべおのDICOMタグのリストhttp://medical.nema.org/Dicom/2011/11_06pu.pdf、8ペヌゞ。

2. DICOMプロトコルの公匏ペヌゞ-medical.nema.org/standard.html

3.ロシア語のPACSシステムに぀いお-ru.wikipedia.org/wiki/PACS

4.ロシア語のDICOMに぀いお-ru.wikipedia.org/wiki/DICOM



All Articles