程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> DCMTK開源庫的學習筆記4:利用ini配置文件對dcm影像進行歸檔,dcmtkdcm

DCMTK開源庫的學習筆記4:利用ini配置文件對dcm影像進行歸檔,dcmtkdcm

編輯:C++入門知識

DCMTK開源庫的學習筆記4:利用ini配置文件對dcm影像進行歸檔,dcmtkdcm


轉:http://blog.csdn.net/zssureqh/article/details/8846337

背景介紹:

醫學影像PACS工作站的服務端需要對大量的dcm文件進行歸檔,寫入數據庫處理。由於醫學圖像的特殊性,每一個患者(即所謂的Patient)每做一次檢查(即Study)都至少會產生一組圖像序列(即Series),而每一組圖像序列下會包含大量的dcm文件(例如做一次心髒CTA的診斷,完整的一個心髒斷層掃描序列大約有200幅圖像)。DICOM3.0協議中對每一幅影像是按照特定的三個UID(唯一標示符)來進行標記的,分別是StudyInstanceUID、SeriesInstanceUID、SOPInstanceUID。其中StudyInstanceUID代表了唯一的一次檢查(Study),SeriesInstanceUID代表了相應檢查下的唯一序列(Series)、SOPInstanceUID代表了唯一檢查下的唯一序列下的唯一圖像。通常PACS工作站都是利用這三個UID來對dcm文件進行歸檔處理。

歸檔的設計:

1、基本的歸檔結構是:

 

第一級:StudyInstanceUID

存儲同一患者的影像數據

第二級:SeriesInstanceUID

存儲同一次檢查下的影像數據

第三級:SOPInstanceUID

存儲同一個序列下的影像數據

了解了大致的歸檔結構後,現在應該考慮怎樣將dcm記錄寫入到數據庫中?最直觀的想法就是將每一個dcm文件都記錄在數據庫中,這樣當需要讀取指定的dcm文件時通過給定的三個UID直接在數據庫中查詢就能夠得到。但是如此一來,數據庫的容量會急劇增加,同一患者在數據庫中存在著大量的冗余記錄。因為患者的影像數據是按照上述的三級目錄來歸檔的,大量的相關的影像數據存儲在服務器的同一個目錄下,對於同一個序列的圖像可以直接在第二級目錄中利用SOPInstanceUID來進行檢索,而不需要進行數據庫的查詢。但是當二級目錄下的文件數量較大時,檢索文件件中的文件同樣需要耗費大量的時間,那麼怎樣可以提高檢索效率呢?答案就是:配置文件。由於在歸檔的時候我們已經讀取過每個dcm文件的三個UID,那麼可以將歸檔時候讀取的UID信息寫入到相應的INI配置文件中,並存儲到相應的圖像序列目錄下。那麼在檢索圖像時,通過前兩級UID可以快速在數據庫中查詢到影像數據的歸檔目錄,當進入到指定的歸檔目錄後,利用歸檔時生成的INI文件,可以快速的檢索到指定的dcm文件,另外如果歸檔時將一些常用的dcm文件信息一同寫入到INI配置文件中(如圖像的寬度、高度、患者姓名、出生年月、窗寬/窗位等),在後續的一些圖像處理中同樣能夠節約時間,提高效率。

 

2、INI配置文件的生成

INI配置文件的格式就不細講了,CSDN中已有很多詳細講解的博文,請大家自行參閱。這次詳細講解一下利用dcmtk開源庫來提取相應的dcm文件信息並寫入到ini配置文件中的方法。

DCMTK開源庫是一個很好的醫學影像開發基礎庫,其很好的實現了DICOM3.0標准,且類的繼承體系簡單明了,與DICOM3.0標准一一對應(隨後會寫關於“dcmtk開源庫的繼承體系與DICOM3.0標准的對應關系”的博文)。這裡我們只用到了dcmtk中的DcmItem類,該類派生自DcmObject基礎類,其含有ElementList成員變量,存儲了DICOM3.0標准中規定的一系列的數據元(Data Element)基本結構如下圖所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 



注:DcmItem類就是Dataset(數據集)的子類。其內部包含了數據元序列(即ElementList數據成員)。

通過閱讀關於DcmItem類的源碼,總結歸納了以下幾種dcmtk開源庫給出的操作dcm文件相應數據元的函數:findAndGet 函數、findOrCreate函數、findAndXXX函數、putAndInsert函數,以及insertXXX函數,如下圖:

至此我們可以利用findAndGet函數類來提取dcm文件中的相關信息,結合WindowsAPI函數來進行INI配置文件的歸檔。由於INI配置文件就是文本文件,因此我們選用了DcmItem中的findAndGetString函數來提取dcm文件中的數據元,利用findAndGetString函數能夠直接得到字符串格式(const char*)的數據元,另外,結合WritePrivateProfileString函數來生成INI配置文件。(注:此處findAndGetString函數正好與WritePrivateProfileString函數的格式匹配,如果采用findAndGet的其他函數,如findAndGetSin32,就需要利用itoa等函數將整型轉換成const char*類型,增加了編程的復雜性)

下面給出部分代碼:

 

[cpp] view plaincopyprint?  
  1.               DcmTagKey THU_DCM_ELEMENTS[]=  
  2. {DCM_InstanceNubmber, DCM_Rows,DCM_Columns,DCM_PatientName};//定義需要寫入到ini文件中的dcm數據元標簽數組  
  3. int num=sizeof(THU_DCM_ELEMNTS)/sizeof(DcmTagKey);  
  4. OFString mImageValue;  
  5. OFString mGap("|");//INI配置文件中各個數據元之間的間隔符  
  6. OFString mImageModule("ImageModule\\");//配置文件的節名稱  
  7. OFString mSOPInstanceUID;  
  8. OFString mSeriesInstanceUID;  
  9. DcmDataset *pDataset=mDcmFile->getDataset();  
  10. DcmMetaInfo *pMetaInfo=mDcmFile->getMetaInfo();  
  11. pDataset->findAndGetOFString(DCM_SeriesInstanceUID,mSeriesInstanceUID);  
  12. pDataset->findAndGetOFString(DCM_SOPInstanceUID,mSOPInstanceUID);  
  13. mImageModule+=mSeriesInstanceUID;  
  14. for(int i=0;i<num;++i)  
  15. {  
  16.     OFString mValueRecord;  
  17.     DcmElement *element;  
  18.     if(THU_DCM_ELEMNTS[i].getGroup()>0x0002)// to determine if the THU_DCM_ELEMENTS[i] is MetaInfo  
  19.     {  
  20.         //the element belongs to Dataset  
  21.         pDataset->findAndGetOFStringArray(THU_DCM_ELEMNTS[i],mValueRecord);  
  22.         mValueRecord+=mGap;  
  23.     }  
  24.     else  
  25.     {  
  26.         //the element belongs to MetaInfo  
  27.         if(THU_DCM_ELEMNTS[i].getGroup()==0x0000 && THU_DCM_ELEMNTS[i].getElement()==0x0000)  
  28.         {  
  29.             mValueRecord=mGap;  
  30.         }  
  31.         else  
  32.         {  
  33.             pMetaInfo->findAndGetOFStringArray(THU_DCM_ELEMNTS[i],mValueRecord);  
  34.             mValueRecord+=mGap;  
  35.         }  
  36.   
  37.     }  
  38.     mImageValue+=mValueRecord;  
  39. }  
  40. ::WritePrivateProfileString(mImageModule.c_str(),mSOPInstanceUID.c_str(),mImageValue.c_str(),iniFileName);  

 

 

3、數據庫的寫入:

 

數據庫寫入的方式與INI配置文件生成基本相似,只要稍微了解C++數據庫編程的人員,就很容易仿照上述INI配置文件的生成過程來完成數據庫寫入的部分,此處就不細講了,只給出簡單的部分代碼:

 

[cpp] view plaincopyprint?  
  1. DcmFileFormat fileformat;  
  2. TCHAR FilePath[MAX_PATH];  
  3. OFCondition oc = fileformat.loadFile(FilePath);  
  4. DcmDataset *pDataset=fileformat.getDataset();  
  5. char query[1000];  
  6. memset(query,0,sizeof(char)*1000);  
  7. lstrcat(query,_T("insert into patient values ("));  
  8.   
  9. const char *tString;  
  10. pDataset->findAndGetString(DCM_InstanceNumber,tString);  
  11. lstrcat(query,tString);  
  12. lstrcat(query,_T(","));  
  13. pDataset->findAndGetString(DCM_PatientName,tString);  
  14. lstrcat(query,_T("\""));  
  15. lstrcat(query,tString);  
  16. lstrcat(query,_T("\""));  
  17. lstrcat(query,_T(","));  
  18. pDataset->findAndGetString(DCM_PatientID,tString);  
  19. lstrcat(query,tString);  
  20. lstrcat(query,_T(","));  
  21. pDataset->findAndGetString(DCM_PatientBirthDate,tString);  
  22. lstrcat(query,tString);  
  23. lstrcat(query,_T(","));  
  24. pDataset->findAndGetString(DCM_PatientSex,tString);  
  25. lstrcat(query,"\"");  
  26. lstrcat(query,tString);  
  27. lstrcat(query,"\"");  
  28. lstrcat(query,",");  
  29. pDataset->findAndGetString(DCM_PatientAge,tString);  
  30. char temp[100];  
  31. memcpy(temp,tString,lstrlen(tString));  
  32. temp[lstrlen(tString)]=_T('\0');  
  33. for(int i=0;i<strlen(temp);++i)  
  34.     if(temp[i]==_T('Y'))  
  35.         temp[i]=_T('\0');  
  36. lstrcat(query,temp);  
  37. lstrcat(query,",");  
  38. lstrcat(query,_T("2013)"));       
  39. n >              </span>//mysql數據庫的寫入  
  40. MYSQL* con;  
  41. con=mysql_init((MYSQL*)0);  
  42. if(con!=NULL && mysql_real_connect(con,host,user,passwd,db,port,unix_socket,client_flag))  
  43. {  
  44.     if(!mysql_select_db(con,db))  
  45.     {  
  46.         ::printf("Selcet successfully the database!\n");  
  47.   
  48.         con->reconnect=1;  
  49.         int rt=mysql_real_query(mysql,query,strlen(query));  
  50.         if(rt)  
  51.         {  
  52.             ::printf("Error making insert!!!\n");  
  53.         }  
  54.   
  55.     }  
  56.   
  57. }  

對於MYSQL的C++操作,可以參見博文:http://www.cnblogs.com/justinzhang/archive/2011/09/23/2185963.html

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved