]> Creatis software - FrontAlgorithms.git/blobdiff - libs/fpa/Image/MoriRegionGrow.hxx
...
[FrontAlgorithms.git] / libs / fpa / Image / MoriRegionGrow.hxx
index 737bf1f79d15acb515c1d9fb6f94a2f959c80bb3..5efdf65179c415022262bef81b57b23e19311e93 100644 (file)
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
 #ifndef __fpa__Image__MoriRegionGrow__hxx__
 #define __fpa__Image__MoriRegionGrow__hxx__
 
+#include <queue>
+#include <itkProgressReporter.h>
+
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
 typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TAuxImage*
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+TAuxiliaryImage*
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
 GetAuxiliaryImage( )
 {
-  return( this->m_Helper->GetOutput( ) );
+  return(
+    dynamic_cast< TAuxiliaryImage* >(
+      this->itk::ProcessObject::GetOutput( 1 )
+      )
+    );
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
 const typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TAuxImage*
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+TAuxiliaryImage*
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
 GetAuxiliaryImage( ) const
 {
-  return( this->m_Helper->GetOutput( ) );
+  return(
+    dynamic_cast< const TAuxiliaryImage* >(
+      this->itk::ProcessObject::GetOutput( 1 )
+      )
+    );
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TInputPixel
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-GetLower( ) const
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
+void
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+SetThresholdRange(
+  const TInputPixel& lower, const TInputPixel& upper,
+  const TInputPixel& delta
+  )
 {
-  return( this->m_Helper->GetLower( ) );
+  this->SetLowerThreshold( lower );
+  this->SetUpperThreshold( upper );
+  this->SetDeltaThreshold( delta );
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TInputPixel
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-GetUpper( ) const
-{
-  return( this->m_Helper->GetUpper( ) );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TInputPixel
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-GetStep( ) const
-{
-  return( this->m_Helper->GetStep( ) );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TOutputPixel
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-GetInsideValue( ) const
-{
-  return( this->m_Threshold->GetInsideValue( ) );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-typename
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-TOutputPixel
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-GetOutsideValue( ) const
-{
-  return( this->m_Threshold->GetInsideValue( ) );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-SetLower( const TInputPixel& v )
-{
-  this->m_Helper->SetLower( v );
-  this->Modified( );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-SetUpper( const TInputPixel& v )
-{
-  this->m_Helper->SetUpper( v );
-  this->Modified( );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-SetStep( const TInputPixel& v )
-{
-  this->m_Helper->SetStep( v );
-  this->Modified( );
-}
-
-// -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-SetInsideValue( const TOutputPixel& v )
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+MoriRegionGrow( )
+  : Superclass( )
 {
-  this->m_Threshold->SetInsideValue( v );
-  this->Modified( );
+  this->m_InsideValue = TOutputPixel( 1 );
+  this->m_OutsideValue = TOutputPixel( 0 );
+  this->m_UpperThreshold = std::numeric_limits< TInputPixel >::max( );
+  if( std::numeric_limits< TInputPixel >::is_integer )
+    this->m_LowerThreshold = std::numeric_limits< TInputPixel >::min( );
+  else
+    this->m_LowerThreshold = -this->m_UpperThreshold;
+  this->m_DeltaThreshold = TInputPixel( 1 );
+
+  this->SetNumberOfRequiredOutputs( 2 );
+  this->SetNthOutput( 0, TOutputImage::New( ) );
+  this->SetNthOutput( 1, TAuxiliaryImage::New( ) );
+
+  this->m_ThresholdFilter = TThresholdFilter::New( );
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-SetOutsideValue( const TOutputPixel& v )
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+~MoriRegionGrow( )
 {
-  this->m_Threshold->SetOutsideValue( v );
-  this->Modified( );
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-MoriRegionGrow( )
-  : Superclass( )
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
+void
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+GenerateInputRequestedRegion( )
 {
-  this->m_Helper = THelper::New( );
-  this->m_Threshold = TThreshold::New( );
+  this->Superclass::GenerateInputRequestedRegion( );
+  if( this->GetInput( ) )
+  {
+    TInputImage* input =
+      const_cast< TInputImage* >( this->GetInput( ) );
+    input->SetRequestedRegionToLargestPossibleRegion( );
+
+  } // fi
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
-~MoriRegionGrow( )
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
+void
+fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
+EnlargeOutputRequestedRegion( itk::DataObject* output )
 {
+  this->Superclass::EnlargeOutputRequestedRegion( output );
+  output->SetRequestedRegionToLargestPossibleRegion( );
 }
 
 // -------------------------------------------------------------------------
-template< class _TInputImage, class _TOutputImage, class _TAuxPixel >
-void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxPixel >::
+template< class _TInputImage, class _TOutputImage, class _TAuxiliaryPixel >
+void fpa::Image::MoriRegionGrow< _TInputImage, _TOutputImage, _TAuxiliaryPixel >::
 GenerateData( )
 {
-  this->m_Helper->ClearSeeds( );
-  this->m_Helper->AddSeed( this->m_Seed, 0 );
-  this->m_Helper->SetInput( this->GetInput( ) );
-  this->m_Helper->Update( );
-
-  this->m_Threshold->SetInput( this->m_Helper->GetOutput( ) );
-  this->m_Threshold->SetLowerThreshold( std::numeric_limits< _TAuxPixel >::min( ) );
-  this->m_Threshold->SetUpperThreshold( this->m_Helper->GetOptimumThreshold( ) );
-  this->m_Threshold->Update( );
-  this->GetOutput( )->Graft( this->m_Threshold->GetOutput( ) );
+  const TInputImage* input = this->GetInput( );
+  TAuxiliaryImage* auxiliary = this->GetAuxiliaryImage( );
+  TRegion region = input->GetRequestedRegion( );
+
+  // Prepare progress counter
+  double prog_size = double( this->m_UpperThreshold - this->m_LowerThreshold );
+  prog_size /= double( this->m_DeltaThreshold );
+  itk::ProgressReporter progress( this, 0, prog_size, 100, 0, 0.7 );
+
+  // Configure outputs
+  auxiliary->SetBufferedRegion( region );
+  auxiliary->Allocate( );
+  auxiliary->FillBuffer( 0 );
+
+  // Init marks
+  typedef itk::Image< bool, TInputImage::ImageDimension > _TMarks;
+  typename _TMarks::Pointer marks = _TMarks::New( );
+  marks->CopyInformation( input );
+  marks->SetRequestedRegion( region );
+  marks->SetBufferedRegion( input->GetBufferedRegion( ) );
+  marks->Allocate( );
+  marks->FillBuffer( false );
+
+  // Prepare queues
+  std::queue< TIndex > queues[ 2 ];
+  queues[ 0 ].push( this->m_Seed );
+  unsigned int cur_queue = 0;
+  unsigned int aux_queue = 1;
+
+  // Incremental strategy
+  TInputPixel upper = this->m_LowerThreshold + this->m_DeltaThreshold;
+  this->m_Curve.clear( );
+  unsigned long count = 0;
+  while( upper <= this->m_UpperThreshold )
+  {
+    // Main growing strategy
+    while( queues[ cur_queue ].size( ) > 0 )
+    {
+      // Get next candidate
+      TIndex node = queues[ cur_queue ].front( );
+      queues[ cur_queue ].pop( );
+      if( marks->GetPixel( node ) )
+        continue;
+      marks->SetPixel( node, true );
+
+      // Apply inclusion predicate
+      TInputPixel value = input->GetPixel( node );
+      bool in = ( ( this->m_LowerThreshold < value ) && ( value < upper ) );
+      if( !in )
+      {
+        if( value < this->m_UpperThreshold )
+          queues[ aux_queue ].push( node );
+        marks->SetPixel( node, false );
+        continue;
+
+      } // fi
+
+      // Ok, pixel lays inside region
+      auxiliary->SetPixel( node, this->m_Curve.size( ) + 1 );
+      count++;
+
+      // Add neighborhood
+      for( unsigned int d = 0; d < TInputImage::ImageDimension; ++d )
+      {
+        TIndex neigh = node;
+        for( int i = -1; i <= 1; i += 2 )
+        {
+          neigh[ d ] = node[ d ] + i;
+          if( region.IsInside( neigh ) )
+            queues[ cur_queue ].push( neigh );
+
+        } // rof
+
+      } // rof
+
+    } // elihw
+
+    // Update curve
+    if( this->m_Curve.size( ) > 0 )
+    {
+      if( this->m_Curve.back( ).YValue < count )
+        this->m_Curve.push_back( TCurveData( upper, count ) );
+      if( this->m_Curve.size( ) > 2 )
+      {
+        long j = this->m_Curve.size( ) - 2;
+        double yp = double( this->m_Curve[ j + 1 ].YValue );
+        double yn = double( this->m_Curve[ j - 1 ].YValue );
+        double xp = double( this->m_Curve[ j + 1 ].XValue );
+        double xn = double( this->m_Curve[ j - 1 ].XValue );
+        this->m_Curve[ j ].Diff1 = ( yp - yn ) / ( xp - xn );
+
+      } // fi
+    }
+    else
+      this->m_Curve.push_back( TCurveData( upper, count ) );
+
+    // Update queue
+    cur_queue = aux_queue;
+    aux_queue = ( cur_queue + 1 ) % 2;
+
+    // Update threshold
+    upper += this->m_DeltaThreshold;
+    progress.CompletedPixel( );
+
+  } // elihw
+
+  // Compute optimum threshold
+  double dmax = -std::numeric_limits< double >::max( );
+  int jmax = 0;
+  for( int j = 1; j < this->m_Curve.size( ) - 1; ++j )
+  {
+    double dp = this->m_Curve[ j + 1 ].Diff1;
+    double dn = this->m_Curve[ j - 1 ].Diff1;
+    double xp = double( this->m_Curve[ j + 1 ].XValue );
+    double xn = double( this->m_Curve[ j - 1 ].XValue );
+    double d2 = ( dp - dn ) / ( xp - xn );
+    if( d2 > dmax )
+    {
+      dmax = d2;
+      jmax = j;
+
+    } // fi
+
+  } // rof
+  this->m_OptimumThreshold = this->m_Curve[ jmax ].XValue;
+
+  // Final threshold
+  this->m_ThresholdFilter->SetInput( auxiliary );
+  this->m_ThresholdFilter->SetInsideValue( this->m_InsideValue );
+  this->m_ThresholdFilter->SetOutsideValue( this->m_OutsideValue );
+  this->m_ThresholdFilter->SetLowerThreshold( 1 );
+  this->m_ThresholdFilter->SetUpperThreshold( jmax );
+  this->m_ThresholdFilter->Update( );
+  this->GetOutput( )->Graft( this->m_ThresholdFilter->GetOutput( ) );
 }
 
 #endif // __fpa__Image__MoriRegionGrow__hxx__