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: https://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.
DICOM tags are represented as strings in the metadata dictionary. The string format is “XXXX,XXXX”, DICOM group number followed by element number, both are hexadecimals. The separator character is either a pipe “|” or a comma “,”.
- Warning
As the metadata dictionary uses the DICOM tag strings as keys it is possible to have multiple entries representing the same DICOM tag with different values. The last one encountered will be used when writing the image to file. For example, the patient name tag “0010,0010” and “0010|0010” may both be in the dictionary with different values due to the different separator character. Similarly, the series description tag may appear multiple times as “0008,103e”, “0008,103E”, “0008|103e”, or “0008|103E”. The strings differ in the separator character and lower or upper case letters in the hexadecimal numbers. Note that when read from file, letters in the hexadecimal numbers are always set to lower case and the separator character is a pipe. To ensure consistency, it is best to always use lower case letters and the pipe separator when explicitly adding tags to the metadata dictionary.
- 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:
