[Insight-users] DICOM orientation

John Drozd john.drozd at gmail.com
Tue Oct 6 15:38:01 EDT 2009


Hi Bill,

Thanks. The code you sent steered me in the right direction to fix the
problem.

I added the following lines to my code which fixed the problem:

//added these lines to fix the orientation problem
  fixedsubjectfilterwriter->UseInputMetaDataDictionaryOff();
  fixedsubjectfilterwriter->SetImageIO( gdcmImageIO );
//end of added code

I suppose when writing a DICOM series to a DICOM volume, I had to set
UseInputMetaDataDictionaryOff()

Unfortunately, this was not in the example code
Examples/IO/DicomSeriesReadImageWrite2.cxx

But it was in
Examples/IO/DicomImageReadWrite.cxx

Thanks again Bill and Harvey for helping me.

Take care,
john




On Tue, Oct 6, 2009 at 11:55 AM, Bill Lorensen <bill.lorensen at gmail.com>wrote:

> John,
>
> I've attached some code thta passes the metat data dictionary from the
> input to the output. This example does a resample, bout you should do
> a similar thing in your program.
>
> Bill
>
> On Tue, Oct 6, 2009 at 11:38 AM, John Drozd <john.drozd at gmail.com> wrote:
> > I have attached a screen capture of the Slicer views. The Slicer views on
> > the left are the original DICOM series (that are not flipped and fine).
> The
> > Slicer Views on the right are the outputted volume (after reading the
> series
> > from memory) and are flipped.  Note the -ve vs +ve values on the sliders,
> > indicating the radiologist vs neurologist views.
> >
> > John
> >
> > On Tue, Oct 6, 2009 at 10:21 AM, John Drozd <john.drozd at gmail.com>
> wrote:
> >>
> >> I invoke the program with:
> >>
> >> ./DeformableRegistration "param.file" "m000-talairach.dcm"
> >>
> "/trumpet/downloads/DeformableRegistration_Plugin/DeformableRegistration/datasubject"
> >>
> >> where the last item on the list is the name of the directory containing
> >> the dicom series.
> >>
> >> john
> >>
> >> On Tue, Oct 6, 2009 at 10:07 AM, John Drozd <john.drozd at gmail.com>
> wrote:
> >>>
> >>> Hi Bill,
> >>>
> >>> Yes, I did read in the original DICOM series into 3D Slicer and the
> >>> original series was not flipped and fine.  I was checking if ITK had
> read
> >>> the series correctly into memory, so I wrote it to a volume. I was
> writing
> >>> the volume out to see what was in memory and when I viewed the
> outputted
> >>> volume in 3D Slicer it was flipped.  In this case, I was basing my code
> on
> >>> Examples/IO/DicomSeriesReadImageWrite2.cxx
> >>> I plan to today read in the series and write it to a series (instead of
> a
> >>> volume) and see if the outputted series will be flipped (hopefully not)
> when
> >>> I view it in 3D Slicer.
> >>> By the way, as shown in Examples/IO/DicomImageReadWrite.cxx, I did read
> >>> in a dicom volume (a single file containing the talairach atlas) and
> wrote
> >>> it out to another dicom volume and the outputted volume this time was
> not
> >>> flipped when I viewed it in 3D Slicer.
> >>>
> >>> Below is my code that I used for reading a dicom series and writing to
> a
> >>> volume:
> >>> (It is part of a deformable registration program that I am writing
> based
> >>> on Examples/Registration/DeformableRegistration1.cxx so there are some
> >>> header files and code from that)
> >>> The pertinent reading and writing code is in red. (about 60 lines down)
> >>>
> >>>
> >>> #if defined(_MSC_VER)
> >>> #pragma warning ( disable : 4786 )
> >>> #endif
> >>>
> >>>
> >>> #include "itkImageFileReader.h"
> >>> #include "itkImageFileWriter.h"
> >>>
> >>> #include "itkRescaleIntensityImageFilter.h"
> >>> #include "itkHistogramMatchingImageFilter.h"
> >>>
> >>> //Added from DicomImageReadWrite.cxx
> >>> #include "itkGDCMImageIO.h"
> >>>
> >>> //Added from DicomSeriesReadImageWrite2.cxx
> >>> #include "itkOrientedImage.h"
> >>> #include "itkGDCMImageIO.h"
> >>> #include "itkGDCMSeriesFileNames.h"
> >>> #include "itkImageSeriesReader.h"
> >>>
> >>> #include "itkFEM.h"
> >>> #include "itkFEMRegistrationFilter.h"
> >>>
> >>> //  Next, we use \code{typedef}s to instantiate all necessary classes.
> >>> We
> >>> //  define the image and element types we plan to use to solve a
> >>> //  two-dimensional registration problem.  We define multiple element
> >>> //  types so that they can be used without recompiling the code.
> >>> //
> >>> //
> >>> //  Note that in order to solve a three-dimensional registration
> >>> //  problem, we would simply define 3D image and element types in lieu
> >>> //  of those above.  The following declarations could be used for a 3D
> >>> //  problem:
> >>>
> >>> typedef itk::Image<short, 3>                    fileImage3DType;
> >>> typedef itk::Image<short, 3>                            Image3DType;
> >>>
> >>> typedef itk::fem::Element3DC0LinearHexahedronMembrane   Element3DType;
> >>> typedef itk::fem::Element3DC0LinearTetrahedronMembrane  Element3DType2;
> >>>
> >>> //  Here, we instantiate the load types and explicitly template the
> >>> //  load implementation type.  We also define visitors that allow the
> >>> //  elements and loads to communicate with one another.
> >>>
> >>> typedef itk::fem::FiniteDifferenceFunctionLoad<Image3DType,Image3DType>
> >>> ImageLoadType;
> >>> template class itk::fem::ImageMetricLoadImplementation<ImageLoadType>;
> >>>
> >>> typedef Element3DType::LoadImplementationFunctionPointer     LoadImpFP;
> >>> typedef Element3DType::LoadType
> >>> ElementLoadType;
> >>>
> >>> typedef Element3DType2::LoadImplementationFunctionPointer
> LoadImpFP2;
> >>> typedef Element3DType2::LoadType
> >>> ElementLoadType2;
> >>>
> >>> typedef itk::fem::VisitorDispatcher<Element3DType,ElementLoadType,
> >>> LoadImpFP>
> >>>
> >>> DispatcherType;
> >>>
> >>> typedef itk::fem::VisitorDispatcher<Element3DType2,ElementLoadType2,
> >>> LoadImpFP2>
> >>>
> >>> DispatcherType2;
> >>>
> >>> //  Once all the necessary components have been instantiated, we can
> >>> //  instantiate the \doxygen{FEMRegistrationFilter}, which depends on
> the
> >>> //  image input and output types.
> >>>
> >>> typedef itk::fem::FEMRegistrationFilter<Image3DType,Image3DType>
> >>> RegistrationType;
> >>>
> >>> int main(int argc, char *argv[])
> >>> {
> >>>   char *paramname;
> >>>   if ( argc < 2 )
> >>>     {
> >>>     std::cout << "Parameter file name missing" << std::endl;
> >>>     std::cout << "Usage: " << argv[0] << " param.file" << " atlas.file"
> >>> << " subject.file" <<std::endl;
> >>>     return EXIT_FAILURE;
> >>>     }
> >>>   else
> >>>     {
> >>>     paramname=argv[1];
> >>>     }
> >>>
> >>> //  The \doxygen{fem::ImageMetricLoad} must be registered before it
> >>> //  can be used correctly with a particular element type.  An example
> >>> //  of this is shown below for ElementType.  Similar
> >>> //  definitions are required for all other defined element types.
> >>>
> >>>
> >>> // Register the correct load implementation with the element-typed
> >>> visitor dispatcher.
> >>>   {
> >>> //  Software Guide : BeginCodeSnippet
> >>>   Element3DType::LoadImplementationFunctionPointer fp =
> >>>
> >>>
> &itk::fem::ImageMetricLoadImplementation<ImageLoadType>::ImplementImageMetricLoad;
> >>>   DispatcherType::RegisterVisitor((ImageLoadType*)0,fp);
> >>> //  Software Guide : EndCodeSnippet
> >>>   }
> >>>   {
> >>>   Element3DType2::LoadImplementationFunctionPointer fp =
> >>>
> >>>
> &itk::fem::ImageMetricLoadImplementation<ImageLoadType>::ImplementImageMetricLoad;
> >>>   DispatcherType2::RegisterVisitor((ImageLoadType*)0,fp);
> >>>   }
> >>>
> >>> //  In order to begin the registration, we declare an instance of the
> >>> //  FEMRegistrationFilter.  For simplicity, we will call
> >>> //  it \code{registrationFilter}.
> >>>
> >>>   RegistrationType::Pointer registrationFilter =
> RegistrationType::New();
> >>>
> >>>   typedef short InputPixelType;
> >>>   const unsigned int   InputDimension = 3;
> >>>
> >>>   typedef itk::Image< InputPixelType, InputDimension > InputImageType;
> >>>
> >>>   typedef itk::ImageSeriesReader< InputImageType > ReaderSeriesType;
> >>>
> >>>
> >>>   ReaderSeriesType::Pointer fixedsubjectfilter =
> ReaderSeriesType::New();
> >>>
> >>>  typedef itk::GDCMImageIO           ImageIOType;
> >>>
> >>>   ImageIOType::Pointer gdcmImageIO = ImageIOType::New();
> >>>
> >>> fixedsubjectfilter->SetImageIO( gdcmImageIO );
> >>>
> >>> typedef itk::GDCMSeriesFileNames NamesGeneratorType;
> >>>   NamesGeneratorType::Pointer nameGenerator =
> NamesGeneratorType::New();
> >>>
> >>>   nameGenerator->SetUseSeriesDetails( true );
> >>>   nameGenerator->AddSeriesRestriction("0008|0021" );
> >>>
> >>>   nameGenerator->SetDirectory( argv[3] );
> >>>
> >>> try
> >>>     {
> >>>     std::cout << std::endl << "The directory: " << std::endl;
> >>>     std::cout << std::endl << argv[3] << std::endl << std::endl;
> >>>     std::cout << "Contains the following DICOM Series: ";
> >>>     std::cout << std::endl << std::endl;
> >>>
> >>> typedef std::vector< std::string >    SeriesIdContainer;
> >>>
> >>>     const SeriesIdContainer & seriesUID =
> nameGenerator->GetSeriesUIDs();
> >>>
> >>>     //std::cout << seriesUID.begin() << endl;
> >>>
> >>>     SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
> >>>     SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
> >>>     while( seriesItr != seriesEnd )
> >>>       {
> >>>       std::cout << seriesItr->c_str() << std::endl;
> >>>       seriesItr++;
> >>>       }
> >>>
> >>> std::string seriesIdentifier;
> >>>
> >>>     if( argc > 4 ) // If no optional series identifier
> >>>       {
> >>>       seriesIdentifier = argv[3];
> >>>       }
> >>>     else
> >>>       {
> >>>       seriesIdentifier = seriesUID.begin()->c_str();
> >>>       }
> >>>
> >>> std::cout << std::endl << std::endl;
> >>>     std::cout << "Now reading series: " << std::endl << std::endl;
> >>>     std::cout << seriesIdentifier << std::endl;
> >>>     std::cout << std::endl << std::endl;
> >>>
> >>> typedef std::vector< std::string >   FileNamesContainer;
> >>>     FileNamesContainer fileNames;
> >>>
> >>>     fileNames = nameGenerator->GetFileNames( seriesIdentifier );
> >>>
> >>> fixedsubjectfilter->SetFileNames( fileNames );
> >>>
> >>> try
> >>>       {
> >>>       fixedsubjectfilter->Update();
> >>>       std::cout << "Subject read successfully"  << std::endl;
> >>>       }
> >>>     catch (itk::ExceptionObject &ex)
> >>>       {
> >>>       std::cout << ex << std::endl;
> >>>       return EXIT_FAILURE;
> >>>       }
> >>>
> >>> typedef itk::ImageFileWriter< InputImageType > WriterSubjectType;
> >>>
> >>>   WriterSubjectType::Pointer fixedsubjectfilterwriter =
> >>> WriterSubjectType::New();
> >>>
> >>> fixedsubjectfilterwriter->SetFileName( "subjectout.dcm" );
> >>>
> >>> fixedsubjectfilterwriter->SetInput( fixedsubjectfilter->GetOutput() );
> >>>
> >>> try
> >>>       {
> >>>       fixedsubjectfilterwriter->Update();
> >>>       }
> >>>     catch (itk::ExceptionObject &ex)
> >>>       {
> >>>       std::cout << ex << std::endl;
> >>>       return EXIT_FAILURE;
> >>>       }
> >>>     }
> >>>   catch (itk::ExceptionObject &ex)
> >>>     {
> >>>     std::cout << ex << std::endl;
> >>>     return EXIT_FAILURE;
> >>>     }
> >>>
> >>>
> >>>
> >>> return EXIT_SUCCESS;
> >>> }
> >>>
> >>>
> >>> john
> >>>
> >>> On Mon, Oct 5, 2009 at 7:09 PM, Bill Lorensen <bill.lorensen at gmail.com
> >
> >>> wrote:
> >>>>
> >>>> 3D Slicer can read the DICOM directly. It will use the direction
> >>>> information properly. Why are you reading and writing it? I am
> >>>> suprised (and concerned) that 3D SLicer would flip the images.
> >>>>
> >>>> Bill
> >>>>
> >>>> On Mon, Oct 5, 2009 at 6:13 PM, John Drozd <john.drozd at gmail.com>
> wrote:
> >>>> > Hello,
> >>>> >
> >>>> > I am reading a brain subject in the form of a DICOM series using ITK
> >>>> > and
> >>>> > writing it out from memory as a volume.
> >>>> > I used the method shown in
> Examples/IO/DicomSeriesReadImageWrite2.cxx
> >>>> > I viewed the original DICOM series in 3D Slicer, and also viewed the
> >>>> > outputted volume in 3D Slicer.
> >>>> > I am using 3D Slicer because I am developing a segmentation module
> for
> >>>> > 3D
> >>>> > Slicer using ITK.
> >>>> > I noticed that the original DICOM series and the outputted volume
> are
> >>>> > inverted in orientation, such that the original series is the
> >>>> > radiologist
> >>>> > view and the outputted volume is the neurosurgean view as per
> >>>> > http://www.itk.org/pipermail/insight-users/2009-June/031128.htmland
> >>>> >
> >>>> >
> http://www.itk.org/Wiki/Proposals:Orientation#DICOM_LPS_Differences_in_Visualization_presented_to_Radiologist_and_NeuroSurgeons
> >>>> >
> >>>> > Does this have something to do with what I read on the internet that
> >>>> > vtk's
> >>>> > images are flipped vertically from itk's images?
> >>>> > Is there a way to manipulate the image in memory using ITK so that
> >>>> > Slicer
> >>>> > will display the outputted volume in the same radiologist
> orientation
> >>>> > as the
> >>>> > original DICOM series?
> >>>> >
> >>>> > Thank you.
> >>>> >
> >>>> > john
> >>>> >
> >>>> > --
> >>>> > John Drozd
> >>>> > Postdoctoral Fellow
> >>>> > Imaging Research Laboratories
> >>>> > Robarts Research Institute
> >>>> > Room 1256
> >>>> > 100 Perth Drive
> >>>> > London, Ontario, Canada
> >>>> > N6A 5K8
> >>>> > (519) 661-2111 ext. 25306
> >>>> >
> >>>> > _____________________________________
> >>>> > Powered by www.kitware.com
> >>>> >
> >>>> > Visit other Kitware open-source projects at
> >>>> > http://www.kitware.com/opensource/opensource.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
> >>> Postdoctoral Fellow
> >>> Imaging Research Laboratories
> >>> Robarts Research Institute
> >>> Room 1256
> >>> 100 Perth Drive
> >>> London, Ontario, Canada
> >>> N6A 5K8
> >>> (519) 661-2111 ext. 25306
> >>
> >>
> >>
> >> --
> >> John Drozd
> >> Postdoctoral Fellow
> >> Imaging Research Laboratories
> >> Robarts Research Institute
> >> Room 1256
> >> 100 Perth Drive
> >> London, Ontario, Canada
> >> N6A 5K8
> >> (519) 661-2111 ext. 25306
> >
> >
> >
> > --
> > John Drozd
> > Postdoctoral Fellow
> > Imaging Research Laboratories
> > Robarts Research Institute
> > Room 1256
> > 100 Perth Drive
> > London, Ontario, Canada
> > N6A 5K8
> > (519) 661-2111 ext. 25306
> >
>



-- 
John Drozd
Postdoctoral Fellow
Imaging Research Laboratories
Robarts Research Institute
Room 1256
100 Perth Drive
London, Ontario, Canada
N6A 5K8
(519) 661-2111 ext. 25306
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.itk.org/pipermail/insight-users/attachments/20091006/2fa578a6/attachment-0001.htm>


More information about the Insight-users mailing list