Read and Print DICOM Tags#

Synopsis#

Example to read, search and print DICOM image metadata tags

Results#

0008|0000 = 406
0008|0005 = ISO_IR 100
0008|0008 = ORIGINAL\PRIMARY\OTHER
0008|0016 = 1.2.840.10008.5.1.4.1.1.4
0008|0018 = 1.2.840.113619.2.133.1762890640.1886.1055165016.76
0008|0020 = 20030625
0008|0021 = 20030625
0008|0022 = 20030625
0008|0023 = 20030625
0008|0030 = 152734
0008|0031 = 153128
0008|0032 = 153128
0008|0033 = 153128
0008|0050 =
0008|0060 = MR
0008|0070 = GE MEDICAL SYSTEMS
0008|0080 = crd
0008|0090 =
0008|1010 = sig3ow0
0008|1030 = Tech_1
0008|103e = head scan
0008|1070 = RPM
0008|1090 = GENESIS_SIGNA
0010|0000 = 82
0010|0010 = Wes Turner
0010|0020 = 1111
0010|0030 =
0010|0040 = O
0010|1010 = 000Y
0010|1030 = 68.039
0010|21b0 =
0018|0000 = 428
0018|0020 = GR
0018|0021 = SS\SP
0018|0022 = FC\VB_GEMS\VASCTOF_GEMS\PFF
0018|0023 = 3D
0018|0025 = N
0018|0050 =  1.6
0018|0080 = 23
0018|0081 = 10
0018|0083 =  1
0018|0084 =  6.38883e+08
0018|0085 = H1
0018|0086 =  1
0018|0087 = 15000
0018|0088 = 1.6
0018|0091 = 0
0018|0093 =  100
0018|0094 = 75
0018|0095 =  97.6562
0018|1000 = 0000018387rdmr3
0018|1020 = 09
0018|1050 =  1.14585
0018|1088 = 0
0018|1090 = 0
0018|1094 = 0
0018|1100 =  220
0018|1250 = HEAD
0018|1251 = HEAD
0018|1310 = 0\256\192\0
0018|1312 = ROW
0018|1314 = 25
0018|1315 = N
0018|1316 = 0.004169
0018|5100 = HFS
0020|0000 = 340
0020|000d = 1.2.840.113619.2.133.1762890640.1886.1055165015.961
0020|000e = 1.2.840.113619.2.133.1762890640.1886.1055165015.999
0020|0010 = 361
0020|0011 =  3
0020|0012 =  0
0020|0013 = 77
0020|0032 = -112\-18.8578\ 128.388
0020|0037 =   1\ 0\ 0\ 0\0.466651\ -0.884442
0020|0052 = 1.2.840.113619.2.133.1762890640.1910.1055164903.673
0020|0060 =
0020|0110 =  0
0020|1040 =
0020|1041 = -32.4746742249
0028|0000 = 148
0028|0002 = 1
0028|0004 = MONOCHROME2
0028|0010 = 256
0028|0011 = 256
0028|0030 =   0.85939\0.859375
0028|0100 = 16
0028|0101 = 16
0028|0102 = 15
0028|0103 = 1
0028|0120 = 0
0028|1050 = 86
0028|1051 =  173
7fe0|0000 = 131084
Patient's Name (0010|0010)  is: Wes Turner

Code#

C++#

//  This example illustrates how to read a DICOM series into a volume and then
//  print most of the DICOM header information. The binary fields are skipped.

#include "itkImageSeriesReader.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"

int
main(int argc, char * argv[])
{
  if (argc < 2)
  {
    std::cerr << "Usage: " << argv[0] << " DicomDirectory " << std::endl;
    return EXIT_FAILURE;
  }

  //  Next, we instantiate the type to be used for storing the image once it is
  //  read into memory.
  using PixelType = signed short;
  constexpr unsigned int Dimension = 3;

  using ImageType = itk::Image<PixelType, Dimension>;

  // We use the image type for instantiating the series reader type and then we
  // construct one object of this class.
  using ReaderType = itk::ImageSeriesReader<ImageType>;

  auto reader = ReaderType::New();

  // A GDCMImageIO object is created and assigned to the reader.
  using ImageIOType = itk::GDCMImageIO;

  auto dicomIO = ImageIOType::New();

  reader->SetImageIO(dicomIO);

  // A GDCMSeriesFileNames is declared in order to generate the names of DICOM
  // slices. We specify the directory with the SetInputDirectory() method
  // and, in this case, take the directory name from the command line arguments.
  // You could have obtained the directory name from a file dialog in a GUI.

  using NamesGeneratorType = itk::GDCMSeriesFileNames;

  auto nameGenerator = NamesGeneratorType::New();

  nameGenerator->SetInputDirectory(argv[1]);

  // The list of files to read is obtained from the name generator by invoking
  // the GetInputFileNames() method and receiving the results in a
  // container of strings. The list of filenames is passed to the reader using
  // the SetFileNames() method.
  using FileNamesContainer = std::vector<std::string>;
  FileNamesContainer fileNames = nameGenerator->GetInputFileNames();

  reader->SetFileNames(fileNames);

  // We trigger the reader by invoking the Update() method. This
  // invocation should normally be done inside a try/catch block given
  // that it may eventually throw exceptions.
  try
  {
    reader->Update();
  }
  catch (const itk::ExceptionObject & ex)
  {
    std::cout << ex << std::endl;
    return EXIT_FAILURE;
  }

  // ITK internally queries GDCM and obtains all the DICOM tags from the file
  // headers. The tag values are stored in the MetaDataDictionary
  // which is a general-purpose container for \{key,value\} pairs. The Metadata
  // dictionary can be recovered from any ImageIO class by invoking the
  // GetMetaDataDictionary() method.
  using DictionaryType = itk::MetaDataDictionary;

  const DictionaryType & dictionary = dicomIO->GetMetaDataDictionary();

  // In this example, we are only interested in the DICOM tags that can be
  // represented as strings. Therefore, we declare a MetaDataObject of
  // string type in order to receive those particular values.
  using MetaDataStringType = itk::MetaDataObject<std::string>;

  // The metadata dictionary is organized as a container with its corresponding
  // iterators. We can therefore visit all its entries by first getting access to
  // its Begin() and End() methods.
  auto itr = dictionary.Begin();
  auto end = dictionary.End();

  // We are now ready for walking through the list of DICOM tags. For this
  // purpose we use the iterators that we just declared. At every entry we
  // attempt to convert it into a string entry by using the dynamic_cast
  // based on RTTI information. The
  // dictionary is organized like a std::map structure, so we should use
  // the first and second members of every entry in order
  // to get access to the \{key,value\} pairs.
  while (itr != end)
  {
    itk::MetaDataObjectBase::Pointer entry = itr->second;

    MetaDataStringType::Pointer entryvalue = dynamic_cast<MetaDataStringType *>(entry.GetPointer());

    if (entryvalue)
    {
      std::string tagkey = itr->first;
      std::string tagvalue = entryvalue->GetMetaDataObjectValue();
      std::cout << tagkey << " = " << tagvalue << std::endl;
    }

    ++itr;
  }

  //  It is also possible to query for specific entries instead of reading all of
  //  them as we did above. In this case, the user must provide the tag
  //  identifier using the standard DICOM encoding. The identifier is stored in a
  //  string and used as key in the dictionary.
  std::string entryId = "0010|0010";

  auto tagItr = dictionary.Find(entryId);

  if (tagItr == end)
  {
    std::cerr << "Tag " << entryId;
    std::cerr << " not found in the DICOM header" << std::endl;
    return EXIT_FAILURE;
  }

  // Since the entry may or may not be of string type we must again use a
  // dynamic_cast in order to attempt to convert it to a string dictionary
  // entry. If the conversion is successful, we can then print out its content.
  MetaDataStringType::ConstPointer entryvalue = dynamic_cast<const MetaDataStringType *>(tagItr->second.GetPointer());

  if (entryvalue)
  {
    std::string tagvalue = entryvalue->GetMetaDataObjectValue();
    std::cout << "Patient's Name (" << entryId << ") ";
    std::cout << " is: " << tagvalue << std::endl;
  }
  else
  {
    std::cerr << "Entry was not of string type" << std::endl;
    return EXIT_FAILURE;
  }

  // This type of functionality will probably be more useful when provided
  // through a graphical user interface. For a full description of the DICOM
  // dictionary please look at the following file.

  return EXIT_SUCCESS;
}

Python#

#!/usr/bin/env python

import sys
import itk
import argparse

parser = argparse.ArgumentParser(description="Read And Print DICOM Tags.")
parser.add_argument(
    "dicom_directory",
    nargs="?",
    help="If DicomDirectory is not specified, current directory is used",
)
args = parser.parse_args()

# current directory by default
dirName = "."
if args.dicom_directory:
    dirName = args.dicom_directory

# Setup the image readers with their type
PixelType = itk.ctype("signed short")
Dimension = 3

ImageType = itk.Image[PixelType, Dimension]

# Using GDCMSeriesFileNames to generate the names of
# DICOM files.
namesGenerator = itk.GDCMSeriesFileNames.New()
namesGenerator.SetUseSeriesDetails(True)
namesGenerator.SetDirectory(dirName)

# Get the names of files
fileNames = namesGenerator.GetInputFileNames()

# Setup the image series reader using GDCMImageIO
reader = itk.ImageSeriesReader[ImageType].New()
dicomIO = itk.GDCMImageIO.New()
dicomIO.LoadPrivateTagsOn()
reader.SetImageIO(dicomIO)
reader.SetFileNames(fileNames)

# Attempt to read the series, exit if unable to.
try:
    reader.Update()
except:
    print("Error occured while reading DICOMs in: " + dirName)
    sys.exit(1)

# ITK internally queries GDCM and obtains all the DICOM tags from the file
# headers. The tag values are stored in the MetaDataDictionary
# which is a general-purpose container for \{key,value\} pairs. The Metadata
# dictionary can be recovered from any ImageIO class by invoking the
# GetMetaDataDictionary() method.
metadata = dicomIO.GetMetaDataDictionary()

# Print the key value pairs from the metadadictionary
tagkeys = metadata.GetKeys()

for tagkey in tagkeys:
    # Note the [] operator for the key
    try:
        tagvalue = metadata[tagkey]
        print(tagkey + "=" + str(tagvalue))
    except RuntimeError:
        # Cannot pass specialized values into metadata dictionary.
        print("Cannot pass specialized value" + tagkey + "into metadadictionary")


# Illustrating use of getting a label given a tag here
entryID = "0010|0010"
if not metadata.HasKey(entryID):
    print("tag: " + entryID + " not found in series")
else:
    # The second parameter is mandatory in python to get the
    # string label value
    label = itk.GDCMImageIO.GetLabelFromTag(entryID, "")
    tagvalue = metadata[entryID]
    print(label[1] + " (" + entryID + ") is: " + str(tagvalue))

Classes demonstrated#

class GDCMImageIO : public itk::ImageIOBase

ImageIO class for reading and writing DICOM V3.0 and ACR/NEMA 1&2 uncompressed images. This class is only an adaptor to the GDCM library.

GDCM can be found at: http://sourceforge.net/projects/gdcm

To learn more about the revision shipped with ITK, call

git log Modules/ThirdParty/GDCM/src/

from an ITK Git checkout.

The compressors supported include “JPEG2000” (default), and “JPEG”. The compression level parameter is not supported.

Warning

There are several restrictions to this current writer:

  • Even though during the writing process you pass in a DICOM file as input The output file may not contains ALL DICOM field from the input file. In particular:

    • The SeQuence DICOM field (SQ).

    • Fields from Private Dictionary.

  • Some very long (>0xfff) binary fields are not loaded (typically 0029|0010), you need to explicitly set the maximum length of elements to load to be bigger (see Get/SetMaxSizeLoadEntry).

  • In DICOM some fields are stored directly using their binary representation. When loaded into the MetaDataDictionary some fields are converted to ASCII (only VR: OB/OW/OF and UN are encoded as mime64).

ITK Sphinx Examples:

See itk::GDCMImageIO for additional documentation.