NA-MIC National Alliance for Medical Image Computing ITK Workshop October 5-8, 2005 Software Design
National Alliance for Medical Image Computing ITK Workshop – Open Source Viewers Design Patterns –PipelinePipeline –DecoratorsDecorators –IteratorsIterators –AdaptorsAdaptors –AccessorsAccessors –FunctorsFunctors –FactoriesFactories –TraitsTraits
National Alliance for Medical Image Computing The Data Pipeline Insight Toolkit - Advanced Course
National Alliance for Medical Image Computing The Data Pipeline Data Object Process Object Data Object Process Object Data Object
National Alliance for Medical Image Computing Who owns the Output ? Data Object Data Object Data Object Process Object The ProcessObject allocates and owns its output Therefore the output is const
National Alliance for Medical Image Computing Instantiate the filters types Construct the filters with New() Connect SetInput() GetOutput() Set filter Parameters Invoke Update() in the last filter How to use the Pipeline ?
National Alliance for Medical Image Computing Modify the filter parameters Invoke Update() in the last filter The Pipeline is intended to be Re-Executed Only the filters that need to re-compute their output will be re-executed
National Alliance for Medical Image Computing Updating the Pipeline Image Reader Filter A Filter B Filter C Filter D Image Writer
National Alliance for Medical Image Computing Updating the Pipeline Image Reader Filter A Filter B Filter C Filter D Image Writer Execute Update()
National Alliance for Medical Image Computing Updating the Pipeline Image Reader Filter A Filter B Filter C Filter D Image Writer Execute Update()
National Alliance for Medical Image Computing Updating the Pipeline Image Reader Filter A Filter B Filter C Filter D Image Writer Execute Update() SetParameter Im OK
National Alliance for Medical Image Computing itk::Object has a TimeStamp Invoking Modified() updates the stamp SetParameter() methods calls Modified() Most Set() methods use itkSetMacro() If you write your own SetParameter() you must remember to invoke Modified() How it works internally
National Alliance for Medical Image Computing What will go wrong with your filter if you create a SetParameter() method and forget to invoke Modified() from it ? How it works internally Quiz ! It will run fine the first time but if you call SetParameter() and then call Update() the filter will not re-execute.
National Alliance for Medical Image Computing Open the itkMacro.h file in Insight/Code/Common How it works internally Exercise Find the itkSetMacro() and identify the line where Modified() is invoked
National Alliance for Medical Image Computing Pervasive Pipelining Insight Toolkit - Advanced Course (or the Ode to Intelligent Design)
National Alliance for Medical Image Computing In the Beginning… there was the itk::DataObject Insight Toolkit - Advanced Course The itk::DataObject originated the itk::Image and the itk::Mesh
National Alliance for Medical Image Computing Only the the itk::DataObject and his sons were admited in the Pipeline garden Insight Toolkit - Advanced Course The float, ints, Transforms and Points grew jealous of the DataObject Since they could not promenade in the Pipeline Garden
National Alliance for Medical Image Computing So in chorus they asked to change the ways of the Pipeline garden Insight Toolkit - Advanced Course And from the darkness of the abyss the itk::DataObjectDecorator was born.
National Alliance for Medical Image Computing Insight Toolkit - Advanced Course With it, the float, ints, Transforms and Points became as DataObjects and walked at their will in the Pipeline Garden.
National Alliance for Medical Image Computing #include itkDataObject.h template class SimpleDataObjectDecorator : public DataObject { public: typedef SimpleDataObjectDecorator Self; typedef DataObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkNewMacro( Self ); itkTypeMacro( SimpleDataObjectDecorator, DataObject ); private: T m_Component; The SimpleDataObjectDecorator
National Alliance for Medical Image Computing public: virtual void Set( const T & value ) { if( m_Component != value ) { m_Component = value; this->Modified(); } } virtual const T & Get() const { return m_Component } The SimpleDataObjectDecorator
National Alliance for Medical Image Computing #include itkDataObject.h template class DataObjectDecorator : public DataObject { public: typedef DataObjectDecorator Self; typedef DataObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkNewMacro( Self ); itkTypeMacro(DataObjectDecorator, DataObject ); private: typename T::Pointer m_Component; The DataObjectDecorator
National Alliance for Medical Image Computing public: virtual void Set( const T * value ) { if( m_Component != value ) { m_Component = value; this->Modified(); } } virtual const T * Get() const { return m_Component } The DataObjectDecorator
National Alliance for Medical Image Computing Iterators Insight Toolkit - Advanced Course
National Alliance for Medical Image Computing STL Iterators Image Iterators –Region –Linear –Slice Mesh Iterators –VectorContainer –MapContainer Iterators
National Alliance for Medical Image Computing #include typedef std::vector VectorType; VectorType myVector; myVector.push_back( 4 ); myVector.push_back( 7 ); myVector.push_back( 19 ); VectorType::const_iterator itr = myVector.begin(); while( itr != myVector.end() ) { std::cout << *itr << std::endl; ++itr; } STL Iterators
National Alliance for Medical Image Computing for( unsigned int z = 0; z < Nz; z++ ) { for( unsigned int y = 0; y < Ny; y++ ) { for( unsigned int x = 0; x < Nx; x++ ) { image[z][y][x] = … // pixel access } } } Image Iterators The Evil nested loop and the Dimensional Trap How to generalize this code to 2D, 3D, 4D …?
National Alliance for Medical Image Computing #include itkImage.h #include itkImageRegionIterator.h typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator IteratorType; ImageType::ConstPointer image = GetConstImageSomeHow(); ImageType::RegionType region = image->GetLargestPossibleRegion(); IteratorType itr( image, region ); itr.GoToBegin(); while( ! itr.IsAtEnd() ) { std::cout << itr.Get() << std::endl; ++itr; } Image Iterators (const)
National Alliance for Medical Image Computing #include itkImage.h #include itkImageRegionIterator.h typedef itk::Image ImageType; typedef itk::ImageRegionIterator IteratorType; ImageType::Pointer image = GetNonConstImageSomeHow(); ImageType::RegionType region = image->GetLargestPossibleRegion(); IteratorType itr( image, region ); itr.GoToBegin(); while( ! itr.IsAtEnd() ) { itr.Set( 0 ); ++itr; } Image Iterators (non-const)
National Alliance for Medical Image Computing #include itkImage.h #include itkImageLinearIteratorWithIndex.h typedef itk::Image ImageType; typedef itk::ImageLinearConstIteratorWithIndex IteratorType; ImageType::ConstPointer image = GetConstImageSomeHow(); ImageType::RegionType region = GetImageRegionSomeHow(); IteratorType itr( image, region ); for( itr.GoToBegin(); !itr.IsAtEnd(); itr.NextLine() ) { while( ! itr.IsAtEndOfLine() ) { std::cout << itr.Get() << : << itr.GetIndex() << std::endl; ++itr; } } Image Linear Iterator (const)
National Alliance for Medical Image Computing #include itkImageSliceIteratorWithIndex.h typedef itk::ImageSliceConstIteratorWithIndex IteratorType; ImageType::ConstPointer image = GetConstImageSomeHow(); ImageType::RegionType region = GetImageRegionSomeHow(); IteratorType itr( image, region ); for( itr.GoToBegin(); !itr.IsAtEnd(); itr.NextSlice() ) { for( ; ! itr.IsAtEndOfSlice(); itr.NextLine() ) { for( ; ! itr.IsAtEndOfLine(); ++itr ) { std::cout << itr.Get() << : << itr.GetIndex() << std::endl; } } } Image Slice Iterator (const)
National Alliance for Medical Image Computing Using the ImageLinearIterator Exercise 28 Use two ImageLinearIterators in order to flip and image across its diagonal
National Alliance for Medical Image Computing Reflective Image Iterator Neighborhood Iterator Shaped Neighborhood Iterator Image Random Iterator Image Random Non Repeating Iterator Flood Filled Function Conditional Iterator Path Iterator Other Image Iterators
National Alliance for Medical Image Computing Iterators absorb a large portion of the complexity in an Image Filter Iterators made possible to generalize ITK to N-Dimensional images Iterators allows to have fast access to pixel data Iterators made ImageAdaptors possible (see later) Importance of Image Iterators
National Alliance for Medical Image Computing #include itkMesh.h typedef itk::Mesh MeshType; MeshType::ConstPointer mesh = GetConstMeshSomeHow(); typedef MeshType::PointsContainer PointsContainer; typedef PointsContainer::ConstIterator PointsIterator; PointsContainer points = mesh->GetPoints(); PointsIterator pointItr = points->Begin(); while( pointItr != points->End() ) { MeshType::PointsType point = pointItr.Value(); std::cout << point << point << std::endl; ++pointItr; } Mesh Iterators (const)
National Alliance for Medical Image Computing Image Adaptors Insight Toolkit - Advanced Course (Things are not always what they seem)
National Alliance for Medical Image Computing Some operations are too simple for a filter Image Process Object Image Filter Image Fake Image Image Adaptor
National Alliance for Medical Image Computing Pixel Accessor Image Fake Image Image Adaptor Image Adaptors = Image Iterators + Pixel Accessors Pixel Accessor Where the transformation is done
National Alliance for Medical Image Computing Pixel Accessor and Image Iterators ImageImage Iterator
National Alliance for Medical Image Computing Pixel Accessor and Image Iterators ImageImage Iterator itr.Get() m_PixelAccessorFunctor.Get( *( m_Buffer + m_Offset ));
National Alliance for Medical Image Computing namespace Accessor { class RedChannel { public: typedef itk::RGBPixel InternalType; typedef float ExternalType; static ExternalType Get()( const InternalType & A ) { return static_cast ( A.GetRed() ); } }; } // end of Accessor namespace Pixel Accessor : Red Channel from RGB Image
National Alliance for Medical Image Computing int main() { typedef Accessor::RedChannel::InternalType InternalPixelType; typedef itk::Image AdaptedImageType; typedef itk::ImageAdaptor ImageAdaptorType; ImageAdaptorType::Pointer adaptor = ImageAdaptorType::New(); typedef itk::ImageFilterReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); adaptor->SetImage( reader->GetOutput() ); Using the Pixel Accessor in the Image Adaptor
National Alliance for Medical Image Computing Image Adaptors are like Images Image Adaptors are not Filters Image Adaptors do not have Buffers Not all Iterators support Image Adaptors Not all Filters support Image Adaptors Image Adaptors
National Alliance for Medical Image Computing typedef itk::Image OutputImageType; typedef itk::RescaleIntensityImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( adaptor ); // Adaptors are like Images !! writer->SetInput( filter->GetOutput() ); writer->Update(); } Using the Pixel Accessor in the Image Adaptor
National Alliance for Medical Image Computing Image Adaptors Pierce the Illusion… to see the Void.
National Alliance for Medical Image Computing Writers access Images buffer directly, They are not fooled by Image Adaptors. Neigborhood Iterators do not call the Get() method… They are not fooled by Image Adaptors. Image Adaptors
National Alliance for Medical Image Computing Image Adaptors Exercise 27 Write a Pixel Accessor that will invert the intensities in an image. Instantiate its corresponding Image Adaptor
National Alliance for Medical Image Computing namespace Accessor { class Inversor { public: typedef unsigned char InternalType; typedef unsigned char ExternalType; static ExternalType Get()( const InternalType & A ) { return static_cast ( A ); } }; } // end of Accessor namespace Pixel Accessor : Invert 8-bits intensities.
National Alliance for Medical Image Computing Functors Insight Toolkit - Advanced Course The Way takes no action, but leaves nothing undone
National Alliance for Medical Image Computing namespace Functor { template class Doubler { public: Doubler() {}; ~Doubler() {}; inline TOutput operator()( const TInput & A ) { return static_cast ( 2.0 * A ); } }; } // end of Functor namespace Functors A Functor is a class that looks like a Function
National Alliance for Medical Image Computing typedef Functor::Doubler FunctorType; FunctorType iDouble; int input = 197.0; int result = iDouble( input ); Functors Functors are used as functions
National Alliance for Medical Image Computing Functors are used by Insight Toolkit - Advanced Course UnaryFuncturImageFilter<> BinaryFunctorImageFilter<> TernaryFunctorImageFilter<> Functors make possible to factorize all other operations of an image filter
National Alliance for Medical Image Computing Factories Insight Toolkit - Advanced Course The origin of the world is its mother; Understand the mother, and you understand the child Tao Te Ching
National Alliance for Medical Image Computing The Class Hierarchy of Factories itk::ObjectFactoryBase itk::DataObject itk::Object itk::ObjectFactory itk::LightObject itk::ProcessObject
National Alliance for Medical Image Computing What happens when we invoke ::New() ? itk::LightObject New() itk::ObjectFactory Create() CreateInstance( typeid(T) ) itk::ObjectFactoryBase Iterate over Registered Factories CreateObject ( classname) return pointer, or NULL if NULL call new
National Alliance for Medical Image Computing Factories itk::ObjectFactoryBase RegisteredFactoriesstd::list static static void RegisteredFactory( ObjectFactoryBase *) ObjectFactory X ObjectFactory Y ObjectFactory Z ObjectFactory W
National Alliance for Medical Image Computing Factories can be loaded as Dynamic Libraries itk::ObjectFactoryBase LoadLibrariesInPath( char * path )static itk::DynamicLoader From path get all filenames that are shared libraries GetSymbolAddress() OpenLibrary( fname) RegisterFactory( ObjectFactoryBase* )static
National Alliance for Medical Image Computing Loading Dynamic Factories Set environment variable ITK_AUTOLOAD_PATH In the Shared library create an itkLoad() function that returns an itk::ObjectFactoryBase * Compile the shared library using CMake command ADD_LIBRARY( Name SHARED …sources…) Copy the shared library in one of the directories in ITK_AUTOLOAD_PATH
National Alliance for Medical Image Computing Image Adaptors Exercise 29 Create a simple Factory Use the same structure for replacing an existing ITK class
National Alliance for Medical Image Computing Creating my own Factory itk::ObjectFactoryBase itk::MyOwnFactory static itkLoad(); FactoryLessNewMacro(); FactoryNew(); GetITKSourceVersion(); GetDescription(); RegisterOneFactory(); MyOwnFactory(); // constructor ~MyOwnFactory(); // destructor
National Alliance for Medical Image Computing Traits Insight Toolkit - Advanced Course Knowing others is Wisdom Knowing the Self is Enlightenment Tao Te Ching
National Alliance for Medical Image Computing Traits Types declared inside another Type Fundamental for enforcing consitency
National Alliance for Medical Image Computing #include itkImageBase.h template class Image : public ImageBase { public: typedef Image Self; typedef ImageBase Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkNewMacro( Self ); itkTypeMacro(Image, ImageBase ); typedef TPixel PixelType; itkStaticConstMacro(ImageDimension, unsigned int, VDimension); Traits Examples
National Alliance for Medical Image Computing #include itkImage.h int main( int, char * argv []) { typedef itk::Image ImageType; typedef itk::ImageFilterReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName( argv[1] ); ImageType::ConstPointer image = reader->GetOutput(); ImageType::IndexType index; index.Fill(0); ImageType::PixelType pixel = reader->GetPixel( index ); Use Traits instead of redundant declarations !
National Alliance for Medical Image Computing template class ImageFilter { public: typedef TImage ImageType; const ImageType * GetImage() const; private: typename ImageType::ConstPointer m_Image; }; template const typename ImageFilter ::ImageType * ImageFilter ::GetImage() const { return m_Image; } Very Important in Return Types…
National Alliance for Medical Image Computing template class ImageFilter { typename TImage::ConstPointer m_Image; }; Note the use of typename You need typename if all the following applies You are in a templated class You are accessing a trait from a class that depends on the template arguments of your current class.
National Alliance for Medical Image Computing Compilers and typename The keyword typename is supported differenty by different compilers Totally ignored by Visual Studio 6.0 Supported in Visual Studio 7.0 and 7.1 Required in gcc 3.2, gcc 3.3 Implicit typenames not supported in gcc 3.4
National Alliance for Medical Image Computing END Insight Toolkit - Advanced Course