8 #include <itkImageToVTKImageFilter.h>
10 #include <itkImageFileReader.h>
11 #include <itkMinimumMaximumImageCalculator.h>
12 #include <itkShiftScaleImageFilter.h>
14 #include <itkSignedMaurerDistanceMapImageFilter.h>
16 #include <itkImageFileWriter.h>
18 #include <fpa/Image/DijkstraWithEndPointDetection.h>
19 #include <fpa/Base/Functors/InvertCostFunction.h>
20 #include <fpa/VTK/ImageMPR.h>
21 #include <fpa/VTK/Image3DObserver.h>
23 #include <fpa/IO/MinimumSpanningTreeWriter.h>
24 #include <fpa/IO/UniqueValuesContainerWriter.h>
25 #include <fpa/IO/MatrixValuesContainerWriter.h>
27 #include <vtkCellArray.h>
28 #include <vtkFloatArray.h>
29 #include <vtkImageMarchingCubes.h>
30 #include <vtkPoints.h>
31 #include <vtkPolyData.h>
32 #include <vtkSmartPointer.h>
34 // -------------------------------------------------------------------------
35 const unsigned int Dim = 3;
36 typedef unsigned char TPixel;
37 typedef float TScalar;
39 typedef itk::Image< TPixel, Dim > TImage;
40 typedef itk::Image< TScalar, Dim > TScalarImage;
41 typedef itk::ImageToVTKImageFilter< TImage > TVTKInputImage;
43 // -------------------------------------------------------------------------
45 void ReadImage( typename I::Pointer& image, const std::string& filename );
48 void SaveImage( const I* image, const std::string& filename );
50 template< class I, class O >
52 const typename I::Pointer& input, typename O::Pointer& output
55 // -------------------------------------------------------------------------
56 int main( int argc, char* argv[] )
61 << "Usage: " << argv[ 0 ] << std::endl
62 << " input_image" << std::endl
63 << " output_distancemap" << std::endl
64 << " output_costmap" << std::endl
65 << " output_labels" << std::endl
66 << " output_minimum_spanning_tree" << std::endl
67 << " output_endpoints" << std::endl
68 << " output_bifurcations" << std::endl
69 << " output_branches" << std::endl
74 std::string input_image_fn = argv[ 1 ];
75 std::string distancemap_fn = argv[ 2 ];
76 std::string output_costmap_fn = argv[ 3 ];
77 std::string output_labels_fn = argv[ 4 ];
78 std::string mst_output_fn = argv[ 5 ];
79 std::string endpoints_output_fn = argv[ 6 ];
80 std::string bifurcations_output_fn = argv[ 7 ];
81 std::string branches_output_fn = argv[ 8 ];
84 TImage::Pointer input_image;
87 ReadImage< TImage >( input_image, input_image_fn );
89 catch( itk::ExceptionObject& err )
92 << "Error caught while reading \""
93 << input_image_fn << "\": " << err
99 TVTKInputImage::Pointer vtk_input_image = TVTKInputImage::New( );
100 vtk_input_image->SetInput( input_image );
101 vtk_input_image->Update( );
103 // Show input image and let some interaction
104 fpa::VTK::ImageMPR view;
105 view.SetBackground( 0.3, 0.2, 0.8 );
106 view.SetSize( 800, 800 );
107 view.SetImage( vtk_input_image->GetOutput( ) );
109 vtkSmartPointer< vtkImageMarchingCubes > mc =
110 vtkSmartPointer< vtkImageMarchingCubes >::New( );
111 mc->SetInputData( vtk_input_image->GetOutput( ) );
112 mc->SetValue( 0, 1e-1 );
114 view.AddPolyData( mc->GetOutput( ), 1, 1, 1, 0.4 );
116 // Allow some interaction and wait for, at least, one seed
118 while( view.GetNumberOfSeeds( ) == 0 )
123 view.GetSeed( 0, p );
124 TImage::PointType pnt;
125 TImage::IndexType seed;
126 pnt[ 0 ] = TImage::PointType::ValueType( p[ 0 ] );
127 pnt[ 1 ] = TImage::PointType::ValueType( p[ 1 ] );
128 pnt[ 2 ] = TImage::PointType::ValueType( p[ 2 ] );
129 input_image->TransformPhysicalPointToIndex( pnt, seed );
131 // Compute squared distance map
132 TScalarImage::Pointer dmap;
133 DistanceMap< TImage, TScalarImage >( input_image, dmap );
135 // Prepare cost conversion function
136 typedef fpa::Base::Functors::InvertCostFunction< TScalar > TFunction;
137 TFunction::Pointer function = TFunction::New( );
139 // Prepare Dijkstra filter
140 typedef fpa::Image::DijkstraWithEndPointDetection< TScalarImage, TScalarImage > TFilter;
141 TFilter::Pointer filter = TFilter::New( );
142 filter->SetInput( dmap );
143 filter->SetConversionFunction( function );
144 filter->SetNeighborhoodOrder( 2 );
145 filter->StopAtOneFrontOff( );
146 filter->AddSeed( seed, TScalar( 0 ) );
148 // Prepare graphical debugger
149 typedef fpa::VTK::Image3DObserver< TFilter, vtkRenderWindow > TDebugger;
150 TDebugger::Pointer debugger = TDebugger::New( );
151 debugger->SetRenderWindow( view.GetWindow( ) );
152 debugger->SetRenderPercentage( 0.0001 );
153 filter->AddObserver( itk::AnyEvent( ), debugger );
154 filter->ThrowEventsOn( );
157 std::time_t start, end;
162 << "Extraction time = "
163 << std::difftime( end, start )
164 << " s." << std::endl;
167 const TFilter::TOutputImage* accumulated_costs = filter->GetOutput( );
168 const TFilter::TLabelImage* labeled_image = filter->GetLabelImage( );
169 const TFilter::TMinimumSpanningTree* mst = filter->GetMinimumSpanningTree( );
170 const TFilter::TUniqueVertices* endpoints = filter->GetEndPoints( );
171 const TFilter::TUniqueVertices* bifurcations = filter->GetBifurcations( );
172 const TFilter::TBranches* branches = filter->GetBranches( );
173 unsigned long nBranches = filter->GetNumberOfBranches( );
176 SaveImage( dmap.GetPointer( ), distancemap_fn );
177 SaveImage( accumulated_costs, output_costmap_fn );
178 SaveImage( labeled_image, output_labels_fn );
180 fpa::IO::MinimumSpanningTreeWriter< TFilter::TMinimumSpanningTree >::Pointer
182 fpa::IO::MinimumSpanningTreeWriter< TFilter::TMinimumSpanningTree >::New( );
183 mst_writer->SetInput( mst );
184 mst_writer->SetFileName( mst_output_fn );
185 mst_writer->Update( );
187 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::Pointer
189 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::New( );
190 endpoints_writer->SetInput( endpoints );
191 endpoints_writer->SetFileName( endpoints_output_fn );
192 endpoints_writer->Update( );
194 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::Pointer
195 bifurcations_writer =
196 fpa::IO::UniqueValuesContainerWriter< TFilter::TUniqueVertices >::New( );
197 bifurcations_writer->SetInput( bifurcations );
198 bifurcations_writer->SetFileName( bifurcations_output_fn );
199 bifurcations_writer->Update( );
201 fpa::IO::MatrixValuesContainerWriter< TFilter::TBranches >::Pointer
203 fpa::IO::MatrixValuesContainerWriter< TFilter::TBranches >::New( );
204 branches_writer->SetInput( branches );
205 branches_writer->SetFileName( branches_output_fn );
206 branches_writer->Update( );
209 vtkSmartPointer< vtkPoints > endpoints_points =
210 vtkSmartPointer< vtkPoints >::New( );
211 vtkSmartPointer< vtkCellArray > endpoints_cells =
212 vtkSmartPointer< vtkCellArray >::New( );
214 TFilter::TUniqueVertices::ConstIterator epIt = endpoints->Begin( );
215 epIt != endpoints->End( );
219 TImage::PointType pnt;
220 input_image->TransformIndexToPhysicalPoint( *epIt, pnt );
221 endpoints_points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
222 endpoints_cells->InsertNextCell( 1 );
224 InsertCellPoint( endpoints_points->GetNumberOfPoints( ) - 1 );
227 vtkSmartPointer< vtkPolyData > endpoints_polydata =
228 vtkSmartPointer< vtkPolyData >::New( );
229 endpoints_polydata->SetPoints( endpoints_points );
230 endpoints_polydata->SetVerts( endpoints_cells );
231 view.AddPolyData( endpoints_polydata, 0, 0, 1, 1 );
234 vtkSmartPointer< vtkPoints > bifurcations_points =
235 vtkSmartPointer< vtkPoints >::New( );
236 vtkSmartPointer< vtkCellArray > bifurcations_cells =
237 vtkSmartPointer< vtkCellArray >::New( );
239 TFilter::TUniqueVertices::ConstIterator bfIt = bifurcations->Begin( );
240 bfIt != bifurcations->End( );
244 TImage::PointType pnt;
245 input_image->TransformIndexToPhysicalPoint( *bfIt, pnt );
246 bifurcations_points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
247 bifurcations_cells->InsertNextCell( 1 );
249 InsertCellPoint( bifurcations_points->GetNumberOfPoints( ) - 1 );
252 vtkSmartPointer< vtkPolyData > bifurcations_polydata =
253 vtkSmartPointer< vtkPolyData >::New( );
254 bifurcations_polydata->SetPoints( bifurcations_points );
255 bifurcations_polydata->SetVerts( bifurcations_cells );
256 view.AddPolyData( bifurcations_polydata, 0, 1, 0, 1 );
258 // Show branches (simple and detailed)
259 vtkSmartPointer< vtkPoints > simple_branches_points =
260 vtkSmartPointer< vtkPoints >::New( );
261 vtkSmartPointer< vtkCellArray > simple_branches_cells =
262 vtkSmartPointer< vtkCellArray >::New( );
264 vtkSmartPointer< vtkPoints > detailed_branches_points =
265 vtkSmartPointer< vtkPoints >::New( );
266 vtkSmartPointer< vtkCellArray > detailed_branches_cells =
267 vtkSmartPointer< vtkCellArray >::New( );
268 vtkSmartPointer< vtkFloatArray > detailed_branches_scalars =
269 vtkSmartPointer< vtkFloatArray >::New( );
271 TFilter::TBranches::ConstIterator brIt = branches->Begin( );
272 for( ; brIt != branches->End( ); ++brIt )
274 // Branch's first point
275 TImage::PointType first_point;
276 input_image->TransformIndexToPhysicalPoint( brIt->first, first_point );
277 unsigned long first_id = simple_branches_points->GetNumberOfPoints( );
278 simple_branches_points->InsertNextPoint(
279 first_point[ 0 ], first_point[ 1 ], first_point[ 2 ]
282 TFilter::TBranches::ConstRowIterator brRowIt = branches->Begin( brIt );
283 for( ; brRowIt != branches->End( brIt ); ++brRowIt )
285 // Branch's second point
286 TImage::PointType second_point;
288 TransformIndexToPhysicalPoint( brRowIt->first, second_point );
289 unsigned long second_id = simple_branches_points->GetNumberOfPoints( );
290 simple_branches_points->InsertNextPoint(
291 second_point[ 0 ], second_point[ 1 ], second_point[ 2 ]
293 simple_branches_cells->InsertNextCell( 2 );
294 simple_branches_cells->InsertCellPoint( first_id );
295 simple_branches_cells->InsertCellPoint( second_id );
298 double pathId = double( brRowIt->second - 1 ) / double( nBranches - 1 );
299 TFilter::TVertices path;
300 mst->GetPath( path, brIt->first, brRowIt->first );
301 TFilter::TVertices::const_iterator pIt = path.begin( );
302 for( ; pIt != path.end( ); ++pIt )
304 TImage::PointType path_point;
305 input_image->TransformIndexToPhysicalPoint( *pIt, path_point );
306 detailed_branches_points->InsertNextPoint(
307 path_point[ 0 ], path_point[ 1 ], path_point[ 2 ]
309 detailed_branches_scalars->InsertNextTuple1( pathId );
310 if( pIt != path.begin( ) )
312 unsigned long nPoints =
313 detailed_branches_points->GetNumberOfPoints( );
314 detailed_branches_cells->InsertNextCell( 2 );
315 detailed_branches_cells->InsertCellPoint( nPoints - 2 );
316 detailed_branches_cells->InsertCellPoint( nPoints - 1 );
325 vtkSmartPointer< vtkPolyData > simple_branches_polydata =
326 vtkSmartPointer< vtkPolyData >::New( );
327 simple_branches_polydata->SetPoints( simple_branches_points );
328 simple_branches_polydata->SetLines( simple_branches_cells );
329 view.AddPolyData( simple_branches_polydata, 1, 0, 1, 1 );
331 vtkSmartPointer< vtkPolyData > detailed_branches_polydata =
332 vtkSmartPointer< vtkPolyData >::New( );
333 detailed_branches_polydata->SetPoints( detailed_branches_points );
334 detailed_branches_polydata->SetLines( detailed_branches_cells );
335 detailed_branches_polydata->
336 GetPointData( )->SetScalars( detailed_branches_scalars );
337 view.AddPolyData( detailed_branches_polydata, 1 );
339 // Let some more interaction
346 // -------------------------------------------------------------------------
348 void ReadImage( typename I::Pointer& image, const std::string& filename )
350 typename itk::ImageFileReader< I >::Pointer reader =
351 itk::ImageFileReader< I >::New( );
352 reader->SetFileName( filename );
355 typename itk::MinimumMaximumImageCalculator< I >::Pointer minmax =
356 itk::MinimumMaximumImageCalculator< I >::New( );
357 minmax->SetImage( reader->GetOutput( ) );
359 double vmin = double( minmax->GetMinimum( ) );
360 double vmax = double( minmax->GetMaximum( ) );
362 typename itk::ShiftScaleImageFilter< I, I >::Pointer shift =
363 itk::ShiftScaleImageFilter< I, I >::New( );
364 shift->SetInput( reader->GetOutput( ) );
365 shift->SetScale( vmax - vmin );
366 shift->SetShift( vmin / ( vmax - vmin ) );
369 image = shift->GetOutput( );
370 image->DisconnectPipeline( );
373 // -------------------------------------------------------------------------
375 void SaveImage( const I* image, const std::string& filename )
377 typename itk::ImageFileWriter< I >::Pointer writer =
378 itk::ImageFileWriter< I >::New( );
379 writer->SetInput( image );
380 writer->SetFileName( filename );
385 catch( itk::ExceptionObject& err )
388 << "Error saving \"" << filename << "\": " << err
394 // -------------------------------------------------------------------------
395 template< class I, class O >
397 const typename I::Pointer& input, typename O::Pointer& output
400 typename itk::SignedMaurerDistanceMapImageFilter< I, O >::Pointer dmap =
401 itk::SignedMaurerDistanceMapImageFilter< I, O >::New( );
402 dmap->SetInput( input );
403 dmap->SetBackgroundValue( ( typename I::PixelType )( 0 ) );
404 dmap->InsideIsPositiveOn( );
405 dmap->SquaredDistanceOn( );
406 dmap->UseImageSpacingOn( );
408 std::time_t start, end;
413 << "Distance map time = "
414 << std::difftime( end, start )
415 << " s." << std::endl;
417 output = dmap->GetOutput( );
418 output->DisconnectPipeline( );