[Insight-users] GDCMImageIO object containing wrong(?) values when editing the DICOM header

John Drozd john.drozd at gmail.com
Thu Feb 17 17:08:50 EST 2011


Hi Jon,

Since this is not shown in the ITK software guide,
I thought this code that I wrote based on
http://www.paraview.org/Bug/view.php?id=6258&nbn=1 ,  might help someone:
It shows how to change a MetaDataDictionaryArray when dealing with changing
header info in Dicom series.

Thanks,
John

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

//
//  This example illustrates how to change a MetaDataDictionaryArray.
//  This example illustrates how to read two DICOM series, adds key
//  tags that are in the second DICOM series to the first DICOM series
//  and write it back with some changed header information as another
//  DICOM series.  This can be useful when sometimes conversion between
//  different file formats as between NIFTI and DICOM and some dicom tags
//  are lost.
//  The keys are defined in the file
//
//  \code{Insight/Utilities/gdcm/
Dicts/dicomV3.dic}
//
//  Please note that modifying the content of a DICOM header is a very risky
//  operation. The Header contains fundamental information about the patient
//  and therefore its consistency must be protected from any data
corruption.
//  Before attempting to modify the DICOM headers of your files, you must
make
//  sure that you have a very good reason for doing so, and that you can
ensure
//  that this information change will not result in a lower quality of
health
//  care to be delivered to the patient.
//
//  \index{DICOM!Changing Headers}
//

// Software Guide : BeginLatex
//
// We must start by including the relevant header files. Here we include the
// image reader, image writer, the image, the Meta data dictionary and its
// entries the Meta data objects and the GDCMImageIO. The Meta data
dictionary
// is the data container that stores all the entries from the DICOM headeronce
// the DICOM image file is read into an ITK image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImage.h"
#include "itkMetaDataDictionary.h"
#include "itkMetaDataObject.h"
#include "itkGDCMImageIO.h"
// Software Guide : EndCodeSnippet

#include <list>
#include <fstream>


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


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

  if( argc < 4 )
    {
      std::cerr << "Usage: " << argv[0] << " OriginalDicomImageDIR
ProcessedDicomImageDIR OutputDicomImageDIR\n";
      //DIR means Directory


    return EXIT_FAILURE;
    }

  typedef unsigned short InputPixelType;


  const unsigned int   Dimension = 3;

  typedef itk::Image< InputPixelType, Dimension > InputImageType;

  typedef itk::GDCMSeriesFileNames                NamesGeneratorTypeOrig;
  NamesGeneratorTypeOrig::Pointer namesGeneratororig =
NamesGeneratorTypeOrig::New();

  namesGeneratororig->SetInputDirectory( argv[1] );

  typedef itk::Image< InputPixelType, Dimension >      ImageTypeOrig;
  typedef itk::ImageSeriesReader< ImageTypeOrig >     ReaderTypeOrig;

  const ReaderTypeOrig::FileNamesContainer & filenamesorig =
                            namesGeneratororig->GetInputFileNames();

  unsigned int numberOfFilenames =  filenamesorig.size();
  std::cout << numberOfFilenames << std::endl;
  for(unsigned int fni = 0; fni<numberOfFilenames; fni++)
    {
    std::cout << "filename # " << fni << " = ";
    std::cout << filenamesorig[fni] << std::endl;
    }

  typedef itk::GDCMImageIO           ImageIOTypeOrig;
  ImageIOTypeOrig::Pointer gdcmImageIOorig = ImageIOTypeOrig::New();
  //reader->SetImageIO( gdcmImageIOorig );

  ReaderTypeOrig::Pointer readerorig = ReaderTypeOrig::New();

  readerorig->SetImageIO( gdcmImageIOorig );
  readerorig->SetFileNames( filenamesorig );

  //end of added code

// Software Guide : BeginLatex
//
// The reading of the image is triggered by invoking \code{Update()} in the
// reader.
//
// Software Guide : EndLatex


  try
    {
// Software Guide : BeginCodeSnippet
    readerorig->Update();
// Software Guide : EndCodeSnippet
    }
  catch (itk::ExceptionObject & e)
    {
    std::cerr << "exception in file reader " << std::endl;
    std::cerr << e.GetDescription() << std::endl;
    std::cerr << e.GetLocation() << std::endl;
    return EXIT_FAILURE;
    }

  typedef itk::Image< InputPixelType, Dimension > InputImageType2;

  typedef itk::GDCMSeriesFileNames                NamesGeneratorTypeProc;
  NamesGeneratorTypeProc::Pointer namesGeneratorproc =
NamesGeneratorTypeProc::New();

  namesGeneratorproc->SetInputDirectory( argv[2] );

  typedef itk::Image< InputPixelType, Dimension >      ImageTypeProc;
  typedef itk::ImageSeriesReader< ImageTypeProc >     ReaderTypeProc;

  const ReaderTypeProc::FileNamesContainer & filenamesproc =
                            namesGeneratorproc->GetInputFileNames();

  numberOfFilenames =  filenamesproc.size();
  std::cout << numberOfFilenames << std::endl;
  for(unsigned int fni = 0; fni<numberOfFilenames; fni++)
    {
    std::cout << "filename # " << fni << " = ";
    std::cout << filenamesproc[fni] << std::endl;
    }

  typedef itk::GDCMImageIO           ImageIOTypeProc;
  ImageIOTypeProc::Pointer gdcmImageIOproc = ImageIOTypeProc::New();

  ReaderTypeProc::Pointer readerproc = ReaderTypeProc::New();

  readerproc->SetImageIO( gdcmImageIOproc );
  readerproc->SetFileNames( filenamesproc );

  try
    {
    readerproc->Update();
    }
  catch (itk::ExceptionObject & e)
    {
    std::cerr << "exception in file reader " << std::endl;
    std::cerr << e.GetDescription() << std::endl;
    std::cerr << e.GetLocation() << std::endl;
    return EXIT_FAILURE;
    }

  typedef itk::MetaDataObject< std::string > MetaDataStringType;

  typedef itk::MetaDataDictionary   DictionaryType1b;
  typedef itk::MetaDataDictionary   DictionaryType2b;

  std::vector<DictionaryType2b*>         pdictArray2b;

  DictionaryType1b::ConstIterator itr1b;
  DictionaryType1b::ConstIterator end1b;

  DictionaryType2b::ConstIterator itr2b;
  DictionaryType2b::ConstIterator end2b;

  for ( unsigned int idx = 0;
                  idx < readerproc->GetMetaDataDictionaryArray()->size();
                  idx++ )
            {

                itk::MetaDataDictionary* pdictionary1b = new
itk::MetaDataDictionary;
                itk::MetaDataDictionary* pSrc1b =
(*(readerorig->GetMetaDataDictionaryArray()))[idx];

        itk::MetaDataDictionary* pdictionary2b = new
itk::MetaDataDictionary;
                itk::MetaDataDictionary* pSrc2b =
(*(readerproc->GetMetaDataDictionaryArray()))[idx];

                if ( pSrc2b )
                {
          *pdictionary1b = (*pSrc1b);
          *pdictionary2b = (*pSrc2b);


          itr1b = pdictionary1b->Begin();
          end1b = pdictionary1b->End();

          itr2b = pdictionary2b->Begin();
          end2b = pdictionary2b->End();

          while( itr1b != end1b )
            {
              itk::MetaDataObjectBase::Pointer  entry1b = itr1b->second;

              MetaDataStringType::Pointer entryvalue1b =
            dynamic_cast<MetaDataStringType *>( entry1b.GetPointer() );

              std::string tagkey1b   = itr1b->first;


              DictionaryType2b::ConstIterator tagItr2b =
pdictionary2b->Find( tagkey1b );

              if( tagItr2b == end2b )
            {
              std::string tagkey   = itr1b->first;
              std::string tagvalue = entryvalue1b->GetMetaDataObjectValue();
              //std::cout << tagkey <<  " = " << tagvalue << std::endl;
              itk::EncapsulateMetaData<std::string>( *pdictionary2b, tagkey
, tagvalue );
            }

              ++itr1b;
            }


          std::string entryIdMR = "0008|0060";
          std::string valueMR = "MR";
          itk::EncapsulateMetaData<std::string>( *pdictionary2b, entryIdMR,
valueMR );


          pdictArray2b.push_back( pdictionary2b );

                }
            }

  typedef unsigned short    OutputPixelType;
  const unsigned int      OutputDimension = 2;

  typedef itk::Image< OutputPixelType, OutputDimension >    Image2DType;

  typedef itk::ImageSeriesWriter<
  ImageTypeProc, Image2DType >  SeriesWriterType;

  SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();

  seriesWriter->SetMetaDataDictionaryArray( &pdictArray2b );

  seriesWriter->SetInput( readerproc->GetOutput() );
  seriesWriter->SetImageIO( gdcmImageIOproc );

  namesGeneratorproc->SetOutputDirectory( argv[3] );

  seriesWriter->SetFileNames( namesGeneratorproc->GetOutputFileNames() );

  try
    {
    seriesWriter->Update();
    }
  catch (itk::ExceptionObject & e)
    {
    std::cerr << "exception in file writer " << std::endl;
    std::cerr << e.GetDescription() << std::endl;
    std::cerr << e.GetLocation() << std::endl;
    return EXIT_FAILURE;
    }

  // Software Guide : BeginLatex
  //
  // Remember again, that modifying the header entries of a DICOM file
involves
  // very serious risks for patients and therefore must be done with extreme
  // caution.
  //
  // Software Guide : EndLatex


  return EXIT_SUCCESS;

}


Thanks,
John


2011/2/17 Jon Haitz Legarreta Gorroño <jhlegarreta at vicomtech.org>

> Hi there,
>
> I'm using ITK and GDCM to convert to DICOM format a stereolitography model
> I built.
> I used a software to convert between .stl and DICOM. The thing is that the
> header I got is apparently lacking some fields that prevent the DICOM files
> from being correctly loaded by some DICOM viewers/workstations.
>
> I was thinking that editing the DICOM header would allow me to solve the
> problem. I know editing the DICOM header is not desirable, but in this case
> my source is not a DICOM node (nobody to blame on exepct the software used
> to convert between STL and DICOM!) and it's just an artificial model I
> built.
>
> What I basically do is this:
>
> 1. Let the user edit the source DICOM header
> 2. Try to save the edited header together with the original slices into a
> new dataset.
>
> I'm puzzled when I check that the members of the itk::GDCMImageIO object I
> handle for the itk::ImageSeriesWriter do not reflect the changes in the
> dictionary after I've called the methods to change the original tags by the
> new values, that is, in short:
>
>
> std::vector<itk::MetaDataDictionary *>  dictionaryArray = new
> std::vector<itk::MetaDataDictionary*>  ;
> itk::GDCMImageIO::Pointer gdcmIO = itk::GDCMImageIO::New();
> itk::ImageSeriesWriter< TInputImage, TOutputImage>::Pointer seriesWriter =
> itk::ImageSeriesWriter< TInputImage, TOutputImage>::New(); // TInputImage
> and TOutputImage are properly set somewhere above
> itk::NumericSeriesFileNames::Pointer outputNames =
> itk::NumericSeriesFileNames::New();
> itk::MetaDataDictionary *toDict= new itk::MetaDataDictionary ();
>
> // Do for each tag of the DICOM Dictionary
> itk::EncapsulateMetaData<std::string>( *toDict, tagKey, tagValue );
> //
>
> dictionaryArray->push_back( toDict );
>
> seriesWriter->SetInput( PointerToITKImage );
>
> // Generate output names
> ...
>
> seriesWriter->SetImageIO( gdcmIO );
> seriesWriter->SetFileNames( outputNames->GetFileNames() );
> seriesWriter->SetMetaDataDictionaryArray( dictionaryArray );
> seriesWriter->Update();
>
> Even if at disk the written header tags are the user-edited ones, at this
> point of the program the gdcmIO object still contains the information
> related to the original dataset. Is that the expected behavior?
>
> I had a look at some older posts concerning the DICOM header issue but
> didn't find an answer to this.
> I also had a look at an (old) ITK example
> (DicomImageReadChangeHeaderWrite.cxx).
>
>
> For sure, I am missing some concept.
>
> Thank you,
> JON HAITZ
>
>
>
>
> _____________________________________
> Powered by www.kitware.com
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Kitware offers ITK Training Courses, for more information visit:
> http://www.kitware.com/products/protraining.html
>
> Please keep messages on-topic and check the ITK FAQ at:
> http://www.itk.org/Wiki/ITK_FAQ
>
> Follow this link to subscribe/unsubscribe:
> http://www.itk.org/mailman/listinfo/insight-users
>



-- 
John Drozd
Post-Doctoral Fellow, Robarts Research Institute
The University of Western Ontario
London, ON, Canada
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.itk.org/pipermail/insight-users/attachments/20110217/0513779e/attachment.htm>


More information about the Insight-users mailing list