1. 程式人生 > 其它 >DCMTK 學習筆記一 之解析tag標籤

DCMTK 學習筆記一 之解析tag標籤

閱讀本文大概需要 3.3 分鐘

我們要解析顯示一張 dcm影象,首先必須要解析其部分標籤資訊。

標籤資訊主要有三類:

  • Meta info
  • 普通 tag
  • 畫素 tag

根據需要進行讀取

使用 DCMKT讀取 dicom標籤是很容易的一件事情

meata info tag讀取

meta 資訊在 0002

有三種方式讀取,這裡展示最簡單的一種

    DcmMetaInfo metainfo;
    OFCondition status;
    status = metainfo.loadFile("G:/dicomFile/3.dcm");

    if (status.good())
    {
        OFString sopClassUID, xferUID;
        if (metainfo.findAndGetOFString(DCM_MediaStorageSOPClassUID, sopClassUID).good())
            COUT << "SOP Class UID: " << sopClassUID << OFendl;
        if (metainfo.findAndGetOFString(DCM_TransferSyntaxUID, xferUID).good())
            COUT << "Transfer Syntax UID: " << xferUID << OFendl;

        metainfo.print(COUT);
    }

輸出結果資訊:

SOP Class UID: 1.2.840.10008.5.1.4.1.1.2
Transfer Syntax UID: 1.2.840.10008.1.2.4.51
# Dicom-Meta-Information-Header
# Used TransferSyntax: Little Endian Explicit
(0002,0000) UL 202                                      #   4, 1 FileMetaInformationGroupLength
(0002,0001) OB 00\01                                    #   2, 1 FileMetaInformationVersion
(0002,0002) UI =CTImageStorage                          #  26, 1 MediaStorageSOPClassUID
(0002,0003) UI [1.2.276.0.7230010.3.1.4.2012715.17328.1511764633.841627] #  56, 1 MediaStorageSOPInstanceUID
(0002,0010) UI =JPEGExtended:Process2+4                 #  22, 1 TransferSyntaxUID
(0002,0012) UI [1.2.276.0.7230010.3.0.3.6.1]            #  28, 1 ImplementationClassUID
(0002,0013) SH [OFFIS_DCMTK_361]                        #  16, 1 ImplementationVersionName

官方參考資料

普通 tag讀取

下面以讀取病人姓名為例

    DcmFileFormat dcmFormat;

    OFCondition ofResult = dcmFormat.loadFile("G:/dicomFile/3.dcm");

    if (!ofResult.good())
    {
        qDebug() << "dcmFormat read fail..." << ofResult.text();
        return false;
    }

    DcmDataset *pDataSet = dcmFormat.getDataset();

    if (nullptr == pDataSet)
    {
        return false;
    }

    OFString strPatientName;
    ofResult = pDataSet->findAndGetOFString(DCM_PatientName, strPatientName);

    if (!ofResult.good())
    {
        return false;
    }

    qDebug() << "patientName:" << strPatientName.c_str();

結果輸出

patientName: Zhang xxx

實際開發當中解析時需要分別對應不同型別,單獨封裝對應的解析方法

比如解析字串tag

bool getStringTagValue(DcmDataset* pDataSet,const DcmTag& pTag, QString &value)
{
    if (nullptr == pDataSet)
    {
        return false;
    }

    const char* strValue = nullptr;
    Uint32 lLength = 0;
    OFCondition ofResult = pDataSet->findAndGetString(pTag, strValue, lLength);

    if (!ofResult.good())
    {
        return false;
    }

    value = QLatin1String(strValue, lLength);

    return true;
}

比如解析浮點數tag

bool getU16TagValue(DcmDataset* pDataSet,const DcmTag& pTag, quint16 &nValue)
{
    Uint16	uint16 = 0;

    if ( pDataSet->findAndGetUint16( pTag, uint16).good() )
    {
        nValue = uint16;

        return true;
    }

    return false;
}

其實 DcmFileFormat物件內部就包含了DcmMetaInfoDcmDataset物件指標,在開始的建構函式中內部自動建立的,內部採用了雙鏈表結構進行儲存

DcmFileFormat::DcmFileFormat()
  : DcmSequenceOfItems(InternalUseTag),
    FileReadMode(ERM_autoDetect)
{
    DcmMetaInfo *MetaInfo = new DcmMetaInfo();
    DcmSequenceOfItems::itemList->insert(MetaInfo);
    MetaInfo->setParent(this);

    DcmDataset *Dataset = new DcmDataset();
    DcmSequenceOfItems::itemList->insert(Dataset);
    Dataset->setParent(this);
}

總結

當然了,上述方法均是採用 DCMTK開源庫進行讀取,自己造輪子也能一步一步讀取,就是比較麻煩一點

GitHub上面有一個開源很久的專案 qdcm,也是基於Qt實現的,可以參考下

qdcm

比如讀取檔案,判斷是否包含頭資訊程式碼

bool DcmFile::hasHeader(const QString &path)
{
    QFile file(path);
    if (!file.open(QFile::ReadOnly)) {
        return false;
    }

    QDataStream ds(&file);
    int s = ds.skipRawData(128);
    if (s != 128) {
        file.close();
        return false;
    }

    char signature[4];
    s = ds.readRawData(signature, 4);
    if (s != 4) {
        file.close();
        return false;
    }

    file.close();

    if (signature[0] == 'D' && signature[1] == 'I' && signature[2] == 'C' && signature[3] == 'M') {
        return true;
    }

    return false;
}

下一篇來學習下 Dicom傳輸語法