Project

General

Profile

Howto IterateDataset

Below there is an example application that loads a given file (command line parameter) and iterates over its dataset providing some demo output.

Version using nextObject() and nextInContainer()

The function works recursively through the dataset and is based on the functions nextInContainer(), which always returns the next object on the same level as the current object, and nextObject(), which returns the first child object below the current one. Of course, a non-recursive version is possible too. There could also be a version that does not require the "container" parameter (in printHierarchy) since it can be deduced by DcmObject's getParent() method.

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "dcmtk/dcmdata/dcfilefo.h" 
#include "dcmtk/dcmdata/dcdeftag.h" 
#include <string>

static void printHierarchy(DcmObject* container, DcmObject* current, unsigned int level)
{
  // Check if we are already done at the current level
  if ( (container == NULL) || (current == NULL)) return;
  OFBool isLeaf = current->isLeaf();
  // Print current object
  std::cout  << std::string(level*2, ' ') << (isLeaf ? "Leaf: " : "No leaf") << current->getTag().toString() << std::endl;
  // If the current object has childs, advance to first child
  if (!current->isLeaf())
  {
    DcmStack stack;
    current->nextObject(stack, OFTrue);
    printHierarchy(current, stack.top() , level + 1);
  }
  // Advance to next object on the same level as the current one
  printHierarchy(container, container->nextInContainer(current), level);
}

int main(int argc, char *argv[])
{
  DcmFileFormat dcmff;
  OFCondition result = dcmff.loadFile(argv[1]);
  if (result.good())
  {
    DcmDataset* dset = dcmff.getDataset();
    printHierarchy(dset, dset->nextInContainer(NULL) /* gets first element in dataset */, 0 /* main level */);
    return 0;
  }
  {
    CERR << "Unable to load file" << OFendl;
    return 1;
  }
}

This is the sample output for a (meaningless) dataset:

Leaf: (0010,0010)
Leaf: (0010,0020)
No leaf(0018,002a)
  No leaf(fffe,e000)
    Leaf: (0010,21a0)
  No leaf(fffe,e000)
    Leaf: (0010,21a0)
  No leaf(fffe,e000)
    Leaf: (0010,21a0)
Leaf: (0020,9421)
Leaf: (0020,9453)

which dcmdump would display as:

(0010,0010) PN [Main level]                             #  10, 1 PatientName
(0010,0020) LO [Main Level]                             #  10, 1 PatientID
(0018,002a) SQ (Sequence with undefined length #=3)     # u/l, 1 AdditionalDrugSequence
  (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
    (0010,21a0) CS [In Sequence Item]                       #  16, 1 SmokingStatus
  (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
  (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
    (0010,21a0) CS [In Sequence Item]                       #  16, 1 SmokingStatus
  (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
  (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
    (0010,21a0) CS [In Sequence Item]                       #  16, 1 SmokingStatus
  (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
(0020,9421) LO [Back on main level]                     #  18, 1 DimensionDescriptionLabel
(0020,9453) LO [Back on main Level]                     #  18, 1 FrameLabel

Shorter version only using nextObject()

Here is a shorter version that only uses nextObject() but is maybe a bit less intuitive.

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "dcmtk/dcmdata/dcfilefo.h" 
#include "dcmtk/dcmdata/dcdeftag.h" 
#include <string>

static void printHierarchy(DcmStack& stack)

{
  if (stack.top() == NULL) return;
  // Check whether we have a leaf or substructured type (sequence)
  OFBool isLeaf = stack.top()->isLeaf();
  // Print current object
  std::cout  << std::string((stack.card()-2)*2, ' ') << (isLeaf ? "Leaf: " : "No leaf") << stack.top()->getTag().toString() << std::endl;
  // Advance to next element
  stack.elem(1)->nextObject(stack, OFTrue);
  printHierarchy(stack);
}

int main(int argc, char *argv[])

{
  DcmFileFormat dcmff;
  OFCondition result = dcmff.loadFile(argv[1]);
  if (result.good())
  {
    DcmDataset* dset = dcmff.getDataset();
    DcmStack stack;
    stack.push(dset);
    stack.push(dset->nextInContainer(NULL));
    printHierarchy(stack);
    return 0;
  } else
  {
    CERR << "Unable to load file" << OFendl;
    return 1;
  }

The output is identical to version 1.

Much short version (without recursion)

DcmStack stack;
while (dset->nextObject(stack, OFTrue).good())
    COUT << OFString((stack.card() / 2) - 1, '>') << stack.top()->getTag() << " " << DcmVR(stack.top()->getVR()).getVRName() << OFendl;

The output on a different dataset looks like this (shows the nesting of sequence items):

...
(0045,1061) IS
(0045,1062) IS
(0045,1063) IS
(0054,0220) SQ
(fffe,e000) na
>(0008,0100) SH
>(0008,0102) SH
>(0008,0104) LO
>(0054,0222) SQ
>(fffe,e000) na
>>(0008,0100) SH
>>(0008,0102) SH
>>(0008,0104) LO
(0088,0200) SQ
(fffe,e000) na
>(0028,0002) US
>(0028,0004) CS
...