DCMTK 學習筆記一 之解析tag標籤
阿新 • • 發佈:2021-06-23
閱讀本文大概需要 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
物件內部就包含了DcmMetaInfo
和DcmDataset
物件指標,在開始的建構函式中內部自動建立的,內部採用了雙鏈表結構進行儲存
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
實現的,可以參考下
比如讀取檔案,判斷是否包含頭資訊程式碼
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
傳輸語法