ITK  6.0.0
Insight Toolkit
Examples/IO/DicomSeriesReadPrintTags.cxx
/*=========================================================================
*
* Copyright NumFOCUS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
// Software Guide : BeginLatex
//
// 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.
//
// \index{DICOM!Header}
// \index{DICOM!Tags}
// \index{DICOM!Printing Tags}
//
// Software Guide : EndLatex
// Software Guide : BeginLatex
//
// The header files for the series reader and the GDCM classes for image IO
// and name generation should be included first.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
#include "itkGDCMImageIO.h"
// Software Guide : EndCodeSnippet
int
main(int argc, char * argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " DicomDirectory " << std::endl;
return EXIT_FAILURE;
}
// Software Guide : BeginLatex
//
// Next, we instantiate the type to be used for storing the image once it
// is read into memory.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using PixelType = short;
constexpr unsigned int Dimension = 3;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We use the image type for instantiating the series reader type and then
// we construct one object of this class.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
auto reader = ReaderType::New();
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// A GDCMImageIO object is created and assigned to the reader.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using ImageIOType = itk::GDCMImageIO;
auto dicomIO = ImageIOType::New();
reader->SetImageIO(dicomIO);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// A GDCMSeriesFileNames is declared in order to generate the names of DICOM
// slices. We specify the directory with the \code{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.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using NamesGeneratorType = itk::GDCMSeriesFileNames;
auto nameGenerator = NamesGeneratorType::New();
nameGenerator->SetInputDirectory(argv[1]);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// The list of files to read is obtained from the name generator by invoking
// the \code{GetInputFileNames()} method and receiving the results in a
// container of strings. The list of filenames is passed to the reader using
// the \code{SetFileNames()} method.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using FileNamesContainer = std::vector<std::string>;
const FileNamesContainer fileNames = nameGenerator->GetInputFileNames();
reader->SetFileNames(fileNames);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// We trigger the reader by invoking the \code{Update()} method. This
// invocation should normally be done inside a \code{try/catch} block given
// that it may eventually throw exceptions.
//
// Software Guide : EndLatex
try
{
// Software Guide : BeginCodeSnippet
reader->Update();
// Software Guide : EndCodeSnippet
}
catch (const itk::ExceptionObject & ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
// Software Guide : BeginLatex
//
// ITK internally queries GDCM and obtains all the DICOM tags from the file
// headers. The tag values are stored in the \doxygen{MetaDataDictionary}
// which is a general-purpose container for \{key,value\} pairs. The
// Metadata dictionary can be recovered from any ImageIO class by invoking
// the \code{GetMetaDataDictionary()} method.
//
// \index{MetaDataDictionary}
// \index{ImageIO!GetMetaDataDictionary()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using DictionaryType = itk::MetaDataDictionary;
const DictionaryType & dictionary = dicomIO->GetMetaDataDictionary();
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// In this example, we are only interested in the DICOM tags that can be
// represented as strings. Therefore, we declare a \doxygen{MetaDataObject}
// of string type in order to receive those particular values.
//
// \index{MetaDataDictionary!MetaDataObject}
// \index{MetaDataDictionary!String entries}
// \index{MetaDataObject!Strings}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
using MetaDataStringType = itk::MetaDataObject<std::string>;
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// 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 \code{Begin()} and \code{End()} methods.
//
// \index{MetaDataDictionary!Begin()}
// \index{MetaDataDictionary!End()}
// \index{MetaDataDictionary!Iterator}
// \index{MetaDataDictionary!ConstIterator}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
auto itr = dictionary.Begin();
auto end = dictionary.End();
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// 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
// \code{dynamic\_cast} based on RTTI information\footnote{Run Time Type
// Information}. The dictionary is organized like a \code{std::map}
// structure, so we should use the \code{first} and \code{second} members of
// every entry in order to get access to the \{key,value\} pairs.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
while (itr != end)
{
const itk::MetaDataObjectBase::Pointer entry = itr->second;
const MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
const std::string tagkey = itr->first;
const std::string tagvalue = entryvalue->GetMetaDataObjectValue();
std::cout << tagkey << " = " << tagvalue << std::endl;
}
++itr;
}
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// 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.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
const 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;
}
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Since the entry may or may not be of string type we must again use a
// \code{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.
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
dynamic_cast<const MetaDataStringType *>(tagItr->second.GetPointer());
if (entryvalue)
{
const 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;
}
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// 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.
//
// \code{Insight/Utilities/gdcm/Dicts/dicomV3.dic}
//
// Software Guide : EndLatex
return EXIT_SUCCESS;
}
Pointer
SmartPointer< Self > Pointer
Definition: itkAddImageFilter.h:93
itk::MetaDataObject
Allows arbitrary data types to be stored as MetaDataObjectBase types, and to be stored in a MetaDataD...
Definition: itkMetaDataObject.h:68
ConstPointer
SmartPointer< const Self > ConstPointer
Definition: itkAddImageFilter.h:94
itk::ImageSeriesReader
Data source that reads image data from a series of disk files.
Definition: itkImageSeriesReader.h:45
itk::SmartPointer< Self >
itkGDCMImageIO.h
itkImageSeriesReader.h
itk::MetaDataDictionary
Provides a mechanism for storing a collection of arbitrary data types.
Definition: itkMetaDataDictionary.h:54
itk::SmartPointer::GetPointer
ObjectType * GetPointer() const noexcept
Definition: itkSmartPointer.h:144
itk::GDCMImageIO
ImageIO class for reading and writing DICOM V3.0 and ACR/NEMA 1&2 uncompressed images....
Definition: itkGDCMImageIO.h:103
itk::ExceptionObject
Standard exception handling object.
Definition: itkExceptionObject.h:50
itk::GDCMSeriesFileNames
Generate a sequence of filenames from a DICOM series.
Definition: itkGDCMSeriesFileNames.h:63
itkGDCMSeriesFileNames.h
itk::Image
Templated n-dimensional image class.
Definition: itkImage.h:88
New
static Pointer New()
itk::GTest::TypedefsAndConstructors::Dimension2::Dimension
constexpr unsigned int Dimension
Definition: itkGTestTypedefsAndConstructors.h:44