日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转】DCMTK开源库的学习笔记4:利用ini配置文件对dcm影像进行归档

發布時間:2023/12/10 编程问答 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】DCMTK开源库的学习笔记4:利用ini配置文件对dcm影像进行归档 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:https://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*類型,增加了編程的復雜性)

下面給出部分代碼:

DcmTagKey THU_DCM_ELEMENTS[]={DCM_InstanceNubmber, DCM_Rows,DCM_Columns,DCM_PatientName};//定義需要寫入到ini文件中的dcm數據元標簽數組int num=sizeof(THU_DCM_ELEMNTS)/sizeof(DcmTagKey);OFString mImageValue;OFString mGap("|");//INI配置文件中各個數據元之間的間隔符OFString mImageModule("ImageModule\\");//配置文件的節名稱OFString mSOPInstanceUID;OFString mSeriesInstanceUID;DcmDataset *pDataset=mDcmFile->getDataset();DcmMetaInfo *pMetaInfo=mDcmFile->getMetaInfo();pDataset->findAndGetOFString(DCM_SeriesInstanceUID,mSeriesInstanceUID);pDataset->findAndGetOFString(DCM_SOPInstanceUID,mSOPInstanceUID);mImageModule+=mSeriesInstanceUID;for(int i=0;i<num;++i){OFString mValueRecord;DcmElement *element;if(THU_DCM_ELEMNTS[i].getGroup()>0x0002)// to determine if the THU_DCM_ELEMENTS[i] is MetaInfo{//the element belongs to DatasetpDataset->findAndGetOFStringArray(THU_DCM_ELEMNTS[i],mValueRecord);mValueRecord+=mGap;}else{//the element belongs to MetaInfoif(THU_DCM_ELEMNTS[i].getGroup()==0x0000 && THU_DCM_ELEMNTS[i].getElement()==0x0000){mValueRecord=mGap;}else{pMetaInfo->findAndGetOFStringArray(THU_DCM_ELEMNTS[i],mValueRecord);mValueRecord+=mGap;}}mImageValue+=mValueRecord;}::WritePrivateProfileString(mImageModule.c_str(),mSOPInstanceUID.c_str(),mImageValue.c_str(),iniFileName);

3、數據庫的寫入:

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

?

DcmFileFormat fileformat;TCHAR FilePath[MAX_PATH];OFCondition oc = fileformat.loadFile(FilePath);DcmDataset *pDataset=fileformat.getDataset();char query[1000];memset(query,0,sizeof(char)*1000);lstrcat(query,_T("insert into patient values ("));const char *tString;pDataset->findAndGetString(DCM_InstanceNumber,tString);lstrcat(query,tString);lstrcat(query,_T(","));pDataset->findAndGetString(DCM_PatientName,tString);lstrcat(query,_T("\""));lstrcat(query,tString);lstrcat(query,_T("\""));lstrcat(query,_T(","));pDataset->findAndGetString(DCM_PatientID,tString);lstrcat(query,tString);lstrcat(query,_T(","));pDataset->findAndGetString(DCM_PatientBirthDate,tString);lstrcat(query,tString);lstrcat(query,_T(","));pDataset->findAndGetString(DCM_PatientSex,tString);lstrcat(query,"\"");lstrcat(query,tString);lstrcat(query,"\"");lstrcat(query,",");pDataset->findAndGetString(DCM_PatientAge,tString);char temp[100];memcpy(temp,tString,lstrlen(tString));temp[lstrlen(tString)]=_T('\0');for(int i=0;i<strlen(temp);++i)if(temp[i]==_T('Y'))temp[i]=_T('\0');lstrcat(query,temp);lstrcat(query,",");lstrcat(query,_T("2013)")); //mysql數據庫的寫入MYSQL* con;con=mysql_init((MYSQL*)0);if(con!=NULL && mysql_real_connect(con,host,user,passwd,db,port,unix_socket,client_flag)){if(!mysql_select_db(con,db)){::printf("Selcet successfully the database!\n");con->reconnect=1;int rt=mysql_real_query(mysql,query,strlen(query));if(rt){::printf("Error making insert!!!\n");}}}

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

總結

以上是生活随笔為你收集整理的【转】DCMTK开源库的学习笔记4:利用ini配置文件对dcm影像进行归档的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。