I need help, please! Here is my problem:<br><br>I have a MR DICOM series with the image orientation (patient) (0020, 0037): 0\1\0\0\0\-1 (sagittal). However, after I read the DICOM series and writing them out right way, The newly written DICOM series have a different the Image Orientation (patient) 1\0\0\0\1\0 (axial) . This is causing serious problems if I don't correct it. However, the Image Orientation can not be overwritten in the writing process!<br>
<br>Here is the sample code I used: <br><br><br>// Software Guide : BeginCodeSnippet<br>#include "itkGDCMImageIO.h"<br>#include "itkGDCMSeriesFileNames.h"<br>#include "itkImageSeriesReader.h"<br>
#include "itkImageSeriesWriter.h"<br>// Software Guide : EndCodeSnippet<br><br>#include <vector><br>#include "itksys/SystemTools.hxx"<br><br>int readWriteDicom3D()<br>{<br><br> // Software Guide : BeginLatex<br>
//<br> // As a second step, we define the image type to be used in this example. This<br> // is done by explicitly selecting a pixel type and a dimension. Using the<br> // image type we can define the type of the series reader.<br>
//<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> typedef signed short PixelType;<br> const unsigned int Dimension = 3;<br><br> typedef itk::Image< PixelType, Dimension > ImageType;<br>
typedef itk::ImageSeriesReader< ImageType > ReaderType;<br> // Software Guide : EndCodeSnippet<br><br> // Software Guide : BeginLatex<br> //<br> // We also declare types for the \doxygen{GDCMImageIO} object that will<br>
// actually read and write the DICOM images, and the<br> // \doxygen{GDCMSeriesFileNames} object that will generate and order all the<br> // filenames for the slices composing the volume dataset. Once we have the<br>
// types, we proceed to create instances of both objects.<br> //<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> typedef itk::GDCMImageIO ImageIOType;<br> typedef itk::GDCMSeriesFileNames NamesGeneratorType;<br>
<br> ImageIOType::Pointer gdcmIO = ImageIOType::New();<br> NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();<br> // Software Guide : EndCodeSnippet<br><br> // Software Guide : BeginLatex<br> //<br>
// Just as the previous example, we get the DICOM filenames from the<br> // directory. Note however, that in this case we use the<br> // \code{SetInputDirectory()} method instead of the \code{SetDirectory()}.<br> // This is done because in the present case we will use the filenames<br>
// generator for producing both the filenames for reading and the filenames<br> // for writing. Then, we invoke the \code{GetInputFileNames()} method in order<br> // to get the list of filenames to read.<br> //<br>
// Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> namesGenerator->SetInputDirectory( "D:\\apps\\SyntheticCT\\Data\\Images\\output\\WBTest\\temp" );<br><br> const ReaderType::FileNamesContainer & filenames =<br>
namesGenerator->GetInputFileNames();<br> // Software Guide : EndCodeSnippet<br><br> unsigned int numberOfFilenames = filenames.size();<br> std::cout << numberOfFilenames << std::endl;<br>
for(unsigned int fni = 0; fni<numberOfFilenames; fni++)<br> {<br> std::cout << "filename # " << fni << " = ";<br> std::cout << filenames[fni] << std::endl;<br>
}<br><br> // Software Guide : BeginLatex<br> //<br> // We construct one instance of the series reader object. Set the DICOM image<br> // IO object to be use with it, and set the list of filenames to read.<br> //<br>
// Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> ReaderType::Pointer reader = ReaderType::New();<br><br> reader->SetImageIO( gdcmIO );<br> reader->SetFileNames( filenames );<br> // Software Guide : EndCodeSnippet<br>
<br> // Software Guide : BeginLatex<br> //<br> // We can trigger the reading process by calling the \code{Update()} method on<br> // the series reader. It is wise to put this invocation inside a<br> // \code{try/catch} block since the process may eventually throw exceptions.<br>
//<br> // Software Guide : EndLatex<br><br> try<br> {<br> // Software Guide : BeginCodeSnippet<br> reader->Update();<br> // Software Guide : EndCodeSnippet<br> }<br> catch (itk::ExceptionObject &excp)<br>
{<br> std::cerr << "Exception thrown while writing the image" << std::endl;<br> std::cerr << excp << std::endl;<br> return EXIT_FAILURE;<br> }<br><br> // Software Guide : BeginLatex<br>
//<br> // At this point we would have the volumetric data loaded in memory and we can<br> // get access to it by invoking the \code{GetOutput()} method in the reader.<br> //<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginLatex<br>
//<br> // Now we can prepare the process for writing the dataset. First, we take the<br> // name of the output directory from the command line arguments.<br> //<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br>
const char * outputDirectory = "D:\\apps\\SyntheticCT\\Data\\Images\\output\\WBTest\\temp_output";<br> // Software Guide : EndCodeSnippet<br><br> // Software Guide : BeginLatex<br> //<br> // Second, we make sure the output directory exist, using the cross platform<br>
// tools: itksys::SystemTools. In this case we select to create the directory<br> // if it does not exist yet.<br> //<br> // \index{itksys!SystemTools}<br> // \index{itksys!MakeDirectory}<br> // \index{SystemTools}<br>
// \index{SystemTools!MakeDirectory}<br> // \index{MakeDirectory!SystemTools}<br> // \index{MakeDirectory!itksys}<br> //<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> itksys::SystemTools::MakeDirectory( outputDirectory );<br>
// Software Guide : EndCodeSnippet<br><br><br><br><br>//itk::MetaDataDictionary & dict = gdcmIO->GetMetaDataDictionary();<br>//itk::EncapsulateMetaData<std::string>(dict, "0008|0060", "CT");<br>
//itk::EncapsulateMetaData<std::string>(dict, "0008|0008", "ORIGINAL\\PRIMARY\\SAGITTAL");<br>//itk::EncapsulateMetaData<std::string>(dict, "0020|0037", "0\\1\\0\\0\\0\\-1 ");<br>
<br><br><br> // Software Guide : BeginLatex<br> //<br> // We instantiate explicitly the image type to be used for writing, and use the<br> // image type for instantiating the type of the series writer.<br> //<br> // Software Guide : EndLatex<br>
<br> // Software Guide : BeginCodeSnippet<br> typedef signed short OutputPixelType;<br> const unsigned int OutputDimension = 2;<br><br> typedef itk::Image< OutputPixelType, OutputDimension > Image2DType;<br>
<br> typedef itk::ImageSeriesWriter<<br> ImageType, Image2DType > SeriesWriterType;<br> // Software Guide : EndCodeSnippet<br><br> // Software Guide : BeginLatex<br> //<br> // We construct a series writer and connect to its input the output from the<br>
// reader. Then we pass the GDCM image IO object in order to be able to write<br> // the images in DICOM format.<br> //<br> // the writer filter. Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br>
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();<br><br> seriesWriter->SetInput( reader->GetOutput() );<br> seriesWriter->SetImageIO( gdcmIO );<br> // Software Guide : EndCodeSnippet<br><br>
// Software Guide : BeginLatex<br> //<br> // It is time now to setup the GDCMSeriesFileNames to generate new filenames<br> // using another output directory. Then simply pass those newly generated<br> // files to the series writer.<br>
//<br> // \index{GDCMSeriesFileNames!SetOutputDirectory()}<br> // \index{GDCMSeriesFileNames!GetOutputFileNames()}<br> // \index{ImageSeriesWriter!SetFileNames()}<br> //<br> // Software Guide : EndLatex<br><br>
// Software Guide : BeginCodeSnippet<br> namesGenerator->SetOutputDirectory( outputDirectory );<br><br> seriesWriter->SetFileNames( namesGenerator->GetOutputFileNames() );<br> // Software Guide : EndCodeSnippet<br>
<br><br><br><br> // Software Guide : BeginLatex<br> //<br> // The following line of code is extremely important for this process to work<br> // correctly. The line is taking the MetaDataDictionary from the input reader<br>
// and passing it to the output writer. The reason why this step is so<br> // important is that the MetaDataDictionary contains all the entries of the<br> // input DICOM header.<br> //<br> // \index{itk::ImageSeriesReader!GetMetaDataDictionaryArray()}<br>
// \index{itk::ImageSeriesWriter!SetMetaDataDictionaryArray()}<br> //<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> seriesWriter->SetMetaDataDictionaryArray(<br> reader->GetMetaDataDictionaryArray() );<br>
// Software Guide : EndCodeSnippet<br><br> // Software Guide : BeginLatex<br> //<br> // Finally we trigger the writing process by invoking the \code{Update()} method<br> // in the series writer. We place this call inside a try/catch block, in case<br>
// any exception is thrown during the writing process.<br> //<br> // Software Guide : EndLatex<br><br> // Software Guide : BeginCodeSnippet<br> try<br> {<br> seriesWriter->Update();<br> }<br> catch( itk::ExceptionObject & excp )<br>
{<br> std::cerr << "Exception thrown while writing the series " << std::endl;<br> std::cerr << excp << std::endl;<br> return EXIT_FAILURE;<br> }<br> // Software Guide : EndCodeSnippet<br>
<br> // Software Guide : BeginLatex<br> //<br> // Please keep in mind that you should avoid to generate DICOM files that have<br> // the appearance of being produced by a scanner. It should be clear from the<br> // directory or filenames that this data was the result of the<br>
// execution of some sort of algorithm. This will help to prevent your dataset<br> // from being used as scanner data by accident.<br> //<br> // Software Guide : EndLatex<br><br> return EXIT_SUCCESS;<br>}<br><br>