From bece008148f4a08cff5daaa3c9b2824462b94319 Mon Sep 17 00:00:00 2001 From: Leonardo Florez-Valencia Date: Tue, 16 Dec 2014 19:11:54 +0100 Subject: [PATCH 1/1] Simple flood fill plugin added. --- .../MainWnd.cxx | 16 +- .../MainWnd.h | 61 ++++ .../MainWnd_ExecutePlugins.cxx | 263 ++++++++++++------ .../MainWnd_LoadPlugins.cxx | 121 +------- lib/cpm/Plugins/SimpleFillRegion.cxx | 233 +++++++++++++++- lib/cpm/Plugins/SimpleFillRegion.h | 9 + 6 files changed, 492 insertions(+), 211 deletions(-) diff --git a/appli/InteractiveDeformableMeshSegmentation/MainWnd.cxx b/appli/InteractiveDeformableMeshSegmentation/MainWnd.cxx index f6d38fa..8e55c5a 100644 --- a/appli/InteractiveDeformableMeshSegmentation/MainWnd.cxx +++ b/appli/InteractiveDeformableMeshSegmentation/MainWnd.cxx @@ -30,7 +30,9 @@ MainWnd::MainWnd( QWidget* parent ) m_InputImage( NULL ), m_SegmentedImage( NULL ), m_ActivePlugin( NULL ), - m_ActiveParameters( NULL ) + m_ActiveParameters( NULL ), + m_ActivePluginType( Self::NonePluginType ), + m_ActivePluginCategory( Self::NonePluginCategory ) { this->m_UI->setupUi( this ); @@ -47,6 +49,12 @@ MainWnd::MainWnd( QWidget* parent ) this->m_UI->m_3DVTK->GetRenderWindow( ) ); + // Associate observer + this->m_DoubleClickCommand = + vtkSmartPointer< DoubleClickCommand >::New( ); + this->m_DoubleClickCommand->SetMainWnd( this ); + this->m_MPR->AddDoubleClickObserver( this->m_DoubleClickCommand ); + // Orientation marks /* TODO vtkSmartPointer< vtkAnnotatedCubeActor > oCube = @@ -339,9 +347,9 @@ _triggered_actionOpenSegmentedImage( ) */ // Ok, start! - this->m_UI->m_XPlaneVTK->GetRenderWindow( )->Render( ); - this->m_UI->m_YPlaneVTK->GetRenderWindow( )->Render( ); - this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->Render( ); + this->m_MPR->Render( 0 ); + this->m_MPR->Render( 1 ); + this->m_MPR->Render( 2 ); this->_UpdateEnabledFlags( ); } // fi diff --git a/appli/InteractiveDeformableMeshSegmentation/MainWnd.h b/appli/InteractiveDeformableMeshSegmentation/MainWnd.h index 3576ac5..45860bb 100644 --- a/appli/InteractiveDeformableMeshSegmentation/MainWnd.h +++ b/appli/InteractiveDeformableMeshSegmentation/MainWnd.h @@ -10,6 +10,7 @@ #include // vtk stuff +#include #include #include #include @@ -21,6 +22,37 @@ #include #include +// ------------------------------------------------------------------------- +class MainWnd; + +class DoubleClickCommand + : public vtkCommand +{ +public: + typedef DoubleClickCommand Self; + +public: + vtkTypeMacro( DoubleClickCommand, vtkCommand ); + +public: + static DoubleClickCommand* New( ); + + void SetMainWnd( MainWnd* wnd ); + void Execute( vtkObject* caller, unsigned long eid, void* data ); + +protected: + DoubleClickCommand( ); + virtual ~DoubleClickCommand( ); + +private: + // Purposely not implemented + DoubleClickCommand( const Self& ); + Self& operator=( const Self& ); + +protected: + MainWnd* m_MainWnd; +}; + // ------------------------------------------------------------------------- namespace Ui { @@ -36,17 +68,38 @@ class MainWnd Q_OBJECT; public: + friend class DoubleClickCommand; + + typedef MainWnd Self; + // Plugins types typedef cpPlugins::Interface::Interface TPluginsInterface; typedef cpPlugins::Interface::Object TPluginObject; typedef cpPlugins::Interface::DataObject TPluginData; typedef cpPlugins::Interface::Image TPluginImage; typedef cpPlugins::Interface::ProcessObject TPlugin; + typedef TPlugin::TParameter TParameter; typedef TPlugin::TParameters TParameters; typedef cpPlugins::Extensions::Visualization::MPRWithDifferentWindows TMPR; typedef std::map< std::string, std::string > TStringMap; + enum PluginType + { + GlobalPluginType = 0, + DoubleClickPluginType, + SpherePluginType, + NonePluginType + }; + + enum PluginCategory + { + SegmentationPluginCategory = 0, + SegmentationFilteringPluginCategory, + MeshProcessingPluginCategory, + NonePluginCategory + }; + public: explicit MainWnd( QWidget* parent = 0 ); virtual ~MainWnd( ); @@ -64,6 +117,10 @@ protected: void _UpdateEnabledFlags( ); bool _ParametersDialog( const TParameters& parameters ); + void _ExecuteDoubleClickPlugin( const double* pnt ); + + template< class P > + void _JoinSegmentations( ); /* TODO template< class I > @@ -125,6 +182,10 @@ private: // Active plugin TPlugin* m_ActivePlugin; QWidget* m_ActiveParameters; + Self::PluginType m_ActivePluginType; + Self::PluginCategory m_ActivePluginCategory; + + vtkSmartPointer< DoubleClickCommand > m_DoubleClickCommand; }; #endif // __MAINWND__H__ diff --git a/appli/InteractiveDeformableMeshSegmentation/MainWnd_ExecutePlugins.cxx b/appli/InteractiveDeformableMeshSegmentation/MainWnd_ExecutePlugins.cxx index 8429a81..cbbfac6 100644 --- a/appli/InteractiveDeformableMeshSegmentation/MainWnd_ExecutePlugins.cxx +++ b/appli/InteractiveDeformableMeshSegmentation/MainWnd_ExecutePlugins.cxx @@ -2,9 +2,16 @@ #include "ui_MainWnd.h" #include +#include #include #include +#include + +#include +#include +#define ITK_MANUAL_INSTANTIATION +#include // ------------------------------------------------------------------------- bool MainWnd:: @@ -52,100 +59,105 @@ _ParametersDialog( const TParameters& parameters ) } // rof gridLayout->addLayout( verticalLayout, 0, 0, 1, 1 ); + + // Infere plugin type + TParameters::const_iterator seedIt = parameters.find( "Seed" ); + TParameters::const_iterator radiusIt = parameters.find( "Radius" ); + TParameters::const_iterator endIt = parameters.end( ); + if( seedIt == endIt && radiusIt == endIt ) + this->m_ActivePluginType = Self::GlobalPluginType; + else if( seedIt != endIt && radiusIt == endIt ) + this->m_ActivePluginType = Self::DoubleClickPluginType; + else if( seedIt != endIt && radiusIt != endIt ) + this->m_ActivePluginType = Self::SpherePluginType; + else + this->m_ActivePluginType = Self::NonePluginType; + QMetaObject::connectSlotsByName( this->m_ActiveParameters ); this->m_ActiveParameters->show( ); - /* - typedef std::map< std::string, QWidget* > _TWidgets; - _TWidgets widgets; - TParameters::const_iterator pIt = parameters.begin( ); - for( ; pIt != parameters.end( ); ++pIt ) - { - unsigned long pos = pIt->first.find_last_of( ":" ); - std::string v_name = pIt->first.substr( 0, pos ); - std::string v_type = pIt->first.substr( pos + 1 ); - QHBoxLayout* horizontalLayout = new QHBoxLayout( ); - QLabel* label = new QLabel( this->m_ActiveParameters ); - label->setText( QString( v_name.c_str( ) ) ); - horizontalLayout->addWidget( label ); - if( v_type == "real" ) - { - QDoubleSpinBox* v_double = new QDoubleSpinBox( this->m_ActiveParameters ); - v_double->setDecimals( 3 ); - v_double->setMinimum( -( std::numeric_limits< double >::max( ) ) ); - v_double->setMaximum( std::numeric_limits< double >::max( ) ); - v_double->setValue( std::atof( pIt->second.c_str( ) ) ); - horizontalLayout->addWidget( v_double ); - widgets[ pIt->first ] = v_double; - } - else if( v_type == "atomic_real" ) - { - if( v_name == "MeshType" ) - { - QLabel* info = new QLabel( this->m_ActiveParameters ); - if( typeid( TScalar ) == typeid( float ) ) - info->setText( QString( "float" ) ); - else if( typeid( TScalar ) == typeid( double ) ) - info->setText( QString( "double" ) ); - horizontalLayout->addWidget( info ); - widgets[ pIt->first ] = info; - } // fi - } // fi - verticalLayout.addLayout( horizontalLayout ); - } // rof - gridLayout.addLayout( &verticalLayout, 0, 0, 1, 1 ); - // Buttons box - QDialogButtonBox buttonBox( this->m_ActiveParameters ); - buttonBox.setOrientation( Qt::Horizontal ); - buttonBox.setStandardButtons( - QDialogButtonBox::Cancel | QDialogButtonBox::Ok - ); - gridLayout.addWidget( &buttonBox, 1, 0, 1, 1 ); - QObject::connect( - &buttonBox, SIGNAL( accepted( ) ), - this->m_ActiveParameters, SLOT( accept( ) ) - ); - QObject::connect( - &buttonBox, SIGNAL( rejected( ) ), - this->m_ActiveParameters, SLOT( reject( ) ) - ); - QMetaObject::connectSlotsByName( this->m_ActiveParameters ); - - // Execute dialog - if( dlg.exec( ) == QDialog::Accepted ) - { - _TWidgets::const_iterator wIt = widgets.begin( ); - for( ; wIt != widgets.end( ); ++wIt ) - { - unsigned long pos = wIt->first.find_last_of( ":" ); - std::string v_name = wIt->first.substr( 0, pos ); - std::string v_type = wIt->first.substr( pos + 1 ); - std::stringstream sstr; - if( v_type == "real" ) - { - QDoubleSpinBox* v_double = - dynamic_cast< QDoubleSpinBox* >( wIt->second ); - if( v_double != NULL ) - sstr << v_double->value( ); - } - else if( v_type == "atomic_real" ) - { - if( v_name == "MeshType" ) + return( false ); +} + +// ------------------------------------------------------------------------- +void MainWnd:: +_ExecuteDoubleClickPlugin( const double* pnt ) +{ + if( + this->m_InputImage == NULL || + this->m_SegmentedImage == NULL || + this->m_ActivePlugin == NULL || + this->m_ActiveParameters == NULL || + this->m_ActivePluginType != Self::DoubleClickPluginType + ) + return; + + TParameters parameters = this->m_ActivePlugin->GetDefaultParameters( ); + + // Variable parameters + for( + TParameters::iterator pIt = parameters.begin( ); + pIt != parameters.end( ); + ++pIt + ) + { + if( pIt->first != "Seed" ) { - QLabel* info = dynamic_cast< QLabel* >( wIt->second ); - if( info != NULL ) - sstr << info->text( ).toStdString( ); + if( pIt->second.first == "double" ) + { + QDoubleSpinBox* v_double = this->m_ActiveParameters-> + findChild< QDoubleSpinBox* >( pIt->first.c_str( ) ); + if( v_double != NULL ) + parameters[ pIt->first ] = + TParameter( "double", v_double->text( ).toStdString( ) ); + + } // fi } // fi - } // fi - parameters[ wIt->first ] = sstr.str( ); + } // rof - } // rof - return( true ); - } - */ - return( false ); + // Seed + std::stringstream seed_str; + seed_str << pnt[ 0 ] << ":" << pnt[ 1 ] << ":" << pnt[ 2 ]; + parameters[ "Seed" ] = TParameter( "point", seed_str.str( ) ); + + // Execute + this->m_ActivePlugin->SetParameters( parameters ); + this->m_ActivePlugin->SetInput( 0, this->m_InputImage ); + this->m_ActivePlugin->SetInput( 1, this->m_SegmentedImage ); + std::string err = this->m_ActivePlugin->Update( ); + if( err != "" ) + { + QMessageBox::critical( this, tr( "Error caugth!" ), tr( err.c_str( ) ) ); + return; + + } // fi + + // Join results + itk::DataObject* s = this->m_SegmentedImage->GetDataObject( ); + if( dynamic_cast< itk::Image< char, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< char >( ); + else if( dynamic_cast< itk::Image< short, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< short >( ); + else if( dynamic_cast< itk::Image< int, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< int >( ); + else if( dynamic_cast< itk::Image< long, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< long >( ); + else if( dynamic_cast< itk::Image< unsigned char, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< unsigned char >( ); + else if( dynamic_cast< itk::Image< unsigned short, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< unsigned short >( ); + else if( dynamic_cast< itk::Image< unsigned int, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< unsigned int >( ); + else if( dynamic_cast< itk::Image< unsigned long, 3 >* >( s ) != NULL ) + this->_JoinSegmentations< unsigned long >( ); + + // Update visualization + this->m_SegmentedImage->UpdateVTKImageData( ); + this->m_MPR->Render( 0 ); + this->m_MPR->Render( 1 ); + this->m_MPR->Render( 2 ); } // ------------------------------------------------------------------------- @@ -174,6 +186,7 @@ _triggered_actionFilterSegmentation( ) this->m_SegmentationFilterClasses[ filter_name ] ) ); + this->m_ActivePluginCategory = Self::SegmentationFilteringPluginCategory; // Show parameters dialog this->_ParametersDialog( this->m_ActivePlugin->GetDefaultParameters( ) ); @@ -185,4 +198,82 @@ _triggered_actionProcessMesh( ) { } +// ------------------------------------------------------------------------- +template< class P > +void MainWnd:: +_JoinSegmentations( ) +{ + typedef itk::Image< P, 3 > _TImage; + + _TImage* old_segmentation = + dynamic_cast< _TImage* >( this->m_SegmentedImage->GetDataObject( ) ); + _TImage* new_segmentation = + dynamic_cast< _TImage* >( + dynamic_cast< TPluginImage* >( + this->m_ActivePlugin->GetOutput( 0 ) + )->GetDataObject( ) + ); + + /* TODO: InPlaceOn does not execute correctly on input image + typedef itk::AndImageFilter< _TImage, _TImage, _TImage > _TFilter; + typename _TFilter::Pointer filter = _TFilter::New( ); + filter->InPlaceOn( ); + filter->SetInput( 0, old_segmentation ); + filter->SetInput( 1, new_segmentation ); + filter->Update( ); + //old_segmentation->DisconnectPipeline( ); + + std::cout << old_segmentation->GetRequestedRegion( ) << std::endl; + std::cout << new_segmentation->GetRequestedRegion( ) << std::endl; + std::cout << old_segmentation->GetBufferedRegion( ) << std::endl; + std::cout << new_segmentation->GetBufferedRegion( ) << std::endl; + */ + typedef itk::ImageRegionConstIterator< _TImage > _TConstIt; + typedef itk::ImageRegionIterator< _TImage > _TIt; + _TConstIt nIt( new_segmentation, new_segmentation->GetRequestedRegion( ) ); + _TIt oIt( old_segmentation, old_segmentation->GetRequestedRegion( ) ); + nIt.GoToBegin( ); + oIt.GoToBegin( ); + for( ; !nIt.IsAtEnd( ); ++nIt, ++oIt ) + oIt.Set( nIt.Get( ) | oIt.Get( ) ); +} + +// ------------------------------------------------------------------------- +DoubleClickCommand* DoubleClickCommand:: +New( ) +{ + return( new DoubleClickCommand( ) ); +} + +// ------------------------------------------------------------------------- +void DoubleClickCommand:: +SetMainWnd( MainWnd* wnd ) +{ + this->m_MainWnd = wnd; +} + +// ------------------------------------------------------------------------- +void DoubleClickCommand:: +Execute( vtkObject* caller, unsigned long eid, void* data ) +{ + if( this->m_MainWnd != NULL ) + this->m_MainWnd->_ExecuteDoubleClickPlugin( + reinterpret_cast< const double* >( data ) + ); +} + +// ------------------------------------------------------------------------- +DoubleClickCommand:: +DoubleClickCommand( ) + : Superclass( ), + m_MainWnd( NULL ) +{ +} + +// ------------------------------------------------------------------------- +DoubleClickCommand:: +~DoubleClickCommand( ) +{ +} + // eof - $RCSfile$ diff --git a/appli/InteractiveDeformableMeshSegmentation/MainWnd_LoadPlugins.cxx b/appli/InteractiveDeformableMeshSegmentation/MainWnd_LoadPlugins.cxx index 8c01ef8..27fbfe2 100644 --- a/appli/InteractiveDeformableMeshSegmentation/MainWnd_LoadPlugins.cxx +++ b/appli/InteractiveDeformableMeshSegmentation/MainWnd_LoadPlugins.cxx @@ -111,126 +111,7 @@ _LoadPlugins( ) ); // Historic objects - - - - /* - this->m_ImageReaderClassName = ""; - this->m_ImageSeriesReaderClassName = ""; - this->m_ImageWriterClassName = ""; - - if( in ) - { - std::string plugin; - std::getline( in, plugin ); - while( !( in.eof( ) ) ) - { - if( this->m_Plugins.Load( plugin ) ) - { - TPluginsInterface::TClassesIterator cIt = - this->m_Plugins.GetClasses( ).begin( ); - TPluginsInterface::TClassesIterator end_cIt = - this->m_Plugins.GetClasses( ).end( ); - for( ; cIt != end_cIt; ++cIt ) - { - std::string c_name = cIt->first; - c_name = c_name.substr( c_name.find_last_of( ":" ) + 1 ); - if( c_name == "ImageReader" ) - { - this->m_ImageReaderClassName = cIt->first; - } - else if( c_name == "ImageSeriesReader" ) - { - this->m_ImageSeriesReaderClassName = cIt->first; - } - else if( c_name == "ImageWriter" ) - { - this->m_ImageWriterClassName = cIt->first; - } - else - { - } // fi - - } // rof - - TFilterPlugins::TClassesIterator cIt = - this->m_Plugins.BeginClasses( ); - for( ; cIt != this->m_Plugins.EndClasses( ); ++cIt ) - { - TFilterObject* filter = - this->m_Plugins.CreateObject( cIt->first ); - if( filter == NULL ) - continue; - std::string cat = filter->GetCategory( ); - std::string catType = cat.substr( cat.find_last_of( ":" ) ); - if( catType == ":BinaryImageToBinaryImageFilter" ) - { - QAction* action = this->m_UI->menuFilterSegmentedImage-> - addAction( QString( cIt->first.c_str( ) ) ); - QObject::connect( - action, SIGNAL( triggered( ) ), - this, SLOT( triggered_aFilterSegmentedImage( ) ) - ); - } - else if( catType == ":ImageToMeshFilter" ) - { - QAction* action = this->m_UI->menuExtractMesh-> - addAction( QString( cIt->first.c_str( ) ) ); - QObject::connect( - action, SIGNAL( triggered( ) ), - this, SLOT( triggered_aSegmentedImageToMesh( ) ) - ); - - } // fi - delete filter; - } // rof - } - else - { - QMessageBox::warning( - this, - tr( "Ignoring plugin" ), - tr( plugin.c_str( ) ) - ); - - } // fi - std::getline( in, plugin ); - - } // elihw - } - else - { - QMessageBox::critical( - this, - tr( "No plugins file loaded!" ), - tr( this->m_PluginsConfigurationFile.c_str( ) ) - ); - - } // fi - in.close( ); - - if( this->m_ImageReaderClassName == "" ) - { - QMessageBox::critical( - this, - tr( "No ImageReader found in plugins!" ), - tr( this->m_PluginsConfigurationFile.c_str( ) ) - ); - - } // fi - - if( this->m_ImageWriterClassName == "" ) - { - QMessageBox::critical( - this, - tr( "No ImageWriter found in plugins!" ), - tr( this->m_PluginsConfigurationFile.c_str( ) ) - ); - - } // fi - this->_UpdateEnabledFlags( ); - */ - } +} // ------------------------------------------------------------------------- bool MainWnd:: diff --git a/lib/cpm/Plugins/SimpleFillRegion.cxx b/lib/cpm/Plugins/SimpleFillRegion.cxx index 167c9e0..5dd4911 100644 --- a/lib/cpm/Plugins/SimpleFillRegion.cxx +++ b/lib/cpm/Plugins/SimpleFillRegion.cxx @@ -1,4 +1,29 @@ #include +#include + +#include +#include + +#define ITK_MANUAL_INSTANTIATION +#include + +// ------------------------------------------------------------------------- +#define cpmPlugins_SimpleFillRegion_Dimension( r, d, i1, i2, f ) \ + if( \ + dynamic_cast< itk::ImageBase< d >* >( i1 ) != NULL && \ + dynamic_cast< itk::ImageBase< d >* >( i2 ) != NULL \ + ) \ + r = this->f< d >( ) + +// ------------------------------------------------------------------------- +#define cpmPlugins_SimpleFillRegion_Pixel1( r, p, d, i, f ) \ + if( dynamic_cast< itk::Image< p, d >* >( i ) != NULL ) \ + r = this->f< p, d >( ) + +// ------------------------------------------------------------------------- +#define cpmPlugins_SimpleFillRegion_Pixel2( r, p1, p2, d, i, f ) \ + if( dynamic_cast< itk::Image< p2, d >* >( i ) != NULL ) \ + r = this->f< p1, p2, d >( ) // ------------------------------------------------------------------------- cpm::Plugins::SimpleFillRegion:: @@ -6,6 +31,8 @@ SimpleFillRegion( ) : Superclass( ) { this->SetNumberOfInputs( 2 ); + this->SetNumberOfOutputs( 1 ); + this->_MakeOutput< cpPlugins::Interface::Image >( 0 ); this->m_DefaultParameters[ "MinDelta" ] = TParameter( "double", "0" ); this->m_DefaultParameters[ "MaxDelta" ] = TParameter( "double", "0" ); @@ -29,7 +56,211 @@ GetClassName( ) const std::string cpm::Plugins::SimpleFillRegion:: _GenerateData( ) { - std::cout << "Simple fill region" << std::endl; + itk::DataObject* i1 = this->_GetInput( 0 ); + itk::DataObject* i2 = this->_GetInput( 1 ); + + std::string r = + "cpm::Plugins::SimpleFillRegion: itk::Image(s) dimensions not supported"; + cpmPlugins_SimpleFillRegion_Dimension( r, 2, i1, i2, _GD0 ); + else cpmPlugins_SimpleFillRegion_Dimension( r, 3, i1, i2, _GD0 ); + return( r ); +} + +// ------------------------------------------------------------------------- +template< unsigned int D > +std::string cpm::Plugins::SimpleFillRegion:: +_GD0( ) +{ + typedef itk::ImageBase< D > _TImage; + + _TImage* i1 = dynamic_cast< _TImage* >( this->_GetInput( 0 ) ); + + std::string r = + "cpm::Plugins::SimpleFillRegion: first image's pixel type not supported"; + cpmPlugins_SimpleFillRegion_Pixel1( r, char, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, short, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, int, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, long, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, unsigned char, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, unsigned short, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, unsigned int, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, unsigned long, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, float, D, i1, _GD1 ); + else cpmPlugins_SimpleFillRegion_Pixel1( r, double, D, i1, _GD1 ); + return( r ); +} + +// ------------------------------------------------------------------------- +template< class P1, unsigned int D > +std::string cpm::Plugins::SimpleFillRegion:: +_GD1( ) +{ + typedef itk::ImageBase< D > _TImage; + + _TImage* i2 = dynamic_cast< _TImage* >( this->_GetInput( 1 ) ); + + std::string r = + "cpm::Plugins::SimpleFillRegion: second image's pixel type not supported"; + cpmPlugins_SimpleFillRegion_Pixel2( r, P1, char, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, short, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, int, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, long, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, unsigned char, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, unsigned short, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, unsigned int, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, unsigned long, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, float, D, i2, _GD2 ); + else cpmPlugins_SimpleFillRegion_Pixel2( r, P1, double, D, i2, _GD2 ); + return( r ); +} + +// ------------------------------------------------------------------------- +template< typename I1, class I2, typename TCoordRep > +class SimpleFillRegionFunction + : public itk::BinaryThresholdImageFunction< I1, TCoordRep > +{ +public: + typedef SimpleFillRegionFunction Self; + typedef itk::BinaryThresholdImageFunction< I1, TCoordRep > Superclass; + typedef itk::SmartPointer< Self > Pointer; + typedef itk::SmartPointer< const Self > ConstPointer; + + itkTypeMacro( SimpleFillRegionFunction, itkBinaryThresholdImageFunction ); + itkNewMacro( Self ); + + itkSetConstObjectMacro( InputSegmentation, I2 ); + + typedef typename Superclass::InputImageType InputImageType; + typedef typename I1::PixelType PixelType; + itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); + typedef typename Superclass::PointType PointType; + typedef typename Superclass::IndexType IndexType; + typedef typename Superclass::ContinuousIndexType ContinuousIndexType; + + virtual bool EvaluateAtIndex( const IndexType& index ) const + { + bool cont = true; + if( this->m_InputSegmentation.IsNotNull( ) ) + cont = ( + this->m_InputSegmentation->GetPixel( index ) == + ( typename I2::PixelType )( 0 ) + ); + if( cont ) + return( this->Superclass::EvaluateAtIndex( index ) ); + else + return( false ); + } + +protected: + SimpleFillRegionFunction( ) + : Superclass( ) + { + } + virtual ~SimpleFillRegionFunction( ) + { + } + +private: + // Purposely not implemented + SimpleFillRegionFunction( const Self& ); + Self& operator=( const Self& ); + +protected: + typename I2::ConstPointer m_InputSegmentation; +}; + +// ------------------------------------------------------------------------- +template< class P1, class P2, unsigned int D > +std::string cpm::Plugins::SimpleFillRegion:: +_GD2( ) +{ + typedef itk::Image< P1, D > _TImage1; + typedef itk::Image< P2, D > _TImage2; + + _TImage1* i1 = dynamic_cast< _TImage1* >( this->_GetInput( 0 ) ); + _TImage2* i2 = dynamic_cast< _TImage2* >( this->_GetInput( 1 ) ); + + // Transform input seed + typename _TImage1::PointType pnt; + TParameters::const_iterator sIt; + sIt = this->m_Parameters.find( "Seed" ); + if( sIt == this->m_Parameters.end( ) ) + return( "cpm::Plugins::SimpleFillRegion: no seed given." ); + char* buff = new char[ sIt->second.second.size( ) + 1 ]; + std::memcpy( buff, sIt->second.second.c_str( ), sIt->second.second.size( ) ); + buff[ sIt->second.second.size( ) ] = '\0'; + char* tok = std::strtok( buff, ":" ); + for( unsigned int d = 0; d < D; ++d ) + { + pnt[ d ] = std::atof( tok ); + tok = std::strtok( NULL, ":" ); + + } // rof + delete [] buff; + typename _TImage1::IndexType idx; + if( !( i1->TransformPhysicalPointToIndex( pnt, idx ) ) ) + return( "cpm::Plugins::SimpleFillRegion: seed is outside image regions." ); + + // Check spatial compatilibity + if( i1->GetLargestPossibleRegion( ) != i2->GetLargestPossibleRegion( ) ) + return( "cpm::Plugins::SimpleFillRegion: incompatible regions." ); + if( i1->GetSpacing( ) != i2->GetSpacing( ) ) + return( "cpm::Plugins::SimpleFillRegion: incompatible spacings." ); + if( i1->GetOrigin( ) != i2->GetOrigin( ) ) + return( "cpm::Plugins::SimpleFillRegion: incompatible origins." ); + if( i1->GetDirection( ) != i2->GetDirection( ) ) + return( "cpm::Plugins::SimpleFillRegion: incompatible directions." ); + + // Create output + cpPlugins::Interface::Image* out_obj = + dynamic_cast< cpPlugins::Interface::Image* >( this->GetOutput( 0 ) ); + typename _TImage2::Pointer out = + dynamic_cast< _TImage2* >( out_obj->GetDataObject( ) ); + if( out.IsNull( ) ) + { + out = _TImage2::New( ); + this->_SetOutput( 0, out ); + + } // fi + + // Create memory, if needed + if( + i1->GetLargestPossibleRegion( ) != out->GetLargestPossibleRegion( ) || + i1->GetSpacing( ) != out->GetSpacing( ) || + i1->GetOrigin( ) != out->GetOrigin( ) || + i1->GetDirection( ) != out->GetDirection( ) + ) + { + out->SetLargestPossibleRegion( i1->GetLargestPossibleRegion( ) ); + out->SetRequestedRegion( i1->GetRequestedRegion( ) ); + out->SetBufferedRegion( i1->GetBufferedRegion( ) ); + out->SetDirection( i1->GetDirection( ) ); + out->SetOrigin( i1->GetOrigin( ) ); + out->SetSpacing( i1->GetSpacing( ) ); + out->Allocate( ); + + } // fi + out->FillBuffer( P2( 0 ) ); + + P1 min_delta = P1( std::atof( this->m_Parameters[ "MinDelta" ].second.c_str( ) ) ); + P1 max_delta = P1( std::atof( this->m_Parameters[ "MaxDelta" ].second.c_str( ) ) ); + P1 lower = i1->GetPixel( idx ) - min_delta; + P1 upper = i1->GetPixel( idx ) + min_delta; + + typedef SimpleFillRegionFunction< _TImage1, _TImage2, double > _TFunction; + typename _TFunction::Pointer f = _TFunction::New( ); + f->SetInputImage( i1 ); + f->SetInputSegmentation( i2 ); + f->ThresholdBetween( lower, upper ); + + typedef + itk::FloodFilledImageFunctionConditionalConstIterator< _TImage1, _TFunction > + _TIterator; + _TIterator fIt( i1, f, idx ); + for( fIt.GoToBegin( ); !fIt.IsAtEnd( ); ++fIt ) + out->SetPixel( fIt.GetIndex( ), 1 ); + + return( "" ); } // eof - $RCSfile$ diff --git a/lib/cpm/Plugins/SimpleFillRegion.h b/lib/cpm/Plugins/SimpleFillRegion.h index 1e84ef6..4b5cb9c 100644 --- a/lib/cpm/Plugins/SimpleFillRegion.h +++ b/lib/cpm/Plugins/SimpleFillRegion.h @@ -28,6 +28,15 @@ namespace cpm protected: virtual std::string _GenerateData( ); + template< unsigned int D > + std::string _GD0( ); + + template< class P1, unsigned int D > + std::string _GD1( ); + + template< class P1, class P2, unsigned int D > + std::string _GD2( ); + protected: itk::ProcessObject::Pointer m_Filter; }; -- 2.46.2