% % Complete documentation on the extended LaTeX markup used for Insight % documentation is available in ``Documenting Insight'', which is part % of the standard documentation for Insight. It may be found online % at: % % http://www.itk.org/ \documentclass{InsightArticle} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % hyperref should be the last package to be loaded. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage[dvips, bookmarks, bookmarksopen, backref, colorlinks,linkcolor={blue},citecolor={blue},urlcolor={blue}, ]{hyperref} % to be able to use options in graphics \usepackage{graphicx} % for pseudo code \usepackage{listings} % subfigures \usepackage{subfigure} % This is a template for Papers to the Insight Journal. % It is comparable to a technical report format. % The title should be descriptive enough for people to be able to find % the relevant document. \title{Slice by slice filtering with ITK} % Increment the release number whenever significant changes are made. % The author and/or editor can define 'significant' however they like. % \release{0.00} % At minimum, give your name and an email address. You can include a % snail-mail address if you like. \author{Ga\"etan Lehmann} \authoraddress{INRA, UMR 1198; ENVA; CNRS, FRE 2857, Biologie du D\'eveloppement et Reproduction, Jouy en Josas, F-78350, France} \begin{document} \maketitle \ifhtml \chapter*{Front Matter\label{front}} \fi \begin{abstract} \noindent While filtering in N dimensions is a main feature of ITK, filtering an image in N-1 dimensions, slice by slice, can be very useful in many cases. Currently, this operation require a consequent amount of work to be done with ITK. A new filter is provided with this article to perform this operation with only a few lines of code. \end{abstract} % \tableofcontents \section{Description and code example} This filter is better descibed by a simple example. For example, suppose we want to perform a median filtering on all the slices of an image\footnote{SliceBySliceImageFilter is not required in that case: the most simple solution is to set the radius to 0 on one dimension - that's only an example.} We first do the standard includes, and check the command line arguments. \small \begin{verbatim} #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkSimpleFilterWatcher.h" #include "itkMedianImageFilter.h" #include "itkSliceBySliceImageFilter.h" int main(int argc, char * argv[]) { if( argc != 3 ) { std::cerr << "usage: " << argv[0] << " input output" << std::endl; exit(1); } \end{verbatim} \normalsize The dimension of the image, the pixel type, and the image type are declared. A file reader is created. \small \begin{verbatim} const int dim = 3; typedef unsigned char PType; typedef itk::Image< PType, dim > IType; typedef itk::ImageFileReader< IType > ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName( argv[1] ); \end{verbatim} \normalsize We then declare the type of the SliceBySliceImageFilter, instantiate a filter, and set the image from the reader as input. At this point, the filter can't do anything: the developper have to give him a filter which will be used internally to perform the transform on all the classes. \small \begin{verbatim} typedef itk::SliceBySliceImageFilter< IType, IType > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( reader->GetOutput() ); \end{verbatim} \normalsize We declare the type of the internal filter - a median - using the type defined in the SliceBySliceImageFilter, instantiate it, and set the options correctly. InternalInputImageType, and InternalOutputImageType are the same type than the input and output image type of the SliceBySliceImageFilter, but decreased of one dimension - here both are \verb$itk::Image< unsigned char, 2 >$. \small \begin{verbatim} typedef itk::MedianImageFilter< FilterType::InternalInputImageType, FilterType::InternalOutputImageType > MedianType; MedianType::Pointer median = MedianType::New(); MedianType::InputSizeType rad; rad.Fill( 5 ); median->SetRadius( rad ); \end{verbatim} \normalsize The median is passed to the slice by slice filter using \verb$SetFilter()$. \small \begin{verbatim} filter->SetFilter( median ); \end{verbatim} \normalsize Finally, the output is wrote to a file. When \verb$Update()$ is called, the slice by slice filter runs the median filter on all the slices of the image, and store the result in its output image. The dimension reduced to pass to dimension N-1 can be selected with \verb$SetDimension()$ and defaults to the highest one. \small \begin{verbatim} itk::SimpleFilterWatcher watcher(filter, "filter"); typedef itk::ImageFileWriter< IType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetInput( filter->GetOutput() ); writer->SetFileName( argv[2] ); writer->Update(); return 0; } \end{verbatim} \normalsize \section{Usage with a full pipeline} SliceBySliceImageFilter is not restricted to a single filter, and can also be used with a full pipeline. Again, an example will help to describe the usage: We first do the standard includes, and check the command line arguments. \small \begin{verbatim} #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkSimpleFilterWatcher.h" #include "itkAddImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkSliceBySliceImageFilter.h" int main(int argc, char * argv[]) { if( argc != 3 ) { std::cerr << "usage: " << argv[0] << " input output" << std::endl; exit(1); } \end{verbatim} \normalsize The dimension of the image, the pixel type, and the image type are declared. A file reader is created. \small \begin{verbatim} const int dim = 3; typedef unsigned char PType; typedef itk::Image< PType, dim > IType; typedef itk::ImageFileReader< IType > ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName( argv[1] ); \end{verbatim} \normalsize In this example, a different pixel type is used in the 2D pipeline than the one used in the 3D pipeline, so we must declare the image types, and the filter types used in the 2D pipeline. \small \begin{verbatim} typedef itk::Image< unsigned short, dim-1 > US2Type; typedef itk::Image< unsigned char, dim-1 > UC2Type; typedef itk::AddImageFilter< UC2Type, UC2Type, US2Type > AddType; AddType::Pointer add = AddType::New(); typedef itk::RescaleIntensityImageFilter< US2Type, UC2Type > RescaleType; RescaleType::Pointer rescale = RescaleType::New(); \end{verbatim} \normalsize The two filters of the 2D pipeline are linked together. \small \begin{verbatim} rescale->SetInput( add->GetOutput() ); \end{verbatim} \normalsize The SliceBySliceImageFilter is instantiated with two more arguments than in the previous example: The type of the input filter in the 2D pipeline (AddType) and the type of the output filter in the 2D pipeline (RescaleType). By default, the type of the input and output filters is $itk::ImageToImageFilter< itk::Image< InputImageType, ImageDimension - 1 >, itk::Image< OutputImageType, ImageDimension - 1 > >$. Note that it is not always needed to provide those types when using a pipeline. \small \begin{verbatim} typedef itk::SliceBySliceImageFilter< IType, IType, AddType, RescaleType > FilterType; FilterType::Pointer filter = FilterType::New(); \end{verbatim} \normalsize The input filter takes two inputs, so we must provide two input to the SliceBySliceImageFilter. \small \begin{verbatim} filter->SetInput( 0, reader->GetOutput() ); filter->SetInput( 1, reader->GetOutput() ); \end{verbatim} \normalsize The input and the output filter are not the same so we have to use the SetInputFilter() and SetOutputFilter() methods instead of SetFilter(). \small \begin{verbatim} filter->SetInputFilter( add ); filter->SetOutputFilter( rescale ); \end{verbatim} \normalsize Finally, the output is wrote to a file. When \verb$Update()$ is called, the slice by slice filter runs the 2D pipeline on all the slices of the image, and store the result in its output image. The dimension reduced to pass to dimension N-1 can be selected with \verb$SetDimension()$ and defaults to the highest one. \small \begin{verbatim} itk::SimpleFilterWatcher watcher(filter, "filter"); typedef itk::ImageFileWriter< IType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetInput( filter->GetOutput() ); writer->SetFileName( argv[2] ); writer->Update(); return 0; } \end{verbatim} \normalsize \section{Improvement since revision 1 and future work} Since the first revision, the SliceBySliceImageFilter has been improved to suppport: \begin{itemize} \item several inputs \item several outputs \item a pipeline of filters \end{itemize} It still lack some features: \begin{itemize} \item the ability to have the input and output image of different size \item the ability to take several inputs of different types \item the ability to produce several outputs of different types \end{itemize} The first feature can reasonably be done. The two last ones looks very difficult to do, and will probably never be implemented. \section{Conclusion} The new provided class gives an easy way to perform a slice by slice transform of an image. % \url{http://www.itk.org} % \code{Insight/Documentation/Style.pdf} % \section{Principles of Solar Spot Detection} % \cite{ITKSoftwareGuide}. % \doxygen{ImageToImageFilter} % \small \begin{verbatim} % \end{verbatim} \normalsize % The {itemize} environment uses a bullet for each \item. If you want the % \item's numbered, use the {enumerate} environment instead. % \begin{itemize} % \item Insight Toolkit 2.4. % \item CMake 2.2 % \end{itemize} % \ref{cthead1} % \begin{figure}[htbp] % \centering % \includegraphics{cthead1} % \caption{The input image.\label{cthead1}} % \end{figure} \appendix \bibliographystyle{plain} \bibliography{InsightJournal} \nocite{ITKSoftwareGuide} \end{document}