--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Base__MarksInterface__h__
+#define __fpa__Base__MarksInterface__h__
+
+#include <itkProcessObject.h>
+#include <vector>
+
+namespace fpa
+{
+ namespace Base
+ {
+ /**
+ */
+ template< class _TVertex >
+ class MarksInterface
+ {
+ public:
+ typedef _TVertex TVertex;
+ typedef MarksInterface Self;
+
+ // Minigraph to represent collisions
+ typedef std::pair< _TVertex, bool > TCollision;
+ typedef std::vector< TCollision > TCollisionsRow;
+ typedef std::vector< TCollisionsRow > TCollisions;
+
+ public:
+ bool StopAtOneFront( ) const;
+ void StopAtOneFrontOn( );
+ void StopAtOneFrontOff( );
+ void SetStopAtOneFront( bool v );
+
+ protected:
+ MarksInterface( itk::ProcessObject* filter );
+ virtual ~MarksInterface( );
+
+ virtual bool _IsMarked( const TVertex& v ) const = 0;
+ virtual unsigned long _GetMark( const TVertex& v ) const = 0;
+ virtual void _Mark( const TVertex& v, unsigned long frontId ) = 0;
+ virtual void _FreeMarks( ) = 0;
+
+ virtual void _InitMarks( unsigned long nSeeds );
+ unsigned long _Collisions( const TVertex& a, const TVertex& b );
+
+ protected:
+ bool m_StopAtOneFront;
+ TCollisions m_Collisions;
+ unsigned int m_NumberOfFronts;
+ unsigned int m_NumberOfSeeds;
+ itk::ProcessObject* m_Filter;
+ };
+
+ } // ecapseman
+
+} // ecapseman
+
+#ifndef ITK_MANUAL_INSTANTIATION
+# include <fpa/Base/MarksInterface.hxx>
+#endif // ITK_MANUAL_INSTANTIATION
+
+#endif // __fpa__Base__MarksInterface__h__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Base__MarksInterface__hxx__
+#define __fpa__Base__MarksInterface__hxx__
+
+#include <queue>
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+bool fpa::Base::MarksInterface< _TVertex >::
+StopAtOneFront( ) const
+{
+ return( this->m_StopAtOneFront );
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+void fpa::Base::MarksInterface< _TVertex >::
+StopAtOneFrontOn( )
+{
+ this->SetStopAtOneFront( true );
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+void fpa::Base::MarksInterface< _TVertex >::
+StopAtOneFrontOff( )
+{
+ this->SetStopAtOneFront( false );
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+void fpa::Base::MarksInterface< _TVertex >::
+SetStopAtOneFront( bool v )
+{
+ if( this->m_StopAtOneFront != v )
+ {
+ this->m_StopAtOneFront = v;
+ if( this->m_Filter != NULL )
+ this->m_Filter->Modified( );
+
+ } // fi
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+fpa::Base::MarksInterface< _TVertex >::
+MarksInterface( itk::ProcessObject* filter )
+ : m_StopAtOneFront( false ),
+ m_NumberOfFronts( 0 ),
+ m_NumberOfSeeds( 0 ),
+ m_Filter( filter )
+{
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+fpa::Base::MarksInterface< _TVertex >::
+~MarksInterface( )
+{
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+void fpa::Base::MarksInterface< _TVertex >::
+_InitMarks( unsigned long nSeeds )
+{
+ this->m_NumberOfFronts = this->m_NumberOfSeeds = nSeeds;
+ TCollision coll( TVertex( ), false );
+ TCollisionsRow row( this->m_NumberOfFronts, coll );
+ this->m_Collisions.clear( );
+ this->m_Collisions.resize( this->m_NumberOfFronts, row );
+}
+
+// -------------------------------------------------------------------------
+template< class _TVertex >
+unsigned long fpa::Base::MarksInterface< _TVertex >::
+_Collisions( const TVertex& a, const TVertex& b )
+{
+ auto ma = this->_GetMark( a );
+ auto mb = this->_GetMark( b );
+ if( ma == mb || ma == 0 || mb == 0 )
+ return( this->m_NumberOfFronts );
+
+ // Mark collision, if it is new
+ ma--; mb--;
+ bool ret = false;
+ bool exists = this->m_Collisions[ ma ][ mb ].second;
+ exists &= this->m_Collisions[ mb ][ ma ].second;
+ if( !exists )
+ {
+ this->m_Collisions[ ma ][ mb ].first = a;
+ this->m_Collisions[ ma ][ mb ].second = true;
+ this->m_Collisions[ mb ][ ma ].first = b;
+ this->m_Collisions[ mb ][ ma ].second = true;
+
+ // Update number of fronts
+ unsigned long count = 0;
+ std::vector< bool > m( this->m_NumberOfSeeds, false );
+ std::queue< unsigned long > q;
+ q.push( 0 );
+ while( !q.empty( ) )
+ {
+ unsigned long f = q.front( );
+ q.pop( );
+
+ if( m[ f ] )
+ continue;
+ m[ f ] = true;
+ count++;
+
+ for( unsigned int n = 0; n < this->m_NumberOfSeeds; ++n )
+ if( this->m_Collisions[ f ][ n ].second && !m[ n ] )
+ q.push( n );
+
+ } // elihw
+ this->m_NumberOfFronts = this->m_NumberOfSeeds - count;
+
+ } // fi
+ return( this->m_NumberOfFronts );
+}
+
+#endif // __fpa__Base__MarksInterface__hxx__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__MarksInterface__h__
+#define __fpa__Image__MarksInterface__h__
+
+#include <fpa/Base/MarksInterface.h>
+#include <itkIndex.h>
+#include <itkImage.h>
+
+namespace fpa
+{
+ namespace Image
+ {
+ /**
+ */
+ template< unsigned int _VDim >
+ class MarksInterface
+ : public fpa::Base::MarksInterface< itk::Index< _VDim > >
+ {
+ public:
+ typedef MarksInterface Self;
+ typedef fpa::Base::MarksInterface< itk::Index< _VDim > > Superclass;
+
+ typedef typename Superclass::TVertex TVertex;
+ typedef typename Superclass::TCollision TCollision;
+ typedef typename Superclass::TCollisionsRow TCollisionsRow;
+ typedef typename Superclass::TCollisions TCollisions;
+
+ typedef itk::Image< unsigned long, _VDim > TMarks;
+
+ protected:
+ virtual bool _IsMarked( const TVertex& v ) const override;
+ virtual unsigned long _GetMark( const TVertex& v ) const override;
+ virtual void _Mark( const TVertex& v, unsigned long frontId ) override;
+ virtual void _FreeMarks( ) override;
+ virtual void _InitMarks( unsigned long nSeeds ) override;
+
+ protected:
+ MarksInterface( itk::ProcessObject* filter );
+ virtual ~MarksInterface( );
+
+ private:
+ typename TMarks::Pointer m_Marks;
+ };
+
+ } // ecapseman
+
+} // ecapseman
+
+#ifndef ITK_MANUAL_INSTANTIATION
+# include <fpa/Image/MarksInterface.hxx>
+#endif // ITK_MANUAL_INSTANTIATION
+
+#endif // __fpa__Image__MarksInterface__h__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__MarksInterface__hxx__
+#define __fpa__Image__MarksInterface__hxx__
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+bool fpa::Image::MarksInterface< _VDim >::
+_IsMarked( const TVertex& v ) const
+{
+ return( this->m_Marks->GetPixel( v ) != 0 );
+}
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+unsigned long fpa::Image::MarksInterface< _VDim >::
+_GetMark( const TVertex& v ) const
+{
+ return( this->m_Marks->GetPixel( v ) );
+}
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+void fpa::Image::MarksInterface< _VDim >::
+_Mark( const TVertex& v, unsigned long frontId )
+{
+ this->m_Marks->SetPixel( v, frontId );
+}
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+void fpa::Image::MarksInterface< _VDim >::
+_FreeMarks( )
+{
+ this->m_Marks = NULL;
+}
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+void fpa::Image::MarksInterface< _VDim >::
+_InitMarks( unsigned long nSeeds )
+{
+ this->Superclass::_InitMarks( nSeeds );
+
+ // Try to guess input
+ if( this->m_Filter == NULL )
+ return;
+ if( this->m_Filter->GetInputs( ).size( ) == 0 )
+ return;
+ itk::ImageBase< _VDim >* input =
+ dynamic_cast< itk::ImageBase< _VDim >* >(
+ this->m_Filter->GetInputs( )[ 0 ].GetPointer( )
+ );
+ if( input == NULL )
+ return;
+
+ // Reserve memory for marks
+ this->m_Marks = TMarks::New( );
+ this->m_Marks->CopyInformation( input );
+ this->m_Marks->SetRequestedRegion( input->GetRequestedRegion( ) );
+ this->m_Marks->SetBufferedRegion( input->GetBufferedRegion( ) );
+ this->m_Marks->Allocate( );
+ this->m_Marks->FillBuffer( false );
+}
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+fpa::Image::MarksInterface< _VDim >::
+MarksInterface( itk::ProcessObject* filter )
+ : Superclass( filter )
+{
+}
+
+// -------------------------------------------------------------------------
+template< unsigned int _VDim >
+fpa::Image::MarksInterface< _VDim >::
+~MarksInterface( )
+{
+}
+
+#endif // __fpa__Image__MarksInterface__hxx__
+
+// eof - $RCSfile$
#include <itkImageToImageFilter.h>
#include <itkFunctionBase.h>
#include <fpa/Base/SeedsInterface.h>
+#include <fpa/Image/MarksInterface.h>
namespace fpa
{
template< class _TInputImage, class _TOutputImage >
class RegionGrow
: public itk::ImageToImageFilter< _TInputImage, _TOutputImage >,
- public fpa::Base::SeedsInterface< typename _TInputImage::IndexType, typename _TInputImage::IndexType::LexicographicCompare >
+ public fpa::Base::SeedsInterface< typename _TInputImage::IndexType, typename _TInputImage::IndexType::LexicographicCompare >,
+ public fpa::Image::MarksInterface< _TInputImage::ImageDimension >
{
public:
typedef _TInputImage TInputImage;
typedef itk::SmartPointer< const Self > ConstPointer;
typedef fpa::Base::SeedsInterface< TIndex, TIndexCompare > TSeedsInterface;
+ typedef fpa::Image::MarksInterface< _TInputImage::ImageDimension > TMarksInterface;
typedef itk::FunctionBase< TInputPixel, bool > TIntensityFunctor;
public:
protected:
typename TIntensityFunctor::Pointer m_IntensityFunctor;
- /* TODO
- TSeeds m_Seeds;
- */
TOutputPixel m_InsideValue;
TOutputPixel m_OutsideValue;
};
RegionGrow( )
: Superclass( ),
TSeedsInterface( this ),
+ TMarksInterface( this ),
m_InsideValue( TInputPixel( 0 ) ),
m_OutsideValue( TInputPixel( 0 ) )
{
output->FillBuffer( this->m_OutsideValue );
// 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 );
+ this->_InitMarks( this->GetNumberOfSeeds( ) );
// Init queue
- std::queue< TIndex > q;
+ typedef std::pair< TIndex, unsigned long > _TNode;
+ std::queue< _TNode > q;
+ unsigned long frontId = 1;
for( TIndex seed: this->GetSeeds( ) )
- q.push( seed );
+ q.push( _TNode( seed, frontId++ ) );
// Main loop
while( q.size( ) > 0 )
{
// Get next candidate
- TIndex node = q.front( );
+ _TNode node = q.front( );
q.pop( );
- if( marks->GetPixel( node ) )
+ if( this->_IsMarked( node.first ) )
continue;
- marks->SetPixel( node, true );
+ this->_Mark( node.first, node.second );
// Apply inclusion predicate
- TInputPixel value = input->GetPixel( node );
+ TInputPixel value = input->GetPixel( node.first );
bool inside = false;
if( this->m_IntensityFunctor.IsNotNull( ) )
inside = this->m_IntensityFunctor->Evaluate( value );
continue;
// Ok, pixel lays inside region
- output->SetPixel( node, this->m_InsideValue );
+ output->SetPixel( node.first, this->m_InsideValue );
// Add neighborhood
for( unsigned int d = 0; d < TInputImage::ImageDimension; ++d )
{
- TIndex neigh = node;
+ TIndex neigh = node.first;
for( int i = -1; i <= 1; i += 2 )
{
- neigh[ d ] = node[ d ] + i;
+ neigh[ d ] = node.first[ d ] + i;
if( region.IsInside( neigh ) )
- q.push( neigh );
+ {
+ if( this->_IsMarked( neigh ) )
+ {
+ unsigned long nColl = this->_Collisions( node.first, neigh );
+ if( nColl == 1 && this->StopAtOneFront( ) )
+ while( q.size( ) > 0 )
+ q.pop( );
+ }
+ else
+ q.push( _TNode( neigh, node.second ) );
+
+ } // fi
} // rof
} // rof
} // elihw
+ this->_FreeMarks( );
}
#endif // __fpa__Image__RegionGrow__hxx__