利用DCMTK開源庫完成JPEG無損壓縮,得到.dcm的圖像文件。(DCMTK_example.sln)
從下面這些博客中學習,非常詳細和全面,算是很經典的文章:
一、基於DCMTK的DICOM相關程序編寫攻略:
http://blog.csdn.net/jackmacro/article/details/5332654
二、DICOM醫學圖像處理:DCMTK在VS2012中的配置:
http://blog.csdn.net/zssureqh/article/details/38460445
三、DCMTK3.6.0 (MT支持庫)安裝 完整說明:
http://blog.163.com/qimo601@126/blog/static/158220932012113771496/
四、DCMTK開源庫對DCM文件的JPEG無損壓縮功能所需要調用的函數進行分析:
http://blog.csdn.net/zssureqh/article/details/38494319(DICOM醫學圖像處理:開源庫mDCM與DCMTK的比較分析(一),JPEG無損壓縮DCM圖像)
下面是從中學習到的知識:
一、基於DCMTK的DICOM相關程序。
1、建立自己的應用工程並將其加入DCMTK的工作空間(Project->Insert Project To WorkSpace)。
2、在自己的工程中加入需要使用的DCMTK靜態庫和頭文件。
按照正確的順序填寫鏈接庫文件(對於鏈接庫來說順序也是很重要的!) DCMTK庫有下面這些依賴關係:
dcmdata -》 ofstd
dcmimage -》 dcmimgle, dcmdata, ofstd
dcmimgle -》dcmdata, ofstd
dcmjpeg -》ijg8, ijg12, ijg16, dcmimage, dcmimgle, dcmdata, ofstd
dcmnet -》dcmdata, ofstd
dcmpstat -》 dcmimage, dcmimgle, dcmsign, dcmsr, imagectn, dcmtls, dcmnet, dcmdata, ofstd
dcmsign -》dcmdata, ofstd
dcmsr -》dcmdata, ofstd
dcmtls -》dcmnet, dcmdata, ofstd
dcmwlm -》dcmnet, dcmdata, ofstd
imagectn -》 dcmnet, dcmdata, ofstd
3、編譯自己的工程。
4、不成功的可能有如下一些問題。
(1)對於單文檔工程,運行時提示:
generated debug assertion
if (!ProcessShellCommand(cmdInfo))
return FALSE;
-- File: docsingl.cpp
Line: 215
原因:缺少AFX_IDS_UNTITLED的字符串
解決:在資源文件的STRING TABLE中加入 ID= AFX_IDS_UNTITLED的鍵值。
(2)編輯時提示:
fatal error C1189: #error : Please use the /MD switch for _AFXDLL builds
原因:
解決:在Project->Settings->Preprocessor definitions中去掉 _AFXDLL項。
(3)編譯時提示:
LIBCMTD.lib(dbgheap.obj):error LNK2005: _malloc already defined in msvcrtd.lib(MSVCRTD.dll)
原因:由於VC在編譯時試圖從兩個不同的庫中寫入同一個函數代碼,只要忽略這些相沖突的默認庫就可以解決。
解決:在Project->Settings->Link->Category->Input—>Ignore Liberies中加入
相應的msvcprtd.lib,msvcrtd.lib等。
另一種解決:保證自己的編譯環境爲:
A)project->settings->c/c++->category->code generation的use run-time library 爲debug multithreaded.
B) 在Project->Settings->Preprocessor definitions中去掉 _AFXDLL項。
C)如果需要,在資源文件的STRING TABLE中加入 ID= AFX_IDS_UNTITLED的鍵值。
D)這樣就不需要忽略那些庫了。
還有可以:
後來嘗試了很多方法,經過摸索,最後得出解決方法:
在Preprocessor中定義_AFXDLL
如果它提示:fatal error C1189: #error : Please use the /MD switch for _AFXDLL builds
就這樣改:
C/C++->Code Generation->Multithread DLL (即實現/MD選項)
(4)編譯時提示:
dcmdata.lib(dcuid.obj) : error LNK2001: unresolved external symbol _Netbios@4
原因:缺少所需的鏈接庫文件
解決:在自己的工程中加入需要使用的DCMTK靜態庫和頭文件,並注意順序。
(5)編譯時提示:
fatal error LNK1181: cannot open input file。。。。。。。 Debug.obj
原因:類似錯誤,可能是由於目錄中含有太長的中文名字。
解決:可以將中文的目錄名改爲英文就OK
(6)運行時提示:
原因:
解決:在Project->Settings->Preprocessor definitions中去掉 _AFXDLL項。
(7)如果將已經make好的dcmtk目錄複製到其它目錄,則需要重新make,否則會出現一大堆路徑錯誤
二、補充完成後項目的依賴庫如下:
再次編譯工程,順利通過編譯,此處利用DCMTK論壇中給的DCM圖像的JPEG無損壓縮,順利實現了對DCM圖像的壓縮。
具體的VS2012工程代碼:http://download.csdn.net/detail/zssureqh/7734777
選用的VS2012版本爲:cn_visual_studio_ultimate_2012_x86_dvd_920954
選用的DCMTK版本爲:3.6.0
(注:鏈接是原博主zssure給的代碼,VS2012。我用VS2010,利用原博主zssure給的.h和.c文件,配置好工程屬性,最重要的是博文中給出的庫的鏈接順序,成功完成編譯。)三、WIN7 + VisualStudio2010 + dcmtk3.6.0 安裝測試小程序
(1)新建一個empty win32 console application,在source文件夾下新建一個cpp文件,把以上源代碼複製粘貼進去。
(2) 右鍵單擊工程名,選擇屬性(properties),在Configuration Properties->C/C++->General下,Additional Include Directories里加入上一步編譯出來的include文件夾,我的電腦上是C:\Program Files\DCMTK\include,這一步是爲了讓程序能夠找到頭文件。
(3) C/C++->code generation裏,Runtime Library 選擇/MTd,這一步是要和之前CMAKE的編譯選項一致。
(4)Linker->General裏,Additional Library Directories裏填寫上一步編譯出來的lib文件夾,我的電腦上是C:\Program Files\DCMTK\lib,這一步是爲了讓程序能夠找到之前編譯好的lib文件。
(5) Linker->Input裏,在Additional Dependencies 裏依次加上wsock32.lib;netapi32.lib;ofstd.lib;oflog.lib;dcmdata.lib;zlib.lib;這一步是加入具體我們程序需要的lib文件。網上很多的帖子中,都沒有提到oflog.lib這個文件,可能是由於舊的版本中並沒有使用到這個文件。但是對於3.6.0版,這個lib文件是必需的。
(6) Apply ,ok,編譯工程,運行。
四、DCMTK開源庫對DCM文件的JPEG無損壓縮功能所需要調用的函數進行分析:
1) DicomFileFormat::loadFile,導入文件,主要是DcmMetaInfo和DcmDataset兩部分;
2) Dataset::chooseReresentation,參數中會出現新舊傳輸語義TransferSyntax,函數根據新的語義對相應數據(主要是像素數據)進行處理,會調用DcmPixelData::canChooseRepresentation、DcmPixelData::chooseRepresentation
3) Dataset::canWriteXfer,參數中是新修改後的傳輸語義。
4) DcmFileFormat::saveFile,參數中需要指出修改後的傳輸語義。
——》隨後會調用dcfilefo.cc文件中的validateMetaInfo函數(該函數中也需要指定新的傳輸語義)。
——》對文件元信息的各個元素分別調用DcmMetaInfo::search和chekMetaHeaderValue兩個函數(在該函數內,會檢測各個元信息元素是否存在,不存在會新建之並插入,其參數中就需要指出新的傳輸語義)
——》DcmElement::putString將新的傳輸協議寫入到MetaInfo中。(基本調用流程如下圖。