[Insight-users] DICOM orientation

Bill Lorensen bill.lorensen at gmail.com
Tue Oct 6 15:40:37 EDT 2009


I acknowledge that it is a bit magical.

On Tue, Oct 6, 2009 at 3:38 PM, John Drozd <john.drozd at gmail.com> wrote:
> 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.html
>> >>>> > and
>> >>>> >
>> >>>> >
>> >>>> > 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
>


More information about the Insight-users mailing list