1 #ifndef __fpa__Image__SkeletonFilter__hxx__
2 #define __fpa__Image__SkeletonFilter__hxx__
4 #include <fpa/Base/Functors/Inverse.h>
5 #include <fpa/Image/Functors/SimpleNeighborhood.h>
6 #include <itkImageRegionIteratorWithIndex.h>
8 // -------------------------------------------------------------------------
9 #define fpa_Image_SkeletonFilter_OutputMacro( o_n, o_t ) \
10 template< class _TImage > \
11 typename fpa::Image::SkeletonFilter< _TImage >:: \
12 o_t* fpa::Image::SkeletonFilter< _TImage >:: \
16 dynamic_cast< o_t* >( \
17 this->itk::ProcessObject::GetOutput( this->m_##o_n##Idx ) \
22 fpa_Image_SkeletonFilter_OutputMacro( Skeleton, TSkeleton );
23 fpa_Image_SkeletonFilter_OutputMacro( Marks, TMarks );
25 // -------------------------------------------------------------------------
26 template< class _TImage >
27 fpa::Image::SkeletonFilter< _TImage >::
31 typedef typename _TImage::PixelType _TPixel;
32 typedef typename _TImage::Superclass _TImageBase;
33 typedef fpa::Image::Functors::SimpleNeighborhood< _TImageBase > _TNeighFunc;
34 typedef fpa::Base::Functors::Inverse< _TPixel, _TPixel > _TInvFunc;
36 unsigned int nOutputs = this->GetNumberOfRequiredOutputs( );
37 this->SetNumberOfRequiredOutputs( nOutputs + 2 );
38 this->m_SkeletonIdx = nOutputs;
39 this->m_MarksIdx = nOutputs + 1;
41 typename TSkeleton::Pointer skeleton = TSkeleton::New( );
42 typename TMarks::Pointer marks = TMarks::New( );
43 this->SetNthOutput( this->m_SkeletonIdx, skeleton.GetPointer( ) );
44 this->SetNthOutput( this->m_MarksIdx, marks.GetPointer( ) );
46 typename _TNeighFunc::Pointer nfunc = _TNeighFunc::New( );
48 this->SetNeighborhoodFunction( nfunc );
50 typename _TInvFunc::Pointer ifunc = _TInvFunc::New( );
51 this->SetCostConversionFunction( ifunc );
54 // -------------------------------------------------------------------------
55 template< class _TImage >
56 fpa::Image::SkeletonFilter< _TImage >::
61 // -------------------------------------------------------------------------
62 template< class _TImage >
63 void fpa::Image::SkeletonFilter< _TImage >::
64 _BeforeGenerateData( )
66 this->Superclass::_BeforeGenerateData( );
67 this->m_SkeletonQueue.clear( );
70 // -------------------------------------------------------------------------
71 template< class _TImage >
72 void fpa::Image::SkeletonFilter< _TImage >::
73 _UpdateResult( const _TQueueNode& n )
75 typedef typename _TSkeletonQueue::value_type _TSkeletonQueueValue;
77 this->Superclass::_UpdateResult( n );
78 double d = double( this->GetInput( )->GetPixel( n.Vertex ) );
79 if( d >= double( 0 ) )
81 // Update skeleton candidates
83 double v = double( n.Result ) / ( d * d );
84 this->m_SkeletonQueue.insert( _TSkeletonQueueValue( v, n.Vertex ) );
89 // -------------------------------------------------------------------------
90 template< class _TImage >
91 void fpa::Image::SkeletonFilter< _TImage >::
94 this->Superclass::_AfterGenerateData( );
97 std::vector< TIndex > end_points;
98 this->_EndPoints( end_points, A );
99 this->_Skeleton( end_points, A );
102 // -------------------------------------------------------------------------
103 template< class _TImage >
104 void fpa::Image::SkeletonFilter< _TImage >::
105 _EndPoints( std::vector< TIndex >& end_points, _TAdjacencies& A )
107 auto marks = this->GetMarks( );
108 auto mst = this->GetMinimumSpanningTree( );
109 auto spac = marks->GetSpacing( );
112 marks->SetLargestPossibleRegion( mst->GetLargestPossibleRegion( ) );
113 marks->SetRequestedRegion( mst->GetRequestedRegion( ) );
114 marks->SetBufferedRegion( mst->GetBufferedRegion( ) );
115 marks->SetSpacing( mst->GetSpacing( ) );
116 marks->SetOrigin( mst->GetOrigin( ) );
117 marks->SetDirection( mst->GetDirection( ) );
119 marks->FillBuffer( 0 );
121 // BFS from maximum queue
122 while( this->m_SkeletonQueue.size( ) > 0 )
125 auto nIt = this->m_SkeletonQueue.begin( );
127 this->m_SkeletonQueue.erase( nIt );
129 // Mark it and update end-points
130 unsigned char m = marks->GetPixel( n.second );
133 marks->SetPixel( n.second, 1 );
134 end_points.push_back( n.second );
135 std::cout << this->m_SkeletonQueue.size( ) << std::endl;
138 TIndex it = n.second;
139 TIndex p = mst->GetParent( it );
142 this->_MarkSphere( it );
144 p = mst->GetParent( it );
147 this->_MarkSphere( it );
153 // -------------------------------------------------------------------------
154 template< class _TImage >
155 void fpa::Image::SkeletonFilter< _TImage >::
156 _Skeleton( const std::vector< TIndex >& end_points, _TAdjacencies& A )
158 std::cout << end_points.size( ) << " " << A.size( ) << std::endl;
161 typedef itk::Image< unsigned long, Self::Dimension > _TTagsImage;
162 typedef typename TMST::TPath _TPath;
164 auto mst = this->GetMinimumSpanningTree( );
165 auto skeleton = this->GetSkeleton( );
168 typename _TTagsImage::Pointer tags = _TTagsImage::New( );
169 tags->SetLargestPossibleRegion( mst->GetLargestPossibleRegion( ) );
170 tags->SetRequestedRegion( mst->GetRequestedRegion( ) );
171 tags->SetBufferedRegion( mst->GetBufferedRegion( ) );
173 tags->FillBuffer( 0 );
174 for( auto eIt = end_points.begin( ); eIt != end_points.end( ); ++eIt )
177 TIndex p = mst->GetParent( it );
180 tags->SetPixel( it, tags->GetPixel( it ) + 1 );
182 p = mst->GetParent( it );
185 tags->SetPixel( it, tags->GetPixel( it ) + 1 );
189 // Build paths (branches)
190 for( auto eIt = end_points.begin( ); eIt != end_points.end( ); ++eIt )
193 TIndex p = mst->GetParent( it );
195 typename _TPath::Pointer path = _TPath::New( );
196 path->SetReferenceImage( mst );
199 if( tags->GetPixel( sIdx ) != tags->GetPixel( it ) )
201 // Ok, a new branch has been added
202 path->AddVertex( it );
203 skeleton->AddBranch( path );
205 // Update a new starting index
206 path = _TPath::New( );
207 path->SetReferenceImage( mst );
211 path->AddVertex( it );
213 p = mst->GetParent( it );
217 // Finally, add last branch
218 path->AddVertex( it );
219 skeleton->AddBranch( path );
225 // -------------------------------------------------------------------------
226 template< class _TImage >
227 void fpa::Image::SkeletonFilter< _TImage >::
228 _MarkSphere( const TIndex& idx )
230 typedef itk::ImageRegionIteratorWithIndex< TMarks > _TMarksIt;
232 static const double _eps = std::sqrt( double( Self::Dimension + 1 ) );
233 auto input = this->GetInput( );
234 auto marks = this->GetMarks( );
235 auto spac = input->GetSpacing( );
236 auto region = input->GetRequestedRegion( );
238 typename _TImage::PointType cnt;
239 input->TransformIndexToPhysicalPoint( idx, cnt );
240 double r = double( input->GetPixel( idx ) ) * _eps;
243 for( unsigned int d = 0; d < Self::Dimension; ++d )
245 long off = long( std::ceil( r / double( spac[ d ] ) ) );
248 i0[ d ] = idx[ d ] - off;
249 i1[ d ] = idx[ d ] + off;
251 if( i0[ d ] < region.GetIndex( )[ d ] )
252 i0[ d ] = region.GetIndex( )[ d ];
254 if( i1[ d ] >= region.GetIndex( )[ d ] + region.GetSize( )[ d ] )
255 i1[ d ] = region.GetIndex( )[ d ] + region.GetSize( )[ d ] - 1;
259 typename _TImage::SizeType size;
260 for( unsigned int d = 0; d < Self::Dimension; ++d )
261 size[ d ] = i1[ d ] - i0[ d ] + 1;
263 typename _TImage::RegionType neighRegion;
264 neighRegion.SetIndex( i0 );
265 neighRegion.SetSize( size );
267 _TMarksIt mIt( marks, neighRegion );
268 for( mIt.GoToBegin( ); !mIt.IsAtEnd( ); ++mIt )
270 TIndex w = mIt.GetIndex( );
271 typename _TImage::PointType p;
272 marks->TransformIndexToPhysicalPoint( w, p );
278 #endif // __fpa__Image__SkeletonFilter__hxx__