Hi Jon,<br><br>Since this is not shown in the ITK software guide,<br>I thought this code that I wrote based on <a href="http://www.paraview.org/Bug/view.php?id=6258&amp;nbn=1" target="_blank">http://www.paraview.org/Bug/view.php?id=6258&amp;nbn=1</a> ,  might help someone:<br>

It shows how to change a MetaDataDictionaryArray when dealing with <span class="il">changing</span> <span class="il">header</span> info in Dicom series.<br><br>Thanks,<br>John<br><br>#if defined(_MSC_VER)<br>#pragma warning ( disable : 4786 )<br>
#endif<br><br>#ifdef __BORLANDC__<br>
#define ITK_LEAN_AND_MEAN<br>#endif<br><br>//<br>//  This example illustrates how to change a MetaDataDictionaryArray.<br>//  This example illustrates how to read two DICOM series, adds key <br>//  tags that are in the second DICOM series to the first DICOM series<br>

//  and write it back with some changed <span class="il">header</span> information as another <br>//  DICOM series.  This can be useful when sometimes conversion between<br>//  different file formats as between NIFTI and DICOM and some dicom tags <br>

//  are lost.<br>//  The keys are defined in the file<br>//<br>//  \code{Insight/Utilities/gdcm/<div id=":366">Dicts/dicomV3.dic}<br>//  <br>//  Please note that modifying the content of a DICOM <span class="il">header</span> is a very risky<br>
//  operation. The <span class="il">Header</span> contains fundamental information about the patient<br>
//  and therefore its consistency must be protected from any data corruption.<br>//  Before attempting to modify the DICOM headers of your files, you must make<br>//  sure that you have a very good reason for doing so, and that you can ensure<br>

//  that this information change will not result in a lower quality of health<br>//  care to be delivered to the patient.<br>//<br>//  \index{DICOM!<span class="il">Changing</span> Headers}<br>//<br><br>// Software Guide : BeginLatex<br>
// <br>// We must start by including the relevant <span class="il">header</span> files. Here we include the<br>
// image reader, image writer, the image, the Meta data dictionary and its<br>// entries the Meta data objects and the GDCMImageIO. The Meta data dictionary<br>// is the data container that stores all the entries from the DICOM <span class="il">header</span> once<br>

// the DICOM image file is read into an ITK image.<br>//<br>// Software Guide : EndLatex<br><br>// Software Guide : BeginCodeSnippet<br>#include &quot;itkImageFileReader.h&quot;<br>#include &quot;itkImageFileWriter.h&quot;<br>

#include &quot;itkImage.h&quot;<br>#include &quot;itkMetaDataDictionary.h&quot;<br>#include &quot;itkMetaDataObject.h&quot;<br>#include &quot;itkGDCMImageIO.h&quot;<br>// Software Guide : EndCodeSnippet<br><br>#include &lt;list&gt;<br>

#include &lt;fstream&gt;<br><br><br>#include &quot;itkGDCMImageIO.h&quot;<br>#include &quot;itkGDCMSeriesFileNames.h&quot;<br>#include &quot;itkImageSeriesReader.h&quot;<br>#include &quot;itkImageSeriesWriter.h&quot;<br>
<br>
<br>int main(int argc, char* argv[])<br>{<br><br>  if( argc &lt; 4 )<br>    {<br>     
std::cerr &lt;&lt; &quot;Usage: &quot; &lt;&lt; argv[0] &lt;&lt; &quot;
OriginalDicomImageDIR ProcessedDicomImageDIR OutputDicomImageDIR\n&quot;;<br>
      //DIR means Directory<br><br><br>    return EXIT_FAILURE;<br>    }<br> <br>  typedef unsigned short InputPixelType;<br><br>  <br>  const unsigned int   Dimension = 3;<br><br>  typedef itk::Image&lt; InputPixelType, Dimension &gt; InputImageType;<br>

<br>  typedef itk::GDCMSeriesFileNames                NamesGeneratorTypeOrig;<br>  NamesGeneratorTypeOrig::Pointer namesGeneratororig = NamesGeneratorTypeOrig::New();<br><br>  namesGeneratororig-&gt;SetInputDirectory( argv[1] );<br>

<br>  typedef itk::Image&lt; InputPixelType, Dimension &gt;      ImageTypeOrig;<br>  typedef itk::ImageSeriesReader&lt; ImageTypeOrig &gt;     ReaderTypeOrig;<br><br>  const ReaderTypeOrig::FileNamesContainer &amp; filenamesorig = <br>

                            namesGeneratororig-&gt;GetInputFileNames();<br><br>  unsigned int numberOfFilenames =  filenamesorig.size();<br>  std::cout &lt;&lt; numberOfFilenames &lt;&lt; std::endl; <br>  for(unsigned int fni = 0; fni&lt;numberOfFilenames; fni++)<br>

    {<br>    std::cout &lt;&lt; &quot;filename # &quot; &lt;&lt; fni &lt;&lt; &quot; = &quot;;<br>    std::cout &lt;&lt; filenamesorig[fni] &lt;&lt; std::endl;<br>    }<br><br>  typedef itk::GDCMImageIO           ImageIOTypeOrig;<br>

  ImageIOTypeOrig::Pointer gdcmImageIOorig = ImageIOTypeOrig::New();<br>  //reader-&gt;SetImageIO( gdcmImageIOorig );<br><br>  ReaderTypeOrig::Pointer readerorig = ReaderTypeOrig::New();<br><br>  readerorig-&gt;SetImageIO( gdcmImageIOorig );<br>

  readerorig-&gt;SetFileNames( filenamesorig );<br><br>  //end of added code<br><br>// Software Guide : BeginLatex<br>// <br>// The reading of the image is triggered by invoking \code{Update()} in the<br>// reader.<br>//<br>

// Software Guide : EndLatex<br><br><br>  try<br>    {<br>// Software Guide : BeginCodeSnippet<br>    readerorig-&gt;Update();<br>// Software Guide : EndCodeSnippet<br>    }<br>  catch (itk::ExceptionObject &amp; e)<br>    {<br>

    std::cerr &lt;&lt; &quot;exception in file reader &quot; &lt;&lt; std::endl;<br>    std::cerr &lt;&lt; e.GetDescription() &lt;&lt; std::endl;<br>    std::cerr &lt;&lt; e.GetLocation() &lt;&lt; std::endl;<br>    return EXIT_FAILURE;<br>

    }<br><br>  typedef itk::Image&lt; InputPixelType, Dimension &gt; InputImageType2;<br><br>  typedef itk::GDCMSeriesFileNames                NamesGeneratorTypeProc;<br>  NamesGeneratorTypeProc::Pointer namesGeneratorproc = NamesGeneratorTypeProc::New();<br>

<br>  namesGeneratorproc-&gt;SetInputDirectory( argv[2] );<br><br>  typedef itk::Image&lt; InputPixelType, Dimension &gt;      ImageTypeProc;<br>  typedef itk::ImageSeriesReader&lt; ImageTypeProc &gt;     ReaderTypeProc;<br>

<br>  const ReaderTypeProc::FileNamesContainer &amp; filenamesproc = <br>                            namesGeneratorproc-&gt;GetInputFileNames();<br>  <br>  numberOfFilenames =  filenamesproc.size();<br>  std::cout &lt;&lt; numberOfFilenames &lt;&lt; std::endl; <br>

  for(unsigned int fni = 0; fni&lt;numberOfFilenames; fni++)<br>    {<br>    std::cout &lt;&lt; &quot;filename # &quot; &lt;&lt; fni &lt;&lt; &quot; = &quot;;<br>    std::cout &lt;&lt; filenamesproc[fni] &lt;&lt; std::endl;<br>

    }<br><br>  typedef itk::GDCMImageIO           ImageIOTypeProc;<br>  ImageIOTypeProc::Pointer gdcmImageIOproc = ImageIOTypeProc::New();<br><br>  ReaderTypeProc::Pointer readerproc = ReaderTypeProc::New();<br><br>  readerproc-&gt;SetImageIO( gdcmImageIOproc );<br>

  readerproc-&gt;SetFileNames( filenamesproc );<br><br>  try<br>    {<br>    readerproc-&gt;Update();<br>    }<br>  catch (itk::ExceptionObject &amp; e)<br>    {<br>    std::cerr &lt;&lt; &quot;exception in file reader &quot; &lt;&lt; std::endl;<br>

    std::cerr &lt;&lt; e.GetDescription() &lt;&lt; std::endl;<br>    std::cerr &lt;&lt; e.GetLocation() &lt;&lt; std::endl;<br>    return EXIT_FAILURE;<br>    }<br><br>  typedef itk::MetaDataObject&lt; std::string &gt; MetaDataStringType;<br>

  <br>  typedef itk::MetaDataDictionary   DictionaryType1b;<br>  typedef itk::MetaDataDictionary   DictionaryType2b;<br>  <br>  std::vector&lt;DictionaryType2b*&gt;         pdictArray2b;<br><br>  DictionaryType1b::ConstIterator itr1b;<br>

  DictionaryType1b::ConstIterator end1b;<br><br>  DictionaryType2b::ConstIterator itr2b;<br>  DictionaryType2b::ConstIterator end2b;<br>  <br>  for ( unsigned int idx = 0;<br>                  idx &lt; readerproc-&gt;GetMetaDataDictionaryArray()-&gt;size();<br>

                  idx++ )<br>            {<br><br>                itk::MetaDataDictionary* pdictionary1b = new itk::MetaDataDictionary;<br>                itk::MetaDataDictionary* pSrc1b = (*(readerorig-&gt;GetMetaDataDictionaryArray()))[idx];<br>

<br>        itk::MetaDataDictionary* pdictionary2b = new itk::MetaDataDictionary;<br>                itk::MetaDataDictionary* pSrc2b = (*(readerproc-&gt;GetMetaDataDictionaryArray()))[idx];<br><br>                if ( pSrc2b )<br>

                {<br>          *pdictionary1b = (*pSrc1b);<br>          *pdictionary2b = (*pSrc2b);<br><br><br>          itr1b = pdictionary1b-&gt;Begin();<br>          end1b = pdictionary1b-&gt;End();<br><br>          itr2b = pdictionary2b-&gt;Begin();<br>

          end2b = pdictionary2b-&gt;End();<br>          <br>          while( itr1b != end1b )<br>            {<br>              itk::MetaDataObjectBase::Pointer  entry1b = itr1b-&gt;second;<br><br>              MetaDataStringType::Pointer entryvalue1b = <br>

            dynamic_cast&lt;MetaDataStringType *&gt;( entry1b.GetPointer() );<br><br>              std::string tagkey1b   = itr1b-&gt;first;<br><br>    <br>              DictionaryType2b::ConstIterator tagItr2b = pdictionary2b-&gt;Find( tagkey1b );<br>

    <br>              if( tagItr2b == end2b )<br>            {<br>              std::string tagkey   = itr1b-&gt;first;<br>              std::string tagvalue = entryvalue1b-&gt;GetMetaDataObjectValue();<br>              //std::cout &lt;&lt; tagkey &lt;&lt;  &quot; = &quot; &lt;&lt; tagvalue &lt;&lt; std::endl;<br>

              itk::EncapsulateMetaData&lt;std::string&gt;( *pdictionary2b, tagkey , tagvalue ); <br>            }<br>              <br>              ++itr1b;<br>            }<br>          <br>  <br>          std::string entryIdMR = &quot;0008|0060&quot;;<br>

          std::string valueMR = &quot;MR&quot;;<br>          itk::EncapsulateMetaData&lt;std::string&gt;( *pdictionary2b, entryIdMR, valueMR );<br><br>                    <br>          pdictArray2b.push_back( pdictionary2b );<br>

          <br>                }<br>            }<br><br>  typedef unsigned short    OutputPixelType;<br>  const unsigned int      OutputDimension = 2;<br><br>  typedef itk::Image&lt; OutputPixelType, OutputDimension &gt;    Image2DType;<br>

<br>  typedef itk::ImageSeriesWriter&lt; <br>  ImageTypeProc, Image2DType &gt;  SeriesWriterType;<br><br>  SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();<br><br>  seriesWriter-&gt;SetMetaDataDictionaryArray( &amp;pdictArray2b );<br>

    <br>  seriesWriter-&gt;SetInput( readerproc-&gt;GetOutput() );<br>  seriesWriter-&gt;SetImageIO( gdcmImageIOproc );<br><br>  namesGeneratorproc-&gt;SetOutputDirectory( argv[3] );<br><br>  seriesWriter-&gt;SetFileNames( namesGeneratorproc-&gt;GetOutputFileNames() );<br>

<br>  try<br>    {<br>    seriesWriter-&gt;Update();<br>    }<br>  catch (itk::ExceptionObject &amp; e)<br>    {<br>    std::cerr &lt;&lt; &quot;exception in file writer &quot; &lt;&lt; std::endl;<br>    std::cerr &lt;&lt; e.GetDescription() &lt;&lt; std::endl;<br>

    std::cerr &lt;&lt; e.GetLocation() &lt;&lt; std::endl;<br>    return EXIT_FAILURE;<br>    }<br><br>  // Software Guide : BeginLatex<br>  // <br>  // Remember again, that modifying the <span class="il">header</span> entries of a DICOM file involves<br>

  // very serious risks for patients and therefore must be done with extreme<br>  // caution.<br>  //<br>  // Software Guide : EndLatex<br><br><br>  return EXIT_SUCCESS;<br><br>}<br><br><br>Thanks,<br><font color="#888888">John</font></div>
<br><br><div class="gmail_quote">2011/2/17 Jon Haitz Legarreta Gorroño <span dir="ltr">&lt;<a href="mailto:jhlegarreta@vicomtech.org">jhlegarreta@vicomtech.org</a>&gt;</span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi there,<br>
<br>
I&#39;m using ITK and GDCM to convert to DICOM format a stereolitography model I built.<br>
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.<br>
<br>
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&#39;s just an artificial model I built.<br>

<br>
What I basically do is this:<br>
<br>
1. Let the user edit the source DICOM header<br>
2. Try to save the edited header together with the original slices into a new dataset.<br>
<br>
I&#39;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&#39;ve called the methods to change the original tags by the new values, that is, in short:<br>

<br>
<br>
std::vector&lt;itk::MetaDataDictionary *&gt;  dictionaryArray = new std::vector&lt;itk::MetaDataDictionary*&gt;  ;<br>
itk::GDCMImageIO::Pointer gdcmIO = itk::GDCMImageIO::New();<br>
itk::ImageSeriesWriter&lt; TInputImage, TOutputImage&gt;::Pointer seriesWriter = itk::ImageSeriesWriter&lt; TInputImage, TOutputImage&gt;::New(); // TInputImage and TOutputImage are properly set somewhere above<br>
itk::NumericSeriesFileNames::Pointer outputNames = itk::NumericSeriesFileNames::New();<br>
itk::MetaDataDictionary *toDict= new itk::MetaDataDictionary ();<br>
<br>
// Do for each tag of the DICOM Dictionary<br>
itk::EncapsulateMetaData&lt;std::string&gt;( *toDict, tagKey, tagValue );<br>
//<br>
<br>
dictionaryArray-&gt;push_back( toDict );<br>
<br>
seriesWriter-&gt;SetInput( PointerToITKImage );<br>
<br>
// Generate output names<br>
...<br>
<br>
seriesWriter-&gt;SetImageIO( gdcmIO );<br>
seriesWriter-&gt;SetFileNames( outputNames-&gt;GetFileNames() );<br>
seriesWriter-&gt;SetMetaDataDictionaryArray( dictionaryArray );<br>
seriesWriter-&gt;Update();<br>
<br>
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?<br>
<br>
I had a look at some older posts concerning the DICOM header issue but didn&#39;t find an answer to this.<br>
I also had a look at an (old) ITK example (DicomImageReadChangeHeaderWrite.cxx).<br>
<br>
<br>
For sure, I am missing some concept.<br>
<br>
Thank you,<br>
JON HAITZ<br>
<br>
<br>
<br>
<br>
_____________________________________<br>
Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
<br>
Visit other Kitware open-source projects at<br>
<a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
<br>
Kitware offers ITK Training Courses, for more information visit:<br>
<a href="http://www.kitware.com/products/protraining.html" target="_blank">http://www.kitware.com/products/protraining.html</a><br>
<br>
Please keep messages on-topic and check the ITK FAQ at:<br>
<a href="http://www.itk.org/Wiki/ITK_FAQ" target="_blank">http://www.itk.org/Wiki/ITK_FAQ</a><br>
<br>
Follow this link to subscribe/unsubscribe:<br>
<a href="http://www.itk.org/mailman/listinfo/insight-users" target="_blank">http://www.itk.org/mailman/listinfo/insight-users</a><br>
</blockquote></div><br><br clear="all"><br>-- <br><div>John Drozd<br></div>


<div>Post-Doctoral Fellow, Robarts Research Institute</div>
<div>The University of Western Ontario</div>
<div>London, ON, Canada<br></div>
<br>