]> Creatis software - cpMesh.git/blobdiff - lib/cpm/Plugins/SimpleFillRegion.cxx
Simple flood fill plugin added.
[cpMesh.git] / lib / cpm / Plugins / SimpleFillRegion.cxx
index 167c9e040e5d2e1dab0b07464a27af7a88df0b87..5dd4911ec2216f930a3210226165afe98eb352c0 100644 (file)
@@ -1,4 +1,29 @@
 #include <cpm/Plugins/SimpleFillRegion.h>
+#include <cpPlugins/Interface/Image.h>
+
+#include <itkBinaryThresholdImageFunction.h>
+#include <itkFloodFilledImageFunctionConditionalConstIterator.h>
+
+#define ITK_MANUAL_INSTANTIATION
+#include <itkImage.h>
+
+// -------------------------------------------------------------------------
+#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$