I have posted a screen capture of the Slicer views at:<br><br><a href="http://www.apmaths.uwo.ca/~jdrozd/SlicerImages.png">http://www.apmaths.uwo.ca/~jdrozd/SlicerImages.png</a><br><br> The Slicer views
on the left are the original DICOM series (that are not flipped and
fine when viewed in 3D Slicer). The Slicer Views on the right are the outputted volume (after
reading the series and then writing the series from memory into a volume) and are flipped when viewed in 3D Slicer. Note the -ve vs +ve
values on the sliders, indicating the radiologist vs neurologist views.<br><font color="#888888">
<br>John</font><br><br><div class="gmail_quote">On Tue, Oct 6, 2009 at 10:21 AM, John Drozd <span dir="ltr"><<a href="mailto:john.drozd@gmail.com">john.drozd@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;">
I invoke the program with:<br><br>./DeformableRegistration "param.file" "m000-talairach.dcm" "/trumpet/downloads/DeformableRegistration_Plugin/DeformableRegistration/datasubject"<br><br>where the last item on the list is the name of the directory containing the dicom series.<br>
<font color="#888888">
<br>john</font><div><div></div><div class="h5"><br><br><div class="gmail_quote">On Tue, Oct 6, 2009 at 10:07 AM, John Drozd <span dir="ltr"><<a href="mailto:john.drozd@gmail.com" target="_blank">john.drozd@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;">
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><font color="#888888"><br><br>john</font><div><div></div><div><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" target="_blank">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><br>
On Mon, Oct 5, 2009 at 6:13 PM, John Drozd <<a href="mailto:john.drozd@gmail.com" target="_blank">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></div></div>-- <br><div><div></div><div>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>
</div></div></blockquote></div><br><br clear="all"><br></div></div>-- <br><div><div></div><div class="h5">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>
</div></div></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>