8 #include <itkImageToVTKImageFilter.h>
10 #include <itkImageFileReader.h>
11 #include <itkImageFileWriter.h>
13 #include <fpa/Image/Functors/ImageCostFunction.h>
14 #include <fpa/Image/DijkstraWithEndPointDetection.h>
15 #include <fpa/VTK/ImageMPR.h>
16 #include <fpa/VTK/Image3DObserver.h>
18 #include <fpa/IO/MinimumSpanningTreeWriter.h>
19 #include <fpa/IO/UniqueValuesContainerWriter.h>
20 #include <fpa/IO/MatrixValuesContainerWriter.h>
22 #include <vtkCellArray.h>
23 #include <vtkFloatArray.h>
24 #include <vtkImageMarchingCubes.h>
25 #include <vtkPoints.h>
26 #include <vtkPolyData.h>
27 #include <vtkSmartPointer.h>
29 // -------------------------------------------------------------------------
30 const unsigned int Dim = 3;
31 typedef unsigned char TPixel;
32 typedef float TScalar;
34 typedef itk::Image< TPixel, Dim > TImage;
35 typedef itk::Image< TScalar, Dim > TScalarImage;
36 typedef itk::ImageToVTKImageFilter< TImage > TVTKInputImage;
38 // -------------------------------------------------------------------------
40 void ReadImage( typename I::Pointer& image, const std::string& filename );
43 void SaveImage( const I* image, const std::string& filename );
45 // -------------------------------------------------------------------------
47 class SkeletonCostFunction
48 : public fpa::Image::Functors::ImageCostFunction< typename F::TInputImage, typename F::TResult >
51 typedef fpa::Image::Functors::ImageCostFunction< typename F::TInputImage, typename F::TResult > Superclass;
52 typedef SkeletonCostFunction Self;
53 typedef itk::SmartPointer< Self > Pointer;
54 typedef itk::SmartPointer< const Self > ConstPointer;
56 typedef typename Superclass::TInputImage TInputImage;
57 typedef typename Superclass::TResult TResult;
58 typedef typename Superclass::TIndex TIndex;
62 itkTypeMacro( SkeletonCostFunction, fpa_Image_Functors_ImageCostFunction );
65 virtual void SetInputImage( const TInputImage* img )
67 this->Superclass::SetInputImage( img );
69 typename TInputImage::SpacingType spac = img->GetSpacing( );
70 typename TInputImage::SpacingType::ValueType min_spac = spac[ 0 ];
71 for( unsigned int d = 1; d < TInputImage::ImageDimension; ++d )
72 min_spac = ( spac[ d ] < min_spac )? spac[ d ]: min_spac;
73 this->m_Distance = TResult( min_spac );
76 virtual TResult Evaluate( const TIndex& v, const TIndex& p ) const
78 TResult res = this->Superclass::Evaluate( v, p );
79 if( res > TResult( 0 ) )
80 return( this->m_Distance );
82 return( TResult( -1 ) );
86 SkeletonCostFunction( )
89 virtual ~SkeletonCostFunction( )
93 // Purposely not implemented
94 SkeletonCostFunction( const Self& );
95 void operator=( const Self& );
101 // -------------------------------------------------------------------------
102 int main( int argc, char* argv[] )
107 << "Usage: " << argv[ 0 ] << std::endl
108 << " input_image" << std::endl
109 << " seed_x seed_y seed_z" << std::endl
110 << " output_costmap" << std::endl
111 << " output_labels" << std::endl
112 << " output_minimum_spanning_tree" << std::endl
113 << " output_endpoints" << std::endl
114 << " output_bifurcations" << std::endl
115 << " output_branches" << std::endl
120 std::string input_image_fn = argv[ 1 ];
121 std::string output_costmap_fn = argv[ 5 ];
122 std::string output_labels_fn = argv[ 6 ];
123 std::string mst_output_fn = argv[ 7 ];
124 std::string endpoints_output_fn = argv[ 8 ];
125 std::string bifurcations_output_fn = argv[ 9 ];
126 std::string branches_output_fn = argv[ 10 ];
129 TImage::PointType pnt;
130 pnt[ 0 ] = TImage::PointType::ValueType( std::atof( argv[ 2 ] ) );
131 pnt[ 1 ] = TImage::PointType::ValueType( std::atof( argv[ 3 ] ) );
132 pnt[ 2 ] = TImage::PointType::ValueType( std::atof( argv[ 4 ] ) );
135 TImage::Pointer input_image;
138 ReadImage< TImage >( input_image, input_image_fn );
140 catch( itk::ExceptionObject& err )
143 << "Error caught while reading \""
144 << input_image_fn << "\": " << err
150 TVTKInputImage::Pointer vtk_input_image = TVTKInputImage::New( );
151 vtk_input_image->SetInput( input_image );
152 vtk_input_image->Update( );
154 // Show input image and let some interaction
155 fpa::VTK::ImageMPR view;
156 view.SetBackground( 0.3, 0.2, 0.8 );
157 view.SetSize( 500, 500 );
158 view.SetImage( vtk_input_image->GetOutput( ) );
160 vtkSmartPointer< vtkImageMarchingCubes > mc =
161 vtkSmartPointer< vtkImageMarchingCubes >::New( );
162 mc->SetInputData( vtk_input_image->GetOutput( ) );
163 mc->SetValue( 0, 1e-1 );
165 view.AddPolyData( mc->GetOutput( ), 1, 1, 1, 0.4 );
167 // Allow some interaction and wait for, at least, one seed
172 TImage::IndexType seed;
173 input_image->TransformPhysicalPointToIndex( pnt, seed );
175 // Prepare Dijkstra filter
176 typedef fpa::Image::DijkstraWithEndPointDetection< TImage, TScalarImage > TFilter;
177 typedef SkeletonCostFunction< TFilter > TFunction;
179 TFunction::Pointer function = TFunction::New( );
181 TFilter::Pointer filter = TFilter::New( );
182 filter->SetInput( input_image );
183 filter->SetCostFunction( function );
184 filter->SetNeighborhoodOrder( 2 );
185 filter->SetSafetyNeighborhoodSize( 0 );
186 filter->StopAtOneFrontOff( );
187 filter->CorrectSeedsOff( );
188 filter->CorrectEndPointsOff( );
189 filter->AddSeed( seed, TScalar( 0 ) );
191 // Prepare graphical debugger
192 typedef fpa::VTK::Image3DObserver< TFilter, vtkRenderWindow > TDebugger;
193 TDebugger::Pointer debugger = TDebugger::New( );
194 debugger->SetRenderWindow( view.GetWindow( ) );
195 debugger->SetRenderPercentage( 0.0000001 );
196 filter->AddObserver( itk::AnyEvent( ), debugger );
197 filter->ThrowEventsOn( );
200 std::time_t start, end;
205 << "Extraction time = "
206 << std::difftime( end, start )
207 << " s." << std::endl;
210 const TFilter::TOutputImage* accumulated_costs = filter->GetOutput( );
211 const TFilter::TLabelImage* labeled_image = filter->GetLabelImage( );
212 const TFilter::TMinimumSpanningTree* mst = filter->GetMinimumSpanningTree( );
213 const TFilter::TUniqueVertices* endpoints = filter->GetEndPoints( );
214 const TFilter::TUniqueVertices* bifurcations = filter->GetBifurcations( );
215 const TFilter::TBranches* branches = filter->GetBranches( );
216 unsigned long nBranches = filter->GetNumberOfBranches( );
219 SaveImage( accumulated_costs, output_costmap_fn );
220 SaveImage( labeled_image, output_labels_fn );
222 fpa::IO::MinimumSpanningTreeWriter< TFilter::TMinimumSpanningTree >::Pointer
224 fpa::IO::MinimumSpanningTreeWriter< TFilter::TMinimumSpanningTree >::New( );
225 mst_writer->SetInput( mst );
226 mst_writer->SetFileName( mst_output_fn );
227 mst_writer->Update( );
229 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::Pointer
231 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::New( );
232 endpoints_writer->SetInput( endpoints );
233 endpoints_writer->SetFileName( endpoints_output_fn );
234 endpoints_writer->Update( );
236 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::Pointer
237 bifurcations_writer =
238 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::New( );
239 bifurcations_writer->SetInput( bifurcations );
240 bifurcations_writer->SetFileName( bifurcations_output_fn );
241 bifurcations_writer->Update( );
243 fpa::IO::MatrixValuesContainerWriter< TFilter::TBranches >::Pointer
245 fpa::IO::MatrixValuesContainerWriter< TFilter::TBranches >::New( );
246 branches_writer->SetInput( branches );
247 branches_writer->SetFileName( branches_output_fn );
248 branches_writer->Update( );
251 vtkSmartPointer< vtkPoints > endpoints_points =
252 vtkSmartPointer< vtkPoints >::New( );
253 vtkSmartPointer< vtkCellArray > endpoints_cells =
254 vtkSmartPointer< vtkCellArray >::New( );
256 TFilter::TUniqueVertices::ConstIterator epIt = endpoints->Begin( );
257 epIt != endpoints->End( );
261 TImage::PointType pnt;
262 input_image->TransformIndexToPhysicalPoint( *epIt, pnt );
263 endpoints_points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
264 endpoints_cells->InsertNextCell( 1 );
266 InsertCellPoint( endpoints_points->GetNumberOfPoints( ) - 1 );
269 vtkSmartPointer< vtkPolyData > endpoints_polydata =
270 vtkSmartPointer< vtkPolyData >::New( );
271 endpoints_polydata->SetPoints( endpoints_points );
272 endpoints_polydata->SetVerts( endpoints_cells );
273 view.AddPolyData( endpoints_polydata, 0, 0, 1, 1 );
276 vtkSmartPointer< vtkPoints > bifurcations_points =
277 vtkSmartPointer< vtkPoints >::New( );
278 vtkSmartPointer< vtkCellArray > bifurcations_cells =
279 vtkSmartPointer< vtkCellArray >::New( );
281 TFilter::TUniqueVertices::ConstIterator bfIt = bifurcations->Begin( );
282 bfIt != bifurcations->End( );
286 TImage::PointType pnt;
287 input_image->TransformIndexToPhysicalPoint( *bfIt, pnt );
288 bifurcations_points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
289 bifurcations_cells->InsertNextCell( 1 );
291 InsertCellPoint( bifurcations_points->GetNumberOfPoints( ) - 1 );
294 vtkSmartPointer< vtkPolyData > bifurcations_polydata =
295 vtkSmartPointer< vtkPolyData >::New( );
296 bifurcations_polydata->SetPoints( bifurcations_points );
297 bifurcations_polydata->SetVerts( bifurcations_cells );
298 view.AddPolyData( bifurcations_polydata, 0, 1, 0, 1 );
300 // Show branches (simple and detailed)
301 vtkSmartPointer< vtkPoints > simple_branches_points =
302 vtkSmartPointer< vtkPoints >::New( );
303 vtkSmartPointer< vtkCellArray > simple_branches_cells =
304 vtkSmartPointer< vtkCellArray >::New( );
306 vtkSmartPointer< vtkPoints > detailed_branches_points =
307 vtkSmartPointer< vtkPoints >::New( );
308 vtkSmartPointer< vtkCellArray > detailed_branches_cells =
309 vtkSmartPointer< vtkCellArray >::New( );
310 vtkSmartPointer< vtkFloatArray > detailed_branches_scalars =
311 vtkSmartPointer< vtkFloatArray >::New( );
313 TFilter::TBranches::ConstIterator brIt = branches->Begin( );
314 for( ; brIt != branches->End( ); ++brIt )
316 // Branch's first point
317 TImage::PointType first_point;
318 input_image->TransformIndexToPhysicalPoint( brIt->first, first_point );
319 unsigned long first_id = simple_branches_points->GetNumberOfPoints( );
320 simple_branches_points->InsertNextPoint(
321 first_point[ 0 ], first_point[ 1 ], first_point[ 2 ]
324 TFilter::TBranches::ConstRowIterator brRowIt = branches->Begin( brIt );
325 for( ; brRowIt != branches->End( brIt ); ++brRowIt )
327 // Branch's second point
328 TImage::PointType second_point;
330 TransformIndexToPhysicalPoint( brRowIt->first, second_point );
331 unsigned long second_id = simple_branches_points->GetNumberOfPoints( );
332 simple_branches_points->InsertNextPoint(
333 second_point[ 0 ], second_point[ 1 ], second_point[ 2 ]
335 simple_branches_cells->InsertNextCell( 2 );
336 simple_branches_cells->InsertCellPoint( first_id );
337 simple_branches_cells->InsertCellPoint( second_id );
340 double pathId = double( brRowIt->second - 1 ) / double( nBranches - 1 );
341 TFilter::TVertices path;
342 mst->GetPath( path, brIt->first, brRowIt->first );
343 TFilter::TVertices::const_iterator pIt = path.begin( );
344 for( ; pIt != path.end( ); ++pIt )
346 TImage::PointType path_point;
347 input_image->TransformIndexToPhysicalPoint( *pIt, path_point );
348 detailed_branches_points->InsertNextPoint(
349 path_point[ 0 ], path_point[ 1 ], path_point[ 2 ]
351 detailed_branches_scalars->InsertNextTuple1( pathId );
352 if( pIt != path.begin( ) )
354 unsigned long nPoints =
355 detailed_branches_points->GetNumberOfPoints( );
356 detailed_branches_cells->InsertNextCell( 2 );
357 detailed_branches_cells->InsertCellPoint( nPoints - 2 );
358 detailed_branches_cells->InsertCellPoint( nPoints - 1 );
367 vtkSmartPointer< vtkPolyData > simple_branches_polydata =
368 vtkSmartPointer< vtkPolyData >::New( );
369 simple_branches_polydata->SetPoints( simple_branches_points );
370 simple_branches_polydata->SetLines( simple_branches_cells );
371 view.AddPolyData( simple_branches_polydata, 1, 0, 1, 1 );
373 vtkSmartPointer< vtkPolyData > detailed_branches_polydata =
374 vtkSmartPointer< vtkPolyData >::New( );
375 detailed_branches_polydata->SetPoints( detailed_branches_points );
376 detailed_branches_polydata->SetLines( detailed_branches_cells );
377 detailed_branches_polydata->
378 GetPointData( )->SetScalars( detailed_branches_scalars );
379 view.AddPolyData( detailed_branches_polydata, 1 );
381 // Let some more interaction
388 // -------------------------------------------------------------------------
390 void ReadImage( typename I::Pointer& image, const std::string& filename )
392 typename itk::ImageFileReader< I >::Pointer reader =
393 itk::ImageFileReader< I >::New( );
394 reader->SetFileName( filename );
396 image = reader->GetOutput( );
397 image->DisconnectPipeline( );
400 // -------------------------------------------------------------------------
402 void SaveImage( const I* image, const std::string& filename )
404 typename itk::ImageFileWriter< I >::Pointer writer =
405 itk::ImageFileWriter< I >::New( );
406 writer->SetInput( image );
407 writer->SetFileName( filename );
412 catch( itk::ExceptionObject& err )
415 << "Error saving \"" << filename << "\": " << err