I am new to DICOM and DCMTK and I am looking to get a grasp on them. I am currently trying to implement a simple DICOM file visualizer that should work like this: I pass a path to the program and it prints in the terminal the contents of the file (similarly to what DCMTK's print method offers). The issue I am encountering is related to the value field.
I had great success in mocking the DcmDataset's print method: I managed to read all tags, their VR, VM, length and value and placed them in a custom multi-way tree (I am not sure if it is unnecessary), even if they were part of nested sequences. However, when I use the same approach for the DcmMetaInfo the methods that should retrieve the values (findAndGet...) fail.
What do I do wrong? Any suggestions regarding the logic of the program or its implementation are welcomed!
Thank you!
Here is what my program prints in the console:
Here is what the DcmMetaInfo's print method outputs:findAndGetOFStringAray() failed for 'SourceApplicationEntityTitle'
findAndGetOFStringAray() failed for 'ImplementationVersionName'
findAndGetOFStringAray() failed for 'ImplementationClassUID'
findAndGetOFStringAray() failed for 'TransferSyntaxUID'
findAndGetOFStringAray() failed for 'MediaStorageSOPInstanceUID'
findAndGetOFStringAray() failed for 'MediaStorageSOPClassUID'
findAndGetOFStringAray() failed for 'FileMetaInformationGroupLength'
(????,????) ?? 0 0 not assigned root
>(0002,0000) UL 1 4 FileMetaInformationGroupLength init::value_not_retrieved
>(0002,0002) UI 1 26 MediaStorageSOPClassUID init::value_not_retrieved
>(0002,0003) UI 1 64 MediaStorageSOPInstanceUID init::value_not_retrieved
>(0002,0010) UI 1 18 TransferSyntaxUID init::value_not_retrieved
>(0002,0012) UI 1 28 ImplementationClassUID init::value_not_retrieved
>(0002,0013) SH 1 16 ImplementationVersionName init::value_not_retrieved
>(0002,0016) AE 1 12 SourceApplicationEntityTitle init::value_not_retrieved
This is the main section from main.cpp:# Dicom-Meta-Information-Header
# Used TransferSyntax: Little Endian Explicit
(0002,0000) UL 212 # 4, 1 FileMetaInformationGroupLength
(0002,0002) UI =SecondaryCaptureImageStorage # 26, 1 MediaStorageSOPClassUID
(0002,0003) UI [1.2.826.0.1.3680043.8.1055.1.20111103112244831.30826609.78057758] # 64, 1 MediaStorageSOPInstanceUID
(0002,0010) UI =LittleEndianImplicit # 18, 1 TransferSyntaxUID
(0002,0012) UI [1.2.826.0.1.3680043.8.1055.1] # 28, 1 ImplementationClassUID
(0002,0013) SH [dicomlibrary-100] # 16, 1 ImplementationVersionName
(0002,0016) AE [DICOMLIBRARY] # 12, 1 SourceApplicationEntityTitle
Code: Select all
Reader reader("tests/online_test.dcm");
if (reader.fopen() < 0) {
std::cerr << "File not loaded!\n";
return -1;
}
Tree* mi = reader.loadMetainfo();
reader.retrieveValues(mi);
mi->preOrderTraversalPrint();
Code: Select all
Tree* Reader::load(DcmItem* container)
{
Tree* t = new Tree();
TreeNode* prev = t->getRoot();
std::stack<TreeNode*> nodeStack;
//[NOTE] the default level in traversal is 2
int currentLevel = 2;
nodeStack.push(t->getRoot());
DcmStack s;
while (container->nextObject(s, OFTrue).good()) {
DcmObject* current = s.top();
int level = s.card();
//[NOTE] create node and insert in tree
DcmTag tag = current->getTag();
DcmVR vr = current->getVR();
unsigned long vm = current->getVM();
Uint32 length = current->getLength();
OFString description = tag.getTagName();
OFString value = "init::value_not_retrieved";
TreeNode* node = new TreeNode(tag, vr, vm, length, description, value);
//[NOTE] update node stack and level if required
if (level == currentLevel) {
t->insert(nodeStack.top(), node);
}
else if (level > currentLevel) {
t->insert(prev, node);
currentLevel++;
nodeStack.push(prev);
}
else {
while (nodeStack.size() > 1 && currentLevel > level) {
nodeStack.pop();
currentLevel--;
}
t->insert(nodeStack.top(), node);
}
prev = node;
}
return t;
}
void Reader::retrieveValues(Tree* tree)
{
std::stack<TreeNode*> nodes{};
for (auto& i : tree->getRoot()->children)
nodes.push(i);
while (!nodes.empty()) {
TreeNode* currentNode = nodes.top();
nodes.pop();
retrieveValue(tree, currentNode);
for (auto& i : currentNode->children)
nodes.push(i);
}
}
void Reader::retrieveValue(Tree* tree, TreeNode* node)
{
DcmItem* item = findContainerOfNode(tree, node);
if (item == nullptr) {
std::cerr << "The container of the node with description \'" << node->description << "\' was not found!\n";
return;
}
switch (node->vr.getEVR())
{
case EVR_AE:case EVR_AS:case EVR_AT:case EVR_CS:case EVR_DA:case EVR_DS:
case EVR_DT:case EVR_FL:case EVR_FD:case EVR_IS:case EVR_LO:case EVR_LT:
case EVR_OB:case EVR_OD:case EVR_OF:case EVR_OL:case EVR_OW:case EVR_PN:
case EVR_SH:case EVR_SL:case EVR_SS:case EVR_ST:case EVR_TM:case EVR_UC:
case EVR_UI:case EVR_UR:case EVR_US:case EVR_UT:case EVR_UN:case EVR_UL:
case EVR_ox:case EVR_xs: {
OFString value{};
OFCondition status = item->findAndGetOFStringArray(node->tag, value);
if (status.good())
node->value = value;
else
std::cerr << "findAndGetOFStringAray() failed for \'" << node->description << "\'\n";
return;
}
case EVR_SQ:case EVR_na:
node->value = "";
return;
case EVR_lt:case EVR_up:case EVR_item:case EVR_metainfo:
case EVR_dataset:case EVR_fileFormat:case EVR_dicomDir:case EVR_dirRecord:
case EVR_pixelSQ:case EVR_pixelItem:case EVR_UNKNOWN:case EVR_OverlayData:
case EVR_UNKNOWN2B:
node->value = "!!not handled!!";
break;
default:
break;
}
}