Hi Bill,<br><br>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<br>
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.<br>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.<br>
<br>Below is my code that I used for reading a dicom series and writing to a volume:<br>(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)<br>
<span style="color: rgb(255, 0, 0);">The pertinent reading and writing code is in red.</span> (about 60 lines down)<br style="color: rgb(255, 0, 0);"><br><br>#if defined(_MSC_VER)<br>#pragma warning ( disable : 4786 )<br>
#endif<br><br><br>#include "itkImageFileReader.h" <br>#include "itkImageFileWriter.h" <br><br>#include "itkRescaleIntensityImageFilter.h"<br>#include "itkHistogramMatchingImageFilter.h"<br>
<br>//Added from DicomImageReadWrite.cxx<br>#include "itkGDCMImageIO.h"<br><br>//Added from DicomSeriesReadImageWrite2.cxx<br>#include "itkOrientedImage.h"<br>#include "itkGDCMImageIO.h"<br>#include "itkGDCMSeriesFileNames.h"<br>
#include "itkImageSeriesReader.h"<br><br>#include "itkFEM.h"<br>#include "itkFEMRegistrationFilter.h"<br><br>// Next, we use \code{typedef}s to instantiate all necessary classes. We<br>// define the image and element types we plan to use to solve a<br>
// two-dimensional registration problem. We define multiple element<br>// types so that they can be used without recompiling the code.<br>//<br>//<br>// Note that in order to solve a three-dimensional registration<br>
// problem, we would simply define 3D image and element types in lieu<br>// of those above. The following declarations could be used for a 3D<br>// problem:<br><br>typedef itk::Image<short, 3> fileImage3DType;<br>
typedef itk::Image<short, 3> Image3DType;<br><br>typedef itk::fem::Element3DC0LinearHexahedronMembrane Element3DType;<br>typedef itk::fem::Element3DC0LinearTetrahedronMembrane Element3DType2;<br>
<br>// Here, we instantiate the load types and explicitly template the<br>// load implementation type. We also define visitors that allow the<br>// elements and loads to communicate with one another.<br><br>typedef itk::fem::FiniteDifferenceFunctionLoad<Image3DType,Image3DType> ImageLoadType;<br>
template class itk::fem::ImageMetricLoadImplementation<ImageLoadType>;<br><br>typedef Element3DType::LoadImplementationFunctionPointer LoadImpFP;<br>typedef Element3DType::LoadType ElementLoadType;<br>
<br>typedef Element3DType2::LoadImplementationFunctionPointer LoadImpFP2;<br>typedef Element3DType2::LoadType ElementLoadType2;<br><br>typedef itk::fem::VisitorDispatcher<Element3DType,ElementLoadType, LoadImpFP> <br>
DispatcherType;<br><br>typedef itk::fem::VisitorDispatcher<Element3DType2,ElementLoadType2, LoadImpFP2> <br> DispatcherType2;<br>
<br>// Once all the necessary components have been instantiated, we can<br>// instantiate the \doxygen{FEMRegistrationFilter}, which depends on the<br>// image input and output types.<br><br>typedef itk::fem::FEMRegistrationFilter<Image3DType,Image3DType> RegistrationType;<br>
<br>int main(int argc, char *argv[])<br>{<br> char *paramname;<br> if ( argc < 2 )<br> {<br> std::cout << "Parameter file name missing" << std::endl;<br> std::cout << "Usage: " << argv[0] << " param.file" << " atlas.file" << " subject.file" <<std::endl;<br>
return EXIT_FAILURE;<br> } <br> else <br> { <br> paramname=argv[1]; <br> }<br><br>// The \doxygen{fem::ImageMetricLoad} must be registered before it<br>// can be used correctly with a particular element type. An example<br>
// of this is shown below for ElementType. Similar<br>// definitions are required for all other defined element types.<br><br><br>// Register the correct load implementation with the element-typed visitor dispatcher. <br>
{<br>// Software Guide : BeginCodeSnippet<br> Element3DType::LoadImplementationFunctionPointer fp = <br> &itk::fem::ImageMetricLoadImplementation<ImageLoadType>::ImplementImageMetricLoad;<br> DispatcherType::RegisterVisitor((ImageLoadType*)0,fp);<br>
// Software Guide : EndCodeSnippet <br> }<br> {<br> Element3DType2::LoadImplementationFunctionPointer fp =<br> &itk::fem::ImageMetricLoadImplementation<ImageLoadType>::ImplementImageMetricLoad;<br> DispatcherType2::RegisterVisitor((ImageLoadType*)0,fp);<br>
}<br><br>// In order to begin the registration, we declare an instance of the<br>// FEMRegistrationFilter. For simplicity, we will call<br>// it \code{registrationFilter}.<br><br> RegistrationType::Pointer registrationFilter = RegistrationType::New();<br>
<br> <span style="color: rgb(255, 0, 0);">typedef short InputPixelType;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> const unsigned int InputDimension = 3;</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> typedef itk::Image< InputPixelType, InputDimension > InputImageType;</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> typedef itk::ImageSeriesReader< InputImageType > ReaderSeriesType;</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> ReaderSeriesType::Pointer fixedsubjectfilter = ReaderSeriesType::New();</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> typedef itk::GDCMImageIO ImageIOType;</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> ImageIOType::Pointer gdcmImageIO = ImageIOType::New();</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">fixedsubjectfilter->SetImageIO( gdcmImageIO );</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">typedef itk::GDCMSeriesFileNames NamesGeneratorType;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> nameGenerator->SetUseSeriesDetails( true );</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> nameGenerator->AddSeriesRestriction("0008|0021" );</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> nameGenerator->SetDirectory( argv[3] );</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">try</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << std::endl << "The directory: " << std::endl;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> std::cout << std::endl << argv[3] << std::endl << std::endl;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << "Contains the following DICOM Series: ";</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> std::cout << std::endl << std::endl;</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">typedef std::vector< std::string > SeriesIdContainer;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> </span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> </span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> //std::cout << seriesUID.begin() << endl;</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> while( seriesItr != seriesEnd )</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << seriesItr->c_str() << std::endl;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> seriesItr++;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">std::string seriesIdentifier;</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> if( argc > 4 ) // If no optional series identifier</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> seriesIdentifier = argv[3];</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> else</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> seriesIdentifier = seriesUID.begin()->c_str();</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">std::cout << std::endl << std::endl;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << "Now reading series: " << std::endl << std::endl;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> std::cout << seriesIdentifier << std::endl;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << std::endl << std::endl;</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">typedef std::vector< std::string > FileNamesContainer;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> FileNamesContainer fileNames;</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> fileNames = nameGenerator->GetFileNames( seriesIdentifier );</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">fixedsubjectfilter->SetFileNames( fileNames );</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">try</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> fixedsubjectfilter->Update();</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> std::cout << "Subject read successfully" << std::endl;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> catch (itk::ExceptionObject &ex)</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << ex << std::endl;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> return EXIT_FAILURE;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);">typedef itk::ImageFileWriter< InputImageType > WriterSubjectType;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> </span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> WriterSubjectType::Pointer fixedsubjectfilterwriter = WriterSubjectType::New();</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">fixedsubjectfilterwriter->SetFileName( "subjectout.dcm" );</span><br style="color: rgb(255, 0, 0);">
<br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);">fixedsubjectfilterwriter->SetInput( fixedsubjectfilter->GetOutput() );</span><br style="color: rgb(255, 0, 0);"><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);">try</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> fixedsubjectfilterwriter->Update();</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> catch (itk::ExceptionObject &ex)</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> std::cout << ex << std::endl;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> return EXIT_FAILURE;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> }</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> catch (itk::ExceptionObject &ex)</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> {</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> std::cout << ex << std::endl;</span><br style="color: rgb(255, 0, 0);"><span style="color: rgb(255, 0, 0);"> return EXIT_FAILURE;</span><br style="color: rgb(255, 0, 0);">
<span style="color: rgb(255, 0, 0);"> }</span><br><br><br><br>return EXIT_SUCCESS;<br>}<br><br><br>john<br><br><div class="gmail_quote">On Mon, Oct 5, 2009 at 7:09 PM, Bill Lorensen <span dir="ltr"><<a href="mailto:bill.lorensen@gmail.com">bill.lorensen@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">3D Slicer can read the DICOM directly. It will use the direction<br>
information properly. Why are you reading and writing it? I am<br>
suprised (and concerned) that 3D SLicer would flip the images.<br>
<br>
Bill<br>
<div><div></div><div class="h5"><br>
On Mon, Oct 5, 2009 at 6:13 PM, John Drozd <<a href="mailto:john.drozd@gmail.com">john.drozd@gmail.com</a>> wrote:<br>
> Hello,<br>
><br>
> I am reading a brain subject in the form of a DICOM series using ITK and<br>
> writing it out from memory as a volume.<br>
> I used the method shown in Examples/IO/DicomSeriesReadImageWrite2.cxx<br>
> I viewed the original DICOM series in 3D Slicer, and also viewed the<br>
> outputted volume in 3D Slicer.<br>
> I am using 3D Slicer because I am developing a segmentation module for 3D<br>
> Slicer using ITK.<br>
> I noticed that the original DICOM series and the outputted volume are<br>
> inverted in orientation, such that the original series is the radiologist<br>
> view and the outputted volume is the neurosurgean view as per<br>
> <a href="http://www.itk.org/pipermail/insight-users/2009-June/031128.html" target="_blank">http://www.itk.org/pipermail/insight-users/2009-June/031128.html</a> and<br>
> <a href="http://www.itk.org/Wiki/Proposals:Orientation#DICOM_LPS_Differences_in_Visualization_presented_to_Radiologist_and_NeuroSurgeons" target="_blank">http://www.itk.org/Wiki/Proposals:Orientation#DICOM_LPS_Differences_in_Visualization_presented_to_Radiologist_and_NeuroSurgeons</a><br>
><br>
> Does this have something to do with what I read on the internet that vtk's<br>
> images are flipped vertically from itk's images?<br>
> Is there a way to manipulate the image in memory using ITK so that Slicer<br>
> will display the outputted volume in the same radiologist orientation as the<br>
> original DICOM series?<br>
><br>
> Thank you.<br>
><br>
> john<br>
><br>
> --<br>
> John Drozd<br>
> Postdoctoral Fellow<br>
> Imaging Research Laboratories<br>
> Robarts Research Institute<br>
> Room 1256<br>
> 100 Perth Drive<br>
> London, Ontario, Canada<br>
> N6A 5K8<br>
> (519) 661-2111 ext. 25306<br>
><br>
</div></div>> _____________________________________<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>
> 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>
><br>
><br>
</blockquote></div><br><br clear="all"><br>-- <br>John Drozd<br>Postdoctoral Fellow<br>Imaging Research Laboratories<br>Robarts Research Institute<br>Room 1256<br>100 Perth Drive<br>London, Ontario, Canada<br>N6A 5K8<br>
(519) 661-2111 ext. 25306<br>