9 #include <itkConstNeighborhoodIterator.h>
10 #include <itkNeighborhoodIterator.h>
11 #include <itkDanielssonDistanceMapImageFilter.h>
13 #include <itkImageFileReader.h>
14 #include <itkImageFileWriter.h>
15 #include <itkImageToVTKImageFilter.h>
17 #include <vtkPoints.h>
18 #include <vtkCellArray.h>
19 #include <vtkPolyData.h>
20 #include <vtkSmartPointer.h>
22 #include <fpa/Base/Functors/InvertCostFunction.h>
23 #include <fpa/Image/Dijkstra.h>
24 #include <fpa/Image/RegionGrowWithMultipleThresholds.h>
25 #include <fpa/VTK/ImageMPR.h>
26 #include <fpa/VTK/Image3DObserver.h>
28 // -------------------------------------------------------------------------
29 const unsigned int Dim = 3;
30 typedef double TPixel;
31 typedef double TScalar;
32 typedef itk::Image< TPixel, Dim > TImage;
33 typedef itk::ImageToVTKImageFilter< TImage > TVTKImage;
35 typedef itk::ImageFileReader< TImage > TImageReader;
36 typedef itk::ImageFileWriter< TImage > TImageWriter;
37 typedef fpa::Image::Dijkstra< TImage, TScalar > TBaseDijkstra;
39 typedef fpa::VTK::ImageMPR TMPR;
40 typedef fpa::VTK::Image3DObserver< TBaseDijkstra, vtkRenderWindow > TDijkstraObs;
42 // -------------------------------------------------------------------------
44 : public TBaseDijkstra
47 typedef TDijkstra Self;
48 typedef TBaseDijkstra Superclass;
49 typedef itk::SmartPointer< Self > Pointer;
50 typedef itk::SmartPointer< const Self > ConstPointer;
52 typedef Superclass::TCost TCost;
53 typedef Superclass::TVertex TVertex;
54 typedef Superclass::InputImageType TImage;
55 typedef std::deque< TVertex > TVertices;
58 typedef std::pair< TCost, TVertex > _TCandidate;
59 typedef std::multimap< TCost, TVertex > _TCandidates;
60 typedef Superclass::_TNode _TNode;
64 itkTypeMacro( TDijkstra, TBaseDijkstra );
73 virtual void _BeforeMainLoop( )
75 const TImage* img = this->GetInput( );
78 TImage::SizeType radius;
80 itk::ConstNeighborhoodIterator< TImage > it(
81 radius, img, img->GetRequestedRegion( )
83 for( unsigned int s = 0; s < this->m_Seeds.size( ); ++s )
85 _TNode seed = this->m_Seeds[ s ];
86 it.SetLocation( seed.Vertex );
88 TImage::SizeType size = it.GetSize( );
90 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
92 TImage::PixelType max_value = img->GetPixel( seed.Vertex );
93 for( unsigned int i = 0; i < nN; ++i )
95 if( it.GetPixel( i ) > max_value )
97 seed.Vertex = it.GetIndex( i );
98 seed.Parent = seed.Vertex;
99 max_value = it.GetPixel( i );
104 this->m_Seeds[ s ] = seed;
108 // End initialization
109 this->Superclass::_BeforeMainLoop( );
110 this->m_Candidates.clear( );
113 virtual void _AfterMainLoop( )
115 typedef unsigned char _TMark;
116 typedef itk::Image< _TMark, TImage::ImageDimension > _TMarkImage;
118 this->Superclass::_AfterMainLoop( );
119 if( this->m_Candidates.size( ) == 0 )
122 const TImage* input = this->GetInput( );
123 TImage::SpacingType spacing = input->GetSpacing( );
125 // Prepare an object to hold marks
126 _TMarkImage::Pointer marks = _TMarkImage::New( );
127 marks->SetLargestPossibleRegion( input->GetLargestPossibleRegion( ) );
128 marks->SetRequestedRegion( input->GetRequestedRegion( ) );
129 marks->SetBufferedRegion( input->GetBufferedRegion( ) );
130 marks->SetOrigin( input->GetOrigin( ) );
131 marks->SetSpacing( spacing );
132 marks->SetDirection( input->GetDirection( ) );
134 marks->FillBuffer( _TMark( 0 ) );
136 // Iterate over the candidates, starting fromt the candidates that
137 // are near thin branches
138 _TCandidates::const_reverse_iterator cIt =
139 this->m_Candidates.rbegin( );
140 for( int leo = 0; leo < 100 && cIt != this->m_Candidates.rend( ); ++cIt )
142 // If pixel hasn't been visited, continue
143 TVertex v = cIt->second;
144 if( marks->GetPixel( v ) != _TMark( 0 ) )
147 // Compute nearest start candidate
148 TImage::SizeType radius;
150 itk::ConstNeighborhoodIterator< TImage > iIt(
151 radius, input, input->GetRequestedRegion( )
153 iIt.SetLocation( v );
155 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
156 nN *= iIt.GetSize( )[ d ];
157 TImage::PixelType min_value = iIt.GetPixel( 0 );
158 TVertex min_vertex = iIt.GetIndex( 0 );
159 if( !( min_value > TImage::PixelType( 0 ) ) )
160 min_value = std::numeric_limits< TImage::PixelType >::max( );
161 for( unsigned int i = 1; i < nN; ++i )
163 TImage::PixelType value = iIt.GetPixel( i );
164 if( !( value > TImage::PixelType( 0 ) ) )
165 value = std::numeric_limits< TImage::PixelType >::max( );
166 if( value < min_value )
169 min_vertex = iIt.GetIndex( i );
175 if( min_value < std::numeric_limits< TImage::PixelType >::max( ) )
177 if( marks->GetPixel( min_vertex ) != _TMark( 0 ) )
180 std::cout << "Leaf: " << leo << " " << min_value << " " << min_vertex << std::endl;
185 double dist = double( 1.5 ) * std::sqrt( double( input->GetPixel( min_vertex ) ) );
186 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
188 ( unsigned long )( dist / spacing[ d ] ) + 1;
189 itk::NeighborhoodIterator< _TMarkImage > mIt(
190 radius, marks, marks->GetRequestedRegion( )
192 mIt.SetLocation( min_vertex );
194 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
195 nN *= mIt.GetSize( )[ d ];
196 for( unsigned int i = 0; i < nN; ++i )
197 if( marks->GetRequestedRegion( ).IsInside( mIt.GetIndex( i ) ) )
199 mIt.SetPixel( i, ( start )? 255: 100 );
204 TImage::SizeType radius;
206 mIt.SetLocation( vIt );
208 TImage::SizeType size = mIt.GetSize( );
210 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
212 for( unsigned int i = 0; i < nN; ++i )
213 if( marks->GetRequestedRegion( ).IsInside( mIt.GetIndex( i ) ) )
214 mIt.SetPixel( i, ( start )? 255: 100 );
218 // Next vertex in current path
219 min_vertex = this->_Parent( min_vertex );
221 } while( min_vertex != this->_Parent( min_vertex ) );
224 marks->SetPixel( v, _TMark( 1 ) );
228 itk::ImageFileWriter< _TMarkImage >::Pointer w =
229 itk::ImageFileWriter< _TMarkImage >::New( );
230 w->SetInput( marks );
231 w->SetFileName( "marks.mhd" );
237 this->m_Axes = vtkSmartPointer< vtkPolyData >::New( );
238 vtkSmartPointer< vtkPoints > points =
239 vtkSmartPointer< vtkPoints >::New( );
240 vtkSmartPointer< vtkCellArray > lines =
241 vtkSmartPointer< vtkCellArray >::New( );
246 std::cout << "Leaf: " << leo << " " << cIt->first << " " << vIt << std::endl;
250 double dist = double( input->GetPixel( vIt ) );
251 TImage::SizeType radius;
252 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
254 ( unsigned long )( dist / spacing[ d ] ) + 1;
255 itk::NeighborhoodIterator< _TMarkImage > mIt(
256 radius, marks, marks->GetRequestedRegion( )
259 mIt.SetLocation( vIt );
261 TImage::SizeType size = mIt.GetSize( );
263 for( unsigned int d = 0; d < TImage::ImageDimension; ++d )
265 for( unsigned int i = 0; i < nN; ++i )
266 if( marks->GetRequestedRegion( ).IsInside( mIt.GetIndex( i ) ) )
267 mIt.SetPixel( i, ( start )? 255: 100 );
272 vIt = this->_Parent( vIt );
274 } while( vIt != this->_Parent( vIt ) );
277 // std::cout << vIt << " " << this->GetSeed( 0 ) << std::endl;
281 TVertex parent = this->_Parent( vIt );
282 while( parent != vIt )
284 pS.push_front( vIt );
286 parent = this->_Parent( vIt );
288 TImage::PointType pnt;
289 this->GetInput( )->TransformIndexToPhysicalPoint( vIt, pnt );
290 points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
291 if( points->GetNumberOfPoints( ) > 1 )
293 lines->InsertNextCell( 2 );
294 lines->InsertCellPoint( points->GetNumberOfPoints( ) - 2 );
295 lines->InsertCellPoint( points->GetNumberOfPoints( ) - 1 );
300 pS.push_front( vIt );
301 TImage::PointType pnt;
302 this->GetInput( )->TransformIndexToPhysicalPoint( vIt, pnt );
303 points->InsertNextPoint( pnt[ 0 ], pnt[ 1 ], pnt[ 2 ] );
304 if( points->GetNumberOfPoints( ) > 1 )
306 lines->InsertNextCell( 2 );
307 lines->InsertCellPoint( points->GetNumberOfPoints( ) - 2 );
308 lines->InsertCellPoint( points->GetNumberOfPoints( ) - 1 );
312 this->m_Axes->SetPoints( points );
313 this->m_Axes->SetLines( lines );
321 virtual bool _UpdateNeigh( _TNode& nn, const _TNode& n )
323 TCost nc = this->_Cost( nn.Vertex, n.Vertex );
324 if( TCost( 0 ) < nc )
326 nn.Cost = n.Cost + ( TCost( 1 ) / nc );
334 virtual bool _UpdateResult( _TNode& n )
336 bool ret = this->Superclass::_UpdateResult( n );
339 TCost nc = this->_Cost( n.Vertex, n.Parent );
340 if( TCost( 0 ) < nc )
342 TCost cc = n.Cost / nc;
343 this->m_Candidates.insert( _TCandidate( cc, n.Vertex ) );
345 this->GetOutput( )->SetPixel( n.Vertex, cc );
354 TDijkstra( const Self& other );
355 Self& operator=( const Self& other );
358 _TCandidates m_Candidates;
360 vtkSmartPointer< vtkPolyData > m_Axes;
363 // -------------------------------------------------------------------------
364 int main( int argc, char* argv[] )
369 << "Usage: " << argv[ 0 ]
370 << " input_image x y z output_image"
376 std::string input_image_fn = argv[ 1 ];
377 TImage::IndexType seed_idx;
378 seed_idx[ 0 ] = std::atoi( argv[ 2 ] );
379 seed_idx[ 1 ] = std::atoi( argv[ 3 ] );
380 seed_idx[ 2 ] = std::atoi( argv[ 4 ] );
381 std::string output_image_fn = argv[ 5 ];
382 bool visual_debug = false;
384 visual_debug = ( std::atoi( argv[ 6 ] ) == 1 );
387 TImageReader::Pointer input_image_reader = TImageReader::New( );
388 input_image_reader->SetFileName( input_image_fn );
391 input_image_reader->Update( );
393 catch( itk::ExceptionObject& err )
395 std::cerr << "Error caught: " << err << std::endl;
399 TImage::ConstPointer input_image = input_image_reader->GetOutput( );
402 TVTKImage::Pointer vtk_image = TVTKImage::New( );
403 vtk_image->SetInput( input_image );
404 vtk_image->Update( );
407 view.SetBackground( 0.3, 0.2, 0.8 );
408 view.SetSize( 800, 800 );
409 view.SetImage( vtk_image->GetOutput( ) );
411 // Allow some interaction
415 TDijkstra::Pointer paths = TDijkstra::New( );
416 paths->AddSeed( seed_idx, TScalar( 0 ) );
417 paths->SetInput( input_image );
418 paths->SetNeighborhoodOrder( 1 );
422 // Configure observer
423 TDijkstraObs::Pointer obs = TDijkstraObs::New( );
424 obs->SetImage( input_image, view.GetWindow( ) );
425 paths->AddObserver( itk::AnyEvent( ), obs );
426 paths->ThrowEventsOn( );
429 paths->ThrowEventsOff( );
430 std::clock_t start = std::clock( );
432 std::clock_t end = std::clock( );
433 double seconds = double( end - start ) / double( CLOCKS_PER_SEC );
434 std::cout << "Paths extraction time = " << seconds << std::endl;
436 view.AddPolyData( paths->m_Axes, 1, 0, 0 );
439 TImageWriter::Pointer dijkstra_writer =
440 TImageWriter::New( );
441 dijkstra_writer->SetInput( paths->GetOutput( ) );
442 dijkstra_writer->SetFileName( "dijkstra.mhd" );
443 dijkstra_writer->Update( );
447 TVTKImage::Pointer output_image_vtk = TVTKImage::New( );
448 output_image_vtk->SetInput( segmentor->GetOutput( ) );
449 output_image_vtk->Update( );
451 vtkSmartPointer< vtkImageMarchingCubes > mc =
452 vtkSmartPointer< vtkImageMarchingCubes >::New( );
453 mc->SetInputData( output_image_vtk->GetOutput( ) );
456 double( segmentor->GetInsideValue( ) ) * double( 0.95 )
460 // Let some interaction and close program
461 view.AddPolyData( mc->GetOutput( ), 0.1, 0.6, 0.8, 0.5 );
464 // Write resulting image
465 TImageWriter::Pointer output_image_writer = TImageWriter::New( );
466 output_image_writer->SetInput( segmentor->GetOutput( ) );
467 output_image_writer->SetFileName( output_image_fn );
470 output_image_writer->Update( );
472 catch( itk::ExceptionObject& err )
474 std::cerr << "Error caught: " << err << std::endl;