#ifndef __fpa__Image__SkeletonFilter__hxx__ #define __fpa__Image__SkeletonFilter__hxx__ #include #include // ------------------------------------------------------------------------- #define fpa_Image_SkeletonFilter_InputMacro( i_n, i_t, i_i ) \ template< class _TDistanceMap, class _TCostMap > \ typename fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ i_t* fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ Get##i_n( ) \ { \ return( \ dynamic_cast< i_t* >( this->Superclass::GetInput( i_i ) ) \ ); \ } \ template< class _TDistanceMap, class _TCostMap > \ const \ typename fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ i_t* fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ Get##i_n( ) const \ { \ return( \ dynamic_cast< const i_t* >( this->Superclass::GetInput( i_i ) ) \ ); \ } \ template< class _TDistanceMap, class _TCostMap > \ void fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ Set##i_n( i_t* input ) \ { \ this->Superclass::SetNthInput( i_i, input ); \ } fpa_Image_SkeletonFilter_InputMacro( DistanceMap, TDistanceMap, 0 ); fpa_Image_SkeletonFilter_InputMacro( CostMap, TCostMap, 1 ); fpa_Image_SkeletonFilter_InputMacro( MinimumSpanningTree, TMST, 2 ); // ------------------------------------------------------------------------- #define fpa_Image_SkeletonFilter_OutputMacro( o_n, o_t, o_i ) \ template< class _TDistanceMap, class _TCostMap > \ typename fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ o_t* fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ Get##o_n( ) \ { \ return( \ dynamic_cast< o_t* >( this->Superclass::GetOutput( o_i ) ) \ ); \ } \ template< class _TDistanceMap, class _TCostMap > \ const typename \ fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ o_t* fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: \ Get##o_n( ) const \ { \ return( \ dynamic_cast< const o_t* >( this->Superclass::GetOutput( o_i ) ) \ ); \ } fpa_Image_SkeletonFilter_OutputMacro( Skeleton, TSkeleton, 0 ); fpa_Image_SkeletonFilter_OutputMacro( EndPoints, TIndices, 1 ); fpa_Image_SkeletonFilter_OutputMacro( Bifurcations, TIndices, 2 ); fpa_Image_SkeletonFilter_OutputMacro( Marks, TMarks, 3 ); // ------------------------------------------------------------------------- template< class _TDistanceMap, class _TCostMap > fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: SkeletonFilter( ) : Superclass( ) { this->SetNumberOfRequiredInputs( 3 ); this->SetNumberOfRequiredOutputs( 3 ); typename TIndices::Pointer end_points = TIndices::New( ); typename TIndices::Pointer bifurcations = TIndices::New( ); typename TSkeleton::Pointer skeleton = TSkeleton::New( ); typename TMarks::Pointer marks = TMarks::New( ); this->SetNthOutput( 0, skeleton.GetPointer( ) ); this->SetNthOutput( 1, end_points.GetPointer( ) ); this->SetNthOutput( 2, bifurcations.GetPointer( ) ); this->SetNthOutput( 3, marks.GetPointer( ) ); } // ------------------------------------------------------------------------- template< class _TDistanceMap, class _TCostMap > fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: ~SkeletonFilter( ) { } // ------------------------------------------------------------------------- template< class _TDistanceMap, class _TCostMap > void fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: GenerateData( ) { // 0. I/O objects const TDistanceMap* dmap = this->GetDistanceMap( ); const TCostMap* cmap = this->GetCostMap( ); const TMST* mst = this->GetMinimumSpanningTree( ); TIndices* ep = this->GetEndPoints( ); TIndices* bi = this->GetBifurcations( ); TSkeleton* sk = this->GetSkeleton( ); // 1. Check input correspondance // TODO // 2. Detect end-points this->_EndPoints( dmap, cmap, mst, ep->Get( ) ); // 3. Build skeleton and keep track of bifurcations this->_Skeleton( dmap, cmap, mst, ep->Get( ), bi->Get( ), sk ); } // ------------------------------------------------------------------------- template< class _TDistanceMap, class _TCostMap > void fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: _EndPoints( const TDistanceMap* dmap, const TCostMap* cmap, const TMST* mst, TIndicesData& end_points ) { typedef itk::ImageRegionConstIteratorWithIndex< _TDistanceMap > _TDistMapIt; typedef itk::ImageRegionConstIteratorWithIndex< _TCostMap > _TCostMapIt; typedef std::multimap< double, TIndex, std::greater< double > > _TQueue; typedef typename _TQueue::value_type _TQueueValue; typedef itk::Image< unsigned char, _TCostMap::ImageDimension > _TMarks; // Some values // typename _TMarks::Pointer marks = _TMarks::New( ); auto marks = this->GetMarks( ); marks->SetLargestPossibleRegion( dmap->GetLargestPossibleRegion( ) ); marks->SetRequestedRegion( dmap->GetRequestedRegion( ) ); marks->SetBufferedRegion( dmap->GetBufferedRegion( ) ); marks->SetSpacing( dmap->GetSpacing( ) ); marks->SetOrigin( dmap->GetOrigin( ) ); marks->SetDirection( dmap->GetDirection( ) ); marks->Allocate( ); marks->FillBuffer( 0 ); // Create queue _TQueue queue; _TDistMapIt dIt( dmap, dmap->GetRequestedRegion( ) ); _TCostMapIt cIt( cmap, cmap->GetRequestedRegion( ) ); dIt.GoToBegin( ); cIt.GoToBegin( ); for( ; !dIt.IsAtEnd( ) && !cIt.IsAtEnd( ); ++dIt, ++cIt ) { double d = double( dIt.Get( ) ); if( d > 0 ) { double v = double( cIt.Get( ) ) / ( d * d ); queue.insert( _TQueueValue( v, dIt.GetIndex( ) ) ); } // fi } // rof // BFS from maximum queue auto region = dmap->GetRequestedRegion( ); double init_v = queue.begin( )->first; while( queue.size( ) > 0 ) { // Get node auto nIt = queue.begin( ); auto n = *nIt; queue.erase( nIt ); unsigned char m = marks->GetPixel( n.second ); // if( ( m & 0x01 ) == 0x01 ) if( m != 0 || ( n.first / init_v ) < double( 1e-1 ) ) continue; // Mark it and update end-points m |= 0x01; marks->SetPixel( n.second, m ); end_points.insert( n.second ); // Get path typename TMST::TPath::Pointer path; mst->GetPath( path, n.second ); for( unsigned long i = 0; i < path->GetSize( ); ++i ) { TIndex idx = path->GetVertex( i ); typename _TCostMap::PointType cnt; cmap->TransformIndexToPhysicalPoint( idx, cnt ); double d = double( 2 ) * double( dmap->GetPixel( idx ) ); // Mark sphere std::queue< TIndex > q; q.push( idx ); while( q.size( ) > 0 ) { TIndex v = q.front( ); q.pop( ); unsigned char m = marks->GetPixel( v ); if( ( m & 0x02 ) == 0x02 ) continue; m |= 0x02; marks->SetPixel( v, m ); for( unsigned int x = 0; x < _TCostMap::ImageDimension; ++x ) { for( int y = -1; y <= 1; y += 2 ) { TIndex w = v; w[ x ] += y; if( region.IsInside( w ) ) { typename _TCostMap::PointType p; cmap->TransformIndexToPhysicalPoint( w, p ); if( cnt.EuclideanDistanceTo( p ) <= d ) q.push( w ); } // fi } // rof } // rof } // elihw } // rof } // elihw } // ------------------------------------------------------------------------- template< class _TDistanceMap, class _TCostMap > void fpa::Image::SkeletonFilter< _TDistanceMap, _TCostMap >:: _Skeleton( const TDistanceMap* dmap, const TCostMap* cmap, const TMST* mst, const TIndicesData& end_points, TIndicesData& bifurcations, TSkeleton* skeleton ) { typedef typename TMST::TPath _TPath; for( auto eIt = end_points.begin( ); eIt != end_points.end( ); ++eIt ) { typename _TPath::Pointer path; mst->GetPath( path, *eIt ); skeleton->AddBranch( path ); } // rof } #endif // __fpa__Image__SkeletonFilter__hxx__ // eof - $RCSfile$