[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