this->SetVertex( b, b );
this->AddEdge( a, b, path );
this->AddEdge( b, a, path );
- // TODO: this->Modified( );
+ this->Modified( );
}
// -------------------------------------------------------------------------
mst, dijkstra->GetSkeletonQueue( )
);
- // Create branches
- TSkeleton* sk = this->GetOutput( );
+ // Compute symbolic branches
+ typedef std::map< TIndex, TIndex, typename TIndex::LexicographicCompare > _TTags;
+ _TTags tags, branches;
typename std::vector< TIndex >::const_iterator eIt = end_points.begin( );
- std::map< TIndex, unsigned long, typename TIndex::LexicographicCompare > tags;
- unsigned long t = 1;
for( ; eIt != end_points.end( ); ++eIt )
{
// Tag path
TIndex it = *eIt;
TIndex p = mst->GetParent( it );
- while( it != p )
+ typename _TTags::iterator bIt = tags.end( );
+ while( it != p && bIt == tags.end( ) )
{
- tags[ it ] = t;
+ typename _TTags::iterator tIt = tags.find( it );
+ if( tIt != tags.end( ) )
+ {
+ // Ok, a bifurcation point has been found
+ // branch1: tIt->second <-> it (ok)
+ branches[ tIt->second ] = it;
+
+ // branch2: *eit <-> it (ok)
+ branches[ *eIt ] = it;
+
+ // branch3: it <-> until next bifurcation
+ bIt = tIt;
+ }
+ else
+ tags[ it ] = *eIt;
it = p;
p = mst->GetParent( it );
} // elihw
- // TODO: More on it
+ if( bIt != tags.end( ) )
+ {
+ TIndex pTag = bIt->second;
+ TIndex nTag = bIt->first;
+ it = bIt->first;
+ p = it;
+ while( tags[ it ] == pTag )
+ {
+ tags[ it ] = nTag;
+ p = it;
+ it = mst->GetParent( it );
+
+ } // elihw
+ branches[ bIt->first ] = p;
+ }
+ else
+ {
+ tags[ it ] = *eIt;
+ branches[ *eIt ] = it;
+
+ } // fi
+
+ } // rof
+
+ // Fill full branches
+ typedef typename _TMST::TVertices _TVertices;
+ typedef typename TSkeleton::TPath _TPath;
+
+ TSkeleton* sk = this->GetOutput( );
+ typename _TTags::const_iterator bIt = branches.begin( );
+ for( ; bIt != branches.end( ); ++bIt )
+ {
+ _TVertices v = mst->GetPath( bIt->first, bIt->second );
+ typename _TPath::Pointer path = _TPath::New( );
+ path->SetReferenceImage( this->GetInput( ) );
+ typename _TVertices::const_reverse_iterator vIt = v.rbegin( );
+ for( ; vIt != v.rend( ); ++vIt )
+ path->AddVertex( *vIt );
+ sk->AddBranch( path );
} // rof
}
} // rof
}
-
-
-/* TODO
- this->m_DistanceMap = TDistanceMap::New( );
- this->m_DistanceMap->InsideIsPositiveOn( );
- this->m_DistanceMap->SquaredDistanceOff( );
- this->m_DistanceMap->UseImageSpacingOn( );
-
- template< class _TImage, class _TScalar >
- void fpa::Image::SkeletonFilter< _TImage, _TScalar >::
- _Skeleton( const std::vector< TVertex >& end_points, _TAdjacencies& A )
- {
- typedef typename TSkeleton::TPath _TPath;
- typedef itk::Image< unsigned long, TImage::ImageDimension > _TTagsImage;
-
- TMST* mst = this->GetMinimumSpanningTree( );
- TSkeleton* skeleton = this->GetSkeleton( );
-
- // Tag branches
- typename _TTagsImage::Pointer tags = _TTagsImage::New( );
- tags->SetLargestPossibleRegion( mst->GetLargestPossibleRegion( ) );
- tags->SetRequestedRegion( mst->GetRequestedRegion( ) );
- tags->SetBufferedRegion( mst->GetBufferedRegion( ) );
- tags->Allocate( );
- tags->FillBuffer( 0 );
- typename std::vector< TVertex >::const_iterator eIt = end_points.begin( );
- for( ; eIt != end_points.end( ); ++eIt )
- {
- TVertex it = *eIt;
- TVertex p = mst->GetParent( it );
- while( it != p )
- {
- tags->SetPixel( it, tags->GetPixel( it ) + 1 );
- it = p;
- p = mst->GetParent( it );
-
- } // elihw
- tags->SetPixel( it, tags->GetPixel( it ) + 1 );
-
- } // rof
-
- // Build paths (branches)
- eIt = end_points.begin( );
- for( ; eIt != end_points.end( ); ++eIt )
- {
- TVertex it = *eIt;
- TVertex p = mst->GetParent( it );
- TVertex sIdx = it;
- typename _TPath::Pointer path = _TPath::New( );
- path->SetReferenceImage( mst );
- while( it != p )
- {
- if( tags->GetPixel( sIdx ) != tags->GetPixel( it ) )
- {
- // Ok, a new branch has been added
- path->AddVertex( it );
- skeleton->AddBranch( path );
-
- // Update a new starting index
- path = _TPath::New( );
- path->SetReferenceImage( mst );
- sIdx = it;
- }
- else
- path->AddVertex( it );
- it = p;
- p = mst->GetParent( it );
-
- } // elihw
-
- // Finally, add last branch
- path->AddVertex( it );
- skeleton->AddBranch( path );
-
- } // rof
- }
-*/
-
#endif // __fpa__Image__SkeletonFilter__hxx__
// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__SkeletonReader__h__
+#define __fpa__Image__SkeletonReader__h__
+
+#include <itkProcessObject.h>
+
+namespace fpa
+{
+ namespace Image
+ {
+ /**
+ */
+ template< class _TSkeleton >
+ class SkeletonReader
+ : public itk::ProcessObject
+ {
+ public:
+ // Basic types
+ typedef SkeletonReader Self;
+ typedef itk::ProcessObject Superclass;
+ typedef itk::SmartPointer< Self > Pointer;
+ typedef itk::SmartPointer< const Self > ConstPointer;
+
+ typedef _TSkeleton TSkeleton;
+
+ public:
+ itkNewMacro( Self );
+ itkTypeMacro( SkeletonReader, itk::ProcessObject );
+
+ itkGetConstMacro( FileName, std::string );
+ itkSetMacro( FileName, std::string );
+
+ public:
+ TSkeleton* GetOutput( );
+ TSkeleton* GetOutput( unsigned int i );
+
+ virtual void GraftOutput( itk::DataObject* out );
+ virtual void GraftOutput(
+ const typename Superclass::DataObjectIdentifierType& key,
+ itk::DataObject* out
+ );
+ virtual void GraftNthOutput( unsigned int i, itk::DataObject* out );
+ virtual itk::DataObject::Pointer MakeOutput(
+ itk::ProcessObject::DataObjectPointerArraySizeType i
+ ) override;
+
+ virtual void Update( ) override
+ { this->GenerateData( ); }
+
+ protected:
+ SkeletonReader( );
+ virtual ~SkeletonReader( );
+
+ virtual void GenerateData( ) override;
+
+ // Do nothing
+ virtual void GenerateOutputInformation( ) override
+ { }
+
+ private:
+ // Purposely not implemented
+ SkeletonReader( const Self& );
+ void operator=( const Self& );
+
+ protected:
+ std::string m_FileName;
+ };
+
+ } // ecapseman
+
+} // ecapseman
+
+#ifndef ITK_MANUAL_INSTANTIATION
+# include <fpa/Image/SkeletonReader.hxx>
+#endif // ITK_MANUAL_INSTANTIATION
+
+#endif // __fpa__Image__SkeletonReader__h__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__SkeletonReader__hxx__
+#define __fpa__Image__SkeletonReader__hxx__
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+_TSkeleton* fpa::Image::SkeletonReader< _TSkeleton >::
+GetOutput( )
+{
+ return(
+ itkDynamicCastInDebugMode< TSkeleton* >( this->GetPrimaryOutput( ) )
+ );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+_TSkeleton* fpa::Image::SkeletonReader< _TSkeleton >::
+GetOutput( unsigned int i )
+{
+ return(
+ itkDynamicCastInDebugMode< TSkeleton* >(
+ this->itk::ProcessObject::GetOutput( i )
+ )
+ );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonReader< _TSkeleton >::
+GraftOutput( itk::DataObject* out )
+{
+ this->GraftNthOutput( 0, out );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonReader< _TSkeleton >::
+GraftOutput(
+ const typename Superclass::DataObjectIdentifierType& key,
+ itk::DataObject* out
+ )
+{
+ if( out == NULL )
+ {
+ itkExceptionMacro(
+ << "Requested to graft output that is a NULL pointer"
+ );
+
+ } // fi
+ itk::DataObject* output = this->itk::ProcessObject::GetOutput( key );
+ output->Graft( out );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonReader< _TSkeleton >::
+GraftNthOutput( unsigned int i, itk::DataObject* out )
+{
+ if( i >= this->GetNumberOfIndexedOutputs( ) )
+ {
+ itkExceptionMacro(
+ << "Requested to graft output " << i
+ << " but this filter only has "
+ << this->GetNumberOfIndexedOutputs( )
+ << " indexed Outputs."
+ );
+
+ } // fi
+ this->GraftOutput( this->MakeNameFromOutputIndex( i ), out );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+itk::DataObject::Pointer
+fpa::Image::SkeletonReader< _TSkeleton >::
+MakeOutput( itk::ProcessObject::DataObjectPointerArraySizeType i )
+{
+ return( TSkeleton::New( ).GetPointer( ) );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+fpa::Image::SkeletonReader< _TSkeleton >::
+SkeletonReader( )
+ : Superclass( )
+{
+ typename TSkeleton::Pointer out =
+ static_cast< TSkeleton* >( this->MakeOutput( 0 ).GetPointer( ) );
+ this->itk::ProcessObject::SetNumberOfRequiredInputs( 0 );
+ this->itk::ProcessObject::SetNumberOfRequiredOutputs( 1 );
+ this->itk::ProcessObject::SetNthOutput( 0, out.GetPointer( ) );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+fpa::Image::SkeletonReader< _TSkeleton >::
+~SkeletonReader( )
+{
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonReader< _TSkeleton >::
+GenerateData( )
+{
+ typedef typename TSkeleton::TPath _TPath;
+ typedef typename _TPath::TIndex _TIndex;
+ typedef typename _TPath::TSpacing _TSpacing;
+ typedef typename _TPath::TPoint _TPoint;
+ typedef typename _TPath::TDirection _TDirection;
+
+ std::string buffer;
+ std::ifstream file_stream( this->m_FileName.c_str( ) );
+ if( !file_stream )
+ {
+ itkExceptionMacro(
+ << "Error reading skeleton from \"" << this->m_FileName << "\""
+ );
+ return;
+
+ } // fi
+ file_stream.seekg( 0, std::ios::end );
+ buffer.reserve( ( unsigned int )( file_stream.tellg( ) ) );
+ file_stream.seekg( 0, std::ios::beg );
+ buffer.assign(
+ ( std::istreambuf_iterator< char >( file_stream ) ),
+ std::istreambuf_iterator< char >( )
+ );
+ file_stream.close( );
+
+ std::istringstream in( buffer );
+ unsigned int dim;
+ in >> dim;
+ if( dim != TSkeleton::Dimension )
+ {
+ itkExceptionMacro(
+ << "Mismatched skeletons dimension: " << dim
+ << " != " << TSkeleton::Dimension
+ );
+ return;
+
+ } // fi
+
+ // Read spatial parameters
+ _TSpacing spa;
+ _TDirection dir;
+ _TPoint ori;
+ for( unsigned int d = 0; d < dim; ++d )
+ in >> spa[ d ];
+ for( unsigned int d = 0; d < dim; ++d )
+ for( unsigned int e = 0; e < dim; ++e )
+ in >> dir[ d ][ e ];
+ for( unsigned int d = 0; d < dim; ++d )
+ in >> ori[ d ];
+
+ // Read end-points, just to ignore
+ unsigned int n;
+ in >> n;
+ for( unsigned int i = 0; i < n; ++i )
+ {
+ _TIndex idx;
+ for( unsigned int d = 0; d < dim; ++d )
+ in >> idx[ d ];
+
+ } // rof
+
+ // Read bifurcations, just to ignore
+ in >> n;
+ for( unsigned int i = 0; i < n; ++i )
+ {
+ _TIndex idx;
+ for( unsigned int d = 0; d < dim; ++d )
+ in >> idx[ d ];
+
+ } // rof
+
+ // Read paths
+ TSkeleton* out = this->GetOutput( );
+ unsigned int nPaths;
+ in >> nPaths;
+ for( unsigned int p = 0; p < nPaths; ++p )
+ {
+ typename _TPath::Pointer path = _TPath::New( );
+ path->SetSpacing( spa );
+ path->SetOrigin( ori );
+ path->SetDirection( dir );
+
+ unsigned long pathSize;
+ in >> pathSize;
+ for( unsigned long id = 0; id < pathSize; ++id )
+ {
+ _TIndex idx;
+ for( unsigned int d = 0; d < dim; ++d )
+ in >> idx[ d ];
+ path->AddVertex( idx );
+
+ } // rof
+ out->AddBranch( path );
+
+ } // rof
+}
+
+#endif // __fpa__Image__SkeletonReader__hxx__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__SkeletonToPolyDataFilter__h__
+#define __fpa__Image__SkeletonToPolyDataFilter__h__
+
+#include <vtkPolyDataAlgorithm.h>
+
+namespace fpa
+{
+ namespace Image
+ {
+ /**
+ */
+ template< class _TSkeleton >
+ class SkeletonToPolyDataFilter
+ : public vtkPolyDataAlgorithm
+ {
+ public:
+ typedef SkeletonToPolyDataFilter Self;
+ typedef _TSkeleton TSkeleton;
+
+ public:
+ vtkTypeMacro( SkeletonToPolyDataFilter, vtkPolyDataAlgorithm );
+
+ public:
+ static Self* New( );
+
+ const TSkeleton* GetInput( ) const;
+ void SetInput( const TSkeleton* sk );
+
+ protected:
+ SkeletonToPolyDataFilter( );
+ virtual ~SkeletonToPolyDataFilter( );
+
+ int RequestData(
+ vtkInformation* information,
+ vtkInformationVector** input,
+ vtkInformationVector* output
+ );
+ int RequestInformation(
+ vtkInformation* information,
+ vtkInformationVector** input,
+ vtkInformationVector* output
+ );
+
+ private:
+ // Purposely not implemented
+ SkeletonToPolyDataFilter( const Self& );
+ void operator=( const Self& );
+
+ protected:
+ const TSkeleton* m_Skeleton;
+ };
+
+ } // ecapseman
+
+} // ecapseman
+
+#ifndef ITK_MANUAL_INSTANTIATION
+# include <fpa/Image/SkeletonToPolyDataFilter.hxx>
+#endif // ITK_MANUAL_INSTANTIATION
+
+#endif // __fpa__Image__SkeletonToPolyDataFilter__h__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__SkeletonToPolyDataFilter__hxx__
+#define __fpa__Image__SkeletonToPolyDataFilter__hxx__
+
+#include <vtkCellArray.h>
+#include <vtkInformation.h>
+#include <vtkInformationVector.h>
+#include <vtkSmartPointer.h>
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+typename fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+Self* fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+New( )
+{
+ return( new Self( ) );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+const typename
+fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+TSkeleton* fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+GetInput( ) const
+{
+ return( this->m_Skeleton );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+SetInput( const TSkeleton* sk )
+{
+ if( this->m_Skeleton != sk )
+ {
+ this->m_Skeleton = sk;
+ this->Modified( );
+
+ } // fi
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+SkeletonToPolyDataFilter( )
+ : vtkPolyDataAlgorithm( ),
+ m_Skeleton( NULL )
+{
+ this->SetNumberOfInputPorts( 0 );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+~SkeletonToPolyDataFilter( )
+{
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+int fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+RequestData(
+ vtkInformation* information,
+ vtkInformationVector** input,
+ vtkInformationVector* output
+ )
+{
+ typedef typename _TSkeleton::TPath _TPath;
+ static const unsigned int dim = _TPath::PathDimension;
+
+ if( this->m_Skeleton == NULL )
+ return( 0 );
+
+ // Get output
+ vtkInformation* info = output->GetInformationObject( 0 );
+ vtkPolyData* out = vtkPolyData::SafeDownCast(
+ info->Get( vtkDataObject::DATA_OBJECT( ) )
+ );
+
+ // Prepare data
+ out->SetPoints( vtkSmartPointer< vtkPoints >::New( ) );
+ out->SetVerts( vtkSmartPointer< vtkCellArray >::New( ) );
+ out->SetLines( vtkSmartPointer< vtkCellArray >::New( ) );
+ out->SetPolys( vtkSmartPointer< vtkCellArray >::New( ) );
+ out->SetStrips( vtkSmartPointer< vtkCellArray >::New( ) );
+ vtkPoints* points = out->GetPoints( );
+ vtkCellArray* lines = out->GetLines( );
+
+ // Assign all data
+ typename TMatrix::const_iterator mIt = this->m_Skeleton->BeginEdgesRows( );
+ for( ; mIt != this->m_Skeleton->EndEdgesRows( ); ++mIt )
+ {
+ // TODO: mIt->first; --> this is the row index. <--
+ typename TMatrixRow::const_iterator rIt = mIt->second.begin( );
+ for( ; rIt != mIt->second.end( ); ++rIt )
+ {
+ // TODO: rIt->first; --> this is the column index.
+ typename TEdges::const_iterator eIt = rIt->second.begin( );
+ for( ; eIt != rIt->second.end( ); ++eIt )
+ {
+ _TPath* path = *eIt;
+ for( unsigned long i = 0; i < path->GetSize( ); ++i )
+ {
+ auto pnt = path->GetPoint( i );
+ if( dim == 1 )
+ points->InsertNextPoint( pnt[ 0 ], 0, 0 );
+ else if( dim == 2 )
+ points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], 0 );
+ else
+ points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
+ if( i > 0 )
+ {
+ lines->InsertNextCell( 2 );
+ lines->InsertCellPoint( points->GetNumberOfPoints( ) - 2 );
+ lines->InsertCellPoint( points->GetNumberOfPoints( ) - 1 );
+
+ } // fi
+
+ } // rof
+
+ } // rof
+
+ } // rof
+
+ } // rof
+ return( 1 );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+int fpa::Image::SkeletonToPolyDataFilter< _TSkeleton >::
+RequestInformation(
+ vtkInformation* information,
+ vtkInformationVector** input,
+ vtkInformationVector* output
+ )
+{
+ return( 1 );
+}
+
+#endif // __fpa__Image__SkeletonToPolyDataFilterFilter__hxx__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__SkeletonWriter__h__
+#define __fpa__Image__SkeletonWriter__h__
+
+#include <itkProcessObject.h>
+
+namespace fpa
+{
+ namespace Image
+ {
+ /**
+ */
+ template< class _TSkeleton >
+ class SkeletonWriter
+ : public itk::ProcessObject
+ {
+ public:
+ // Basic types
+ typedef SkeletonWriter Self;
+ typedef itk::ProcessObject Superclass;
+ typedef itk::SmartPointer< Self > Pointer;
+ typedef itk::SmartPointer< const Self > ConstPointer;
+
+ typedef _TSkeleton TSkeleton;
+ typedef typename TSkeleton::TEdges TEdges;
+ typedef typename TSkeleton::TMatrix TMatrix;
+ typedef typename TSkeleton::TMatrixRow TMatrixRow;
+ typedef typename TSkeleton::TPath TPath;
+ typedef typename TSkeleton::TVertex TVertex;
+
+ public:
+ itkNewMacro( Self );
+ itkTypeMacro( SkeletonWriter, itk::ProcessObject );
+
+ itkGetConstMacro( FileName, std::string );
+ itkSetMacro( FileName, std::string );
+
+ public:
+ const TSkeleton* GetInput( ) const;
+ void SetInput( const TSkeleton* skeleton );
+ virtual void Update( ) override;
+
+ protected:
+ SkeletonWriter( );
+ virtual ~SkeletonWriter( );
+
+ virtual void GenerateData( ) override;
+
+ private:
+ // Purposely not implemented
+ SkeletonWriter( const Self& );
+ void operator=( const Self& );
+
+ protected:
+ std::string m_FileName;
+ };
+
+ } // ecapseman
+
+} // ecapseman
+
+#ifndef ITK_MANUAL_INSTANTIATION
+# include <fpa/Image/SkeletonWriter.hxx>
+#endif // ITK_MANUAL_INSTANTIATION
+
+#endif // __fpa__Image__SkeletonWriter__h__
+
+// eof - $RCSfile$
--- /dev/null
+// =========================================================================
+// @author Leonardo Florez Valencia
+// @email florez-l@javeriana.edu.co
+// =========================================================================
+
+#ifndef __fpa__Image__SkeletonWriter__hxx__
+#define __fpa__Image__SkeletonWriter__hxx__
+
+#include <fstream>
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+const _TSkeleton* fpa::Image::SkeletonWriter< _TSkeleton >::
+GetInput( ) const
+{
+ return(
+ dynamic_cast< const TSkeleton* >(
+ this->itk::ProcessObject::GetInput( 0 )
+ )
+ );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonWriter< _TSkeleton >::
+SetInput( const _TSkeleton* skeleton )
+{
+ this->itk::ProcessObject::SetNthInput(
+ 0, const_cast< TSkeleton* >( skeleton )
+ );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonWriter< _TSkeleton >::
+Update( )
+{
+ TSkeleton* input = const_cast< TSkeleton* >( this->GetInput( ) );
+ if( input != NULL )
+ {
+ input->UpdateOutputInformation( );
+ input->UpdateOutputData( );
+ this->GenerateData( );
+ this->ReleaseInputs( );
+
+ } // fi
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+fpa::Image::SkeletonWriter< _TSkeleton >::
+SkeletonWriter( )
+ : Superclass( ),
+ m_FileName( "" )
+{
+ this->SetNumberOfRequiredInputs( 1 );
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+fpa::Image::SkeletonWriter< _TSkeleton >::
+~SkeletonWriter( )
+{
+}
+
+// -------------------------------------------------------------------------
+template< class _TSkeleton >
+void fpa::Image::SkeletonWriter< _TSkeleton >::
+GenerateData( )
+{
+ const TSkeleton* sk = this->GetInput( );
+ typename TMatrix::const_iterator mIt = sk->BeginEdgesRows( );
+ typename TMatrixRow::const_iterator rIt = mIt->second.begin( );
+ typename TEdges::const_iterator eIt = rIt->second.begin( );
+ const TPath* path = *eIt;
+
+ // Write base information
+ std::stringstream out1, out2;
+ out1 << TSkeleton::Dimension << std::endl;
+ typename TPath::TSpacing spa = path->GetSpacing( );
+ for( unsigned int d = 0; d < TSkeleton::Dimension; ++d )
+ out1 << spa[ d ] << " ";
+ out1 << std::endl;
+ typename TPath::TDirection dir = path->GetDirection( );
+ for( unsigned int d = 0; d < TSkeleton::Dimension; ++d )
+ for( unsigned int e = 0; e < TSkeleton::Dimension; ++e )
+ out1 << dir[ d ][ e ] << " ";
+ out1 << std::endl;
+ typename TPath::TPoint ori = path->GetOrigin( );
+ for( unsigned int d = 0; d < TSkeleton::Dimension; ++d )
+ out1 << ori[ d ] << " ";
+ out1 << std::endl;
+
+ // End points
+ std::vector< TVertex > end_points = sk->GetEndPoints( );
+ out1 << end_points.size( ) << std::endl;
+ typename std::vector< TVertex >::const_iterator epIt = end_points.begin( );
+ for( ; epIt != end_points.end( ); ++epIt )
+ {
+ for( unsigned int d = 0; d < TSkeleton::Dimension; ++d )
+ out1 << ( *epIt )[ d ] << " ";
+ out1 << std::endl;
+
+ } // rof
+
+ // Bifurcations
+ std::vector< TVertex > bifurcations = sk->GetBifurcations( );
+ out1 << bifurcations.size( ) << std::endl;
+ typename std::vector< TVertex >::const_iterator bIt = bifurcations.begin( );
+ for( ; bIt != bifurcations.end( ); ++bIt )
+ {
+ for( unsigned int d = 0; d < TSkeleton::Dimension; ++d )
+ out1 << ( *bIt )[ d ] << " ";
+ out1 << std::endl;
+
+ } // rof
+
+ // Write paths
+ unsigned long pathCount = 0;
+ mIt = sk->BeginEdgesRows( );
+ for( ; mIt != sk->EndEdgesRows( ); ++mIt )
+ {
+ typename TMatrixRow::const_iterator rIt = mIt->second.begin( );
+ for( ; rIt != mIt->second.end( ); ++rIt )
+ {
+ typename TEdges::const_iterator eIt = rIt->second.begin( );
+ for( ; eIt != rIt->second.end( ); ++eIt )
+ {
+ TPath* path = *eIt;
+ pathCount++;
+ unsigned int size = path->GetSize( );
+ out2 << size << std::endl;
+ for( unsigned int i = 0; i < path->GetSize( ); ++i )
+ {
+ TVertex v = path->GetVertex( i );
+ for( unsigned int d = 0; d < TSkeleton::Dimension; ++d )
+ out2 << v[ d ] << " ";
+
+ } // rof
+ out2 << std::endl;
+
+ } // rof
+
+ } // rof
+
+ } // rof
+ out1 << pathCount << std::endl << out2.str( );
+
+ // Real write
+ std::ofstream file_stream( this->m_FileName.c_str( ), std::ofstream::binary );
+ if( !file_stream )
+ itkExceptionMacro(
+ << "Unable to write skeleton to \""
+ << this->m_FileName
+ << "\""
+ );
+ file_stream.write( out1.str( ).c_str( ), out1.str( ).size( ) );
+}
+
+#endif // __fpa__Image__SkeletonWriter__hxx__
+
+// eof - $RCSfile$
#include "BaseFunctions.h"
#include <itkImage.h>
#include <fpa/Image/SkeletonFilter.h>
+#include <fpa/Image/SkeletonWriter.h>
// -------------------------------------------------------------------------
-const unsigned int Dim = 3;
+const unsigned int Dim = 2;
typedef short TPixel;
typedef itk::Image< TPixel, Dim > TInputImage;
else
filter->SeedFromMaximumDistanceOn( );
+ // Configure distance map
+ filter->GetDistanceMap( )->InsideIsPositiveOn( );
+ filter->GetDistanceMap( )->SquaredDistanceOff( );
+ filter->GetDistanceMap( )->UseImageSpacingOn( );
+
// Update
filter->Update( );
// Save results
- /* TODO
- std::string err1 =
- fpa::tests::image::Write( filter->GetOutput( ), output_image_filename );
- std::string err2 =
- fpa::tests::image::Write( filter->GetMarks( ), output_marks_filename );
- if( err1 != "" ) std::cerr << err1 << std::endl;
- if( err2 != "" ) std::cerr << err2 << std::endl;
- */
+ fpa::Image::SkeletonWriter< TFilter::TSkeleton >::Pointer writer =
+ fpa::Image::SkeletonWriter< TFilter::TSkeleton >::New( );
+ writer->SetInput( filter->GetOutput( ) );
+ writer->SetFileName( output_skeleton_filename );
+ try
+ {
+ writer->Update( );
+ }
+ catch( std::exception& err )
+ {
+ std::cerr << "Error caught: " << err.what( ) << std::endl;
+ return( 1 );
+
+ } // yrt
return( 0 );
}