以前一直使用別人的免費瀏覽工具來瀏覽DCM圖像,或多或少都存在小的問題,要麼徹底免費可是功能不全很差用,要麼就是收費須要按期下載版本申請試用,折騰來折騰去非常費心,決定最近本身寫個簡單的,不求功能強大隻求本身用起來駕輕就熟。linux
底層文件的讀取使用DCMTK3.6.3的DCMData包;考慮支持跨平臺,上層顯示使用QT來作。git
在Linux和windows兩個平臺下編譯DCMTK生成的Config文件夾中的頭文件內容是不一樣的,爲了更好地組織兩個平臺的頭文件和庫文件,在dcmtk文件夾分別新建linux和win文件夾,將ubuntu下編譯後的include文件夾拷貝到linux下,將win7下編譯後的include文件夾拷貝到win下。讀取文件主要使用DCMTK的DcmData庫,該庫依賴了ofstd,oflog庫,爲了支持RLE壓縮和JPEG壓縮,還須要dcmjpeg庫。以linux爲例,將編譯後的config文件夾下的include目錄和源碼中的ofstd,oflog,dcmjpeg,dcmdata文件夾中的include文件夾拷貝到dcmtk/linux/include目錄下,並在工程文件.pro中將這些目錄添加到INCLUDEPATH中;github
win32: INCLUDEPATH += $$PWD/dcmtk/win/include/ else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/ win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/config else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/config win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/ofstd else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/ofstd win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/ofstd/diag else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/ofstd/diag win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/ofstd/variadic else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/ofstd/variadic win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/oflog else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/oflog win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/oflog/config else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/oflog/config win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/oflog/helpers else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/oflog/helpers win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/oflog/internal else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/oflog/internal win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/oflog/thread else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/oflog/thread win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/oflog/spi else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/oflog/spi win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/dcmjpeg else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/dcmjpeg win32: INCLUDEPATH += $$PWD/dcmtk/win/include/dcmtk/dcmdata else:unix: INCLUDEPATH += $$PWD/dcmtk/linux/include/dcmtk/dcmdata
將這幾個庫文件也拷貝到dcmtk/linux/lib文件夾下,使用到的庫文件和.pro代碼以下:chrome
DEPENDPATH += C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\x64; win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -lcharset_d else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -lcharset_d else:unix: LIBS += -lcharset win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -llibiconv_d else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -llibiconv_d else:unix: LIBS += -liconv win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -lofstd else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -lofstd else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -lofstd win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -loflog else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -loflog else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -loflog win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -ldcmjpeg else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -ldcmjpeg else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -ldcmjpeg win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -ldcmimage else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -ldcmimage else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -ldcmimage win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -ldcmimgle else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -ldcmimgle else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -ldcmimgle win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -lijg8 else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -lijg8 else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -lijg8 win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -lijg12 else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -lijg12 else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -lijg12 win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -lijg16 else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -lijg16 else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -lijg16 win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -ldcmdata else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -ldcmdata else:unix: LIBS += -L$$PWD/dcmtk/linux/lib/ -ldcmdata win32:CONFIG(release, debug|release): LIBS += -L'C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/x64/' -lNetAPI32 else:win32:CONFIG(debug, debug|release): LIBS += -L'C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/x64/' -lNetAPI32 win32: LIBS += -L'C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/x64/' -lWSock32 win32:CONFIG(release, debug|release): LIBS += -L'C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/xl64/' -lWS2_32 else:win32:CONFIG(debug, debug|release): LIBS += -L'C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/x64/' -lWS2_32 win32:CONFIG(release, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/release/ -lzlib_d else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/dcmtk/win/lib/debug/ -lzlib_d unix:!macx: LIBS += -lz win32: LIBS += -L'C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib/' -lIPHlpApi win32: LIBS += -lAdvAPI32
須要添加的頭文件以下:ubuntu
#include "dcdeftag.h" #include "dcdatset.h" #include "dcelem.h" #include "dcfilefo.h" #include "dcuid.h" #include "dcrledrg.h" #include "dcmetinf.h" #include "djdecode.h"
接下來就可使用DcmFielFormat類來讀取圖像信息了。windows
DcmFileFormat* m_pDcmFile; OFCondition result = dcmFile.loadFile(strFileName); if (result.bad()) { return false; } DcmDataset* dataset = dcmFile.getDataset(); if (dataset == NULL) { return false; }
首先,若是讀取RLE或者JEPG壓縮的圖像,須要先使用DcmJpeg庫來轉換Transfer syntax,方法以下:less
DcmMetaInfo* meta = dcmFile.getMetaInfo(); DcmElement *element = NULL; OFString transferSyntaxUID; result = meta->findAndGetElement(DCM_TransferSyntaxUID, element); if (result.bad() || element == NULL) { // assert(false); // return false; } else { element->getOFString(transferSyntaxUID, 0); } if (transferSyntaxUID.compare(UID_RLELosslessTransferSyntax)==0) { DcmRLEDecoderRegistration::registerCodecs(); result = dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL); DcmRLEDecoderRegistration::cleanup(); if (result.bad()) { return false; } } else if ( transferSyntaxUID.compare(UID_JPEGProcess14SV1TransferSyntax)==0 || transferSyntaxUID.compare(UID_JPEGProcess1TransferSyntax)==0 ) { DJDecoderRegistration::registerCodecs(); result = dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL); DJDecoderRegistration::cleanup(); if (result.bad()) { return false; } }
接下來讀取像素相關的tag,主要讀取C.6.3 Image Pixel Module也就是TableC.7-11a.Image Pixel Module Attributes的Tags。主要Tag的含義以下:工具
(0028,0002)Samples per Pixel:每一個像素的存儲單元個數,也就是幾個存儲單元數據來表示一個像素的信息。值爲1或者3,其餘值的含義沒有定義,對於monochrome和palette color圖像值爲1,對於RGB或者其餘vector color models,值爲3.學習
(0028,0004)Photometric Interpretation:圖像的類型,詳見C7.6.3.1.2 Photometric Interpretation的解釋,黑白灰度圖像大多使用MONOCHROME1或者MONOCHROME2。ui
(0028,0010)Rows:圖像的行數
(0028,0011)Columns:圖像的列數
(0028,0100)Bits Allocated:每一個Sample分配的bit數
(0028,0101)Bits Stored:每一個Sample實際存儲的bit數
(0028,0102)High Bit:每一個sample的最高位
(0028,0103)Pixel Repersentation:Sample的數據表示形式,0表示無符號整型,1表示2的補碼。
(7FE0,0010)Pixel Data:像素數據
(0028,0006)Planar Configuration:彩色像素數據的表示形式,是按像素來排布仍是按顏色色素來排布,好比RGB圖像,0表示RGBRGBRGB……RGB的形式來存儲,1表示RRR……RRRGGG……GGGBBB……BBB的形式來存儲。
(0028,0106)Smallest Image Pixel:本幅圖中像素值的最小值
(0028,0107)Largest Image Pixel Value:本幅圖像中像素值的最大值;
(0028,1101-1103)(0028,1201-1203)分別爲RGB描述了一個查找表,若是圖像是PALETTE COLOR,就利用像素值做爲索引來查找這個表,從而獲得真正的像素值。Descriptor包含三個數值,第一個值爲查找表的元素個數;第二個值爲最小的索引數,也就是(7FE0, 0010)中讀取的最小數;第三個值爲查找表的每個元素的位數。
經過以上Tags就能夠解析出來圖像中每一個像素的具體值,接下來要把這些像素值顯示出來,通常須要通過兩步轉換,Modality LUT和VOI LUT。
Modality LUT: 將設備相關的像素值轉換爲設備無關的像素值,好比CT圖像的Hounsfield units轉換爲與CT無關的像素值。若是是線性轉換就使用Rescale Slope(0028,1053)和Rescale Intercept(0028,1052)來轉換,若是是非線性就使用Modality LUT Sequnce(0028, 3000)來轉換。
VOI LUT:在進行Modality LUT後,將獲得的像素信息轉換成顯示像素信息,好比將像素信息縮放到可顯示的範圍內。若是是線性轉換就經過Window Center(0028,1050)和Window Width(0028,1051)來轉換,若是是非線性就經過VOI LUT Sequence(0028, 3010)來定義。在C11.2.1.2.2中明確提到只有MONO1和MONO2的圖像才須要VOI LUT轉換。
只要按照定義把像素值正確地讀出來,再通過正確的LUT,一個完整的圖像就獲得了。
代碼託管在github.com上,https://github.com/JorSean/dicom-explorer。歡迎搞DICOM開發的同仁們指點,你們一塊學習一塊進步。