]> Creatis software - FrontAlgorithms.git/blobdiff - appli/CTBronchi/Process.cxx
...
[FrontAlgorithms.git] / appli / CTBronchi / Process.cxx
index 9f29ffc9c0ef410d45563552dcb3817fa3e4dd6a..d1498ea2f7ca62fe146cfca09cbc571590fe40a5 100644 (file)
@@ -6,12 +6,18 @@
 #include <streambuf>
 #include <tclap/CmdLine.h>
 
+#include <itkAndImageFilter.h>
+#include <itkBinaryThresholdImageFilter.h>
 #include <itkMinimumMaximumImageCalculator.h>
 #include <itkInvertIntensityImageFilter.h>
 #include <itkHessianRecursiveGaussianImageFilter.h>
 #include <itkHessian3DToVesselnessMeasureImageFilter.h>
 
+#include <fpa/Common/SliceBySliceRandomWalker.h>
+#include <fpa/Filters/Image/ExtractSkeleton.h>
 #include <fpa/Filters/Image/Mori.h>
+#include <fpa/Filters/Image/RandomWalker.h>
+#include <fpa/Functors/Dijkstra/Image/Gaussian.h>
 
 #include "MoriLabelling.h"
 #include "Process.h"
@@ -23,26 +29,38 @@ Process( )
     m_InsideLabel( 1 ),
     m_OutsideLabel( 2 )
 {
-  this->m_StrArg[ "input" ] = TArgument( "", true );
-  this->m_StrArg[ "seed_file" ] = TArgument( "", false );
-  this->m_StrArg[ "seed" ] = TArgument( "", false );
-  this->m_StrArg[ "seed_type" ] = TArgument( "point", false );
-
-  this->m_DblArg[ "beta" ] = TArgument( "2.5", false );
-  this->m_DblArg[ "epsilon" ] = TArgument( "1e-5", false );
-  this->m_DblArg[ "vesselness_sigma" ] = TArgument( "0.5", false );
-  this->m_DblArg[ "vesselness_alpha1" ] = TArgument( "0.5", false );
-  this->m_DblArg[ "vesselness_alpha2" ] = TArgument(  "2", false );
-  this->m_DblArg[ "mori_min_thr" ] = TArgument( "-850", false );
-  this->m_DblArg[ "mori_kernel" ] = TArgument( "20", false );
-  this->m_DblArg[ "mori_signal_thr" ] = TArgument( "100", false );
-  this->m_DblArg[ "mori_signal_influence" ] = TArgument( "0.5", false );
-  this->m_DblArg[ "mori_lower" ] = TArgument( "-1024", false );
-  this->m_DblArg[ "mori_upper" ] = TArgument( "0", false );
-  this->m_DblArg[ "mori_delta" ] = TArgument( "1", false );
-  this->m_DblArg[ "slicerw_thr" ] = TArgument( "5", false );
-  this->m_DblArg[ "fastrw_thr" ] = TArgument( "65", false );
-  this->m_DblArg[ "labels_upper_thr" ] = TArgument( "-400", false );
+  this->m_StrArgs[ "input" ] = TStrArg( "", "I", true );
+  this->m_StrArgs[ "vesselness" ] = TStrArg( "", "V", false );
+  this->m_StrArgs[ "mori" ] = TStrArg( "", "M", false );
+  this->m_StrArgs[ "labels" ] = TStrArg( "", "L", false );
+  this->m_StrArgs[ "fastrw" ] = TStrArg( "", "F", false );
+  this->m_StrArgs[ "slicerw" ] = TStrArg( "", "R", false );
+  this->m_StrArgs[ "andrw" ] = TStrArg( "", "A", false );
+  this->m_StrArgs[ "fastrw_skeleton" ] = TStrArg( "", "G", false );
+  this->m_StrArgs[ "slicerw_skeleton" ] = TStrArg( "", "U", false );
+  this->m_StrArgs[ "andrw_skeleton" ] = TStrArg( "", "W", false );
+  this->m_StrArgs[ "fastrw_points" ] = TStrArg( "", "B", false );
+  this->m_StrArgs[ "slicerw_points" ] = TStrArg( "", "C", false );
+  this->m_StrArgs[ "andrw_points" ] = TStrArg( "", "D", false );
+  this->m_StrArgs[ "seed_file" ] = TStrArg( "", "P", false );
+  this->m_StrArgs[ "seed" ] = TStrArg( "", "S", false );
+  this->m_StrArgs[ "seed_type" ] = TStrArg( "point", "T", false );
+
+  this->m_DblArgs[ "beta" ] = TDblArg( 2.5, "b", false );
+  this->m_DblArgs[ "epsilon" ] = TDblArg( 1e-5, "e", false );
+  this->m_DblArgs[ "vesselness_sigma" ] = TDblArg( 0.5, "a", false );
+  this->m_DblArgs[ "vesselness_alpha1" ] = TDblArg( 0.5, "c", false );
+  this->m_DblArgs[ "vesselness_alpha2" ] = TDblArg(  2, "d", false );
+  this->m_DblArgs[ "mori_min_thr" ] = TDblArg( -850, "f", false );
+  this->m_DblArgs[ "mori_kernel" ] = TDblArg( 20, "g", false );
+  this->m_DblArgs[ "mori_signal_thr" ] = TDblArg( 100, "i", false );
+  this->m_DblArgs[ "mori_signal_influence" ] = TDblArg( 0.5, "j", false );
+  this->m_DblArgs[ "mori_lower" ] = TDblArg( -1024, "k", false );
+  this->m_DblArgs[ "mori_upper" ] = TDblArg( 0, "l", false );
+  this->m_DblArgs[ "mori_delta" ] = TDblArg( 1, "m", false );
+  this->m_DblArgs[ "slicerw_thr" ] = TDblArg( 5, "n", false );
+  this->m_DblArgs[ "fastrw_thr" ] = TDblArg( 65, "o", false );
+  this->m_DblArgs[ "labels_upper_thr" ] = TDblArg( -400, "p", false );
 }
 
 // -------------------------------------------------------------------------
@@ -55,61 +73,46 @@ CTBronchi::Process::
 void CTBronchi::Process::
 ParseArguments( int argc, char* argv[] )
 {
-  typedef TCLAP::ValueArg< std::string > _TStrArg;
-  typedef TCLAP::ValueArg< TScalar >     _TDblArg;
-  std::map< std::string, _TStrArg* > strArg;
-  std::map< std::string, _TDblArg* > dblArg;
-  unsigned char flag = 'a';
-
-  TArguments::iterator sIt = this->m_StrArg.begin( );
-  for( ; sIt != this->m_StrArg.end( ); ++sIt )
-  {
-    std::stringstream fStr;
-    fStr << flag;
-    flag++;
-    if( flag == 'h' )
-      flag++;
-
-    _TStrArg* a = new _TStrArg(
-      fStr.str( ), sIt->first, sIt->first,
+  typedef TCLAP::ValueArg< TString > _TStrArg;
+  typedef TCLAP::ValueArg< TScalar > _TDblArg;
+  std::map< TString, _TStrArg* > strArgs;
+  std::map< TString, _TDblArg* > dblArgs;
+
+  // Load arguments
+  TStrArgs::iterator sIt = this->m_StrArgs.begin( );
+  for( ; sIt != this->m_StrArgs.end( ); ++sIt )
+    strArgs[ sIt->first ] = new _TStrArg(
       std::get< 1 >( sIt->second ),
+      sIt->first, sIt->first,
+      std::get< 2 >( sIt->second ),
       std::get< 0 >( sIt->second ),
-      "string"
+      TString( "string (" ) + std::get< 0 >( sIt->second ) + ")"
       );
-    strArg[ sIt->first ] = a;
-
-  } // rof
 
-  TArguments::iterator dIt = this->m_DblArg.begin( );
-  for( ; dIt != this->m_DblArg.end( ); ++dIt )
+  TDblArgs::iterator dIt = this->m_DblArgs.begin( );
+  for( ; dIt != this->m_DblArgs.end( ); ++dIt )
   {
-    std::stringstream fStr;
-    fStr << flag;
-    flag++;
-    if( flag == 'h' )
-      flag++;
-
-    std::istringstream vStr( std::get< 0 >( dIt->second ) );
-    TScalar v;
-    vStr >> v;
-
-    _TDblArg* a = new _TDblArg(
-      fStr.str( ), dIt->first, dIt->first,
+    std::stringstream v;
+    v << "value (" << std::get< 0 >( dIt->second ) << ")";
+    dblArgs[ dIt->first ] = new _TDblArg(
       std::get< 1 >( dIt->second ),
-      v, "value"
+      dIt->first, dIt->first,
+      std::get< 2 >( dIt->second ),
+      std::get< 0 >( dIt->second ),
+      v.str( )
       );
-    dblArg[ dIt->first ] = a;
 
   } // rof
 
-  std::map< std::string, _TStrArg* >::iterator saIt;
-  std::map< std::string, _TDblArg* >::iterator daIt;
+  // Parse arguments
+  std::map< TString, _TStrArg* >::iterator saIt;
+  std::map< TString, _TDblArg* >::iterator daIt;
   try
   {
     TCLAP::CmdLine cmd( "CTBronchi pipeline", ' ', "1.0.0" );
-    for( saIt = strArg.begin( ); saIt != strArg.end( ); ++saIt )
+    for( saIt = strArgs.begin( ); saIt != strArgs.end( ); ++saIt )
       cmd.add( *( saIt->second ) );
-    for( daIt = dblArg.begin( ); daIt != dblArg.end( ); ++daIt )
+    for( daIt = dblArgs.begin( ); daIt != dblArgs.end( ); ++daIt )
       cmd.add( *( daIt->second ) );
     cmd.parse( argc, argv );
   }
@@ -121,44 +124,89 @@ ParseArguments( int argc, char* argv[] )
 
   } // yrt
 
-  for( saIt = strArg.begin( ); saIt != strArg.end( ); ++saIt )
+  // Get values
+  for( saIt = strArgs.begin( ); saIt != strArgs.end( ); ++saIt )
   {
-    std::get< 0 >( this->m_StrArg[ saIt->first ] ) = saIt->second->getValue( );
+    std::get< 0 >( this->m_StrArgs[ saIt->first ] ) =
+      saIt->second->getValue( );
     delete saIt->second;
 
   } // rof
-  for( daIt = dblArg.begin( ); daIt != dblArg.end( ); ++daIt )
+  for( daIt = dblArgs.begin( ); daIt != dblArgs.end( ); ++daIt )
   {
-    std::stringstream vStr;
-    vStr << daIt->second->getValue( );
-    std::get< 0 >( this->m_DblArg[ daIt->first ] ) = vStr.str( );
+    std::get< 0 >( this->m_DblArgs[ daIt->first ] ) =
+      daIt->second->getValue( );
     delete daIt->second;
 
   } // rof
 
-  // Compute base filename
-  std::string iname = std::get< 0 >( this->m_StrArg[ "input" ] );
-  this->m_BaseFileName = iname.substr( 0, iname.find_last_of( "." ) );
+  // Compute base filenames
+  TString bname = std::get< 0 >( this->m_StrArgs[ "input" ] );
+  bname = bname.substr( 0, bname.find_last_of( "." ) );
+  const unsigned int N = 6;
+  const unsigned int M = 6;
+  TString names[ N + M ] =
+    {
+      "vesselness",
+      "mori",
+      "labels",
+      "fastrw",
+      "slicerw",
+      "andrw",
+      "fastrw_skeleton",
+      "slicerw_skeleton",
+      "andrw_skeleton",
+      "fastrw_points",
+      "slicerw_points",
+      "andrw_points"
+    };
+  for( unsigned int i = 0; i < N; ++i )
+    if( std::get< 0 >( this->m_StrArgs[ names[ i ] ] ) == "" )
+      std::get< 0 >( this->m_StrArgs[ names[ i ] ] ) =
+        bname + "_" + names[ i ] + ".mha";
+  for( unsigned int i = 0; i < M; ++i )
+    if( std::get< 0 >( this->m_StrArgs[ names[ i + N ] ] ) == "" )
+      std::get< 0 >( this->m_StrArgs[ names[ i + N ] ] ) =
+        bname + "_" + names[ i + N ] + ".txt";
 }
 
 // -------------------------------------------------------------------------
 void CTBronchi::Process::
 Update( )
 {
-  this->_Input( );
-  this->_Vesselness( );
-  this->_Mori( );
-  this->_MoriLabelling( );
+  this->_Input( this->m_Input );
+  this->_Vesselness( this->m_Input, this->m_Vesselness );
+  this->_Mori( this->m_Input, this->m_Mori, this->m_Seed );
+  this->_MoriLabelling(
+    this->m_Input, this->m_Mori, this->m_Vesselness, this->m_Labels
+    );
+  this->_FastRW( this->m_Input, this->m_Labels, this->m_FastRW );
+  this->_SliceRW(
+    this->m_Input, this->m_Mori, this->m_Vesselness, this->m_SliceRW
+    );
+  this->_AndImages( this->m_FastRW, this->m_SliceRW, this->m_AndRW );
+  this->_Skeleton(
+    this->m_SliceRW, this->m_SliceRWSkeleton,
+    std::get< 0 >( this->m_StrArgs[ "slicerw_skeleton" ] )
+    );
+  this->_Skeleton(
+    this->m_AndRW, this->m_AndRWSkeleton,
+    std::get< 0 >( this->m_StrArgs[ "andrw_skeleton" ] )
+    );
+  this->_Skeleton(
+    this->m_FastRW, this->m_FastRWSkeleton,
+    std::get< 0 >( this->m_StrArgs[ "fastrw_skeleton" ] )
+    );
 }
 
 // -------------------------------------------------------------------------
+template< class _TImage >
 void CTBronchi::Process::
-_Input( )
+_Input( _TImage& input )
 {
-  std::string iname = std::get< 0 >( this->m_StrArg[ "input" ] );
-  std::string sname = std::get< 0 >( this->m_StrArg[ "seed_file" ] );
-  std::string seed = std::get< 0 >( this->m_StrArg[ "seed" ] );
-  std::string stype = std::get< 0 >( this->m_StrArg[ "seed_type" ] );
+  TString sname = std::get< 0 >( this->m_StrArgs[ "seed_file" ] );
+  TString seed = std::get< 0 >( this->m_StrArgs[ "seed" ] );
+  TString stype = std::get< 0 >( this->m_StrArgs[ "seed_type" ] );
   if( sname == "" && seed == "" )
     throw std::runtime_error( "No seed given." );
   if( sname != "" )
@@ -185,155 +233,149 @@ _Input( )
     sSeed >> idx[ 0 ] >> idx[ 1 ] >> idx[ 2 ];
 
   // Read image
-  double t = this->m_Input.Load( iname );
+  TString iname = std::get< 0 >( this->m_StrArgs[ "input" ] );
+  double t = input.Load( iname );
   if( t < 0 )
-    std::runtime_error( std::string( "Could not read \"" ) + iname + "\"" );
+    std::runtime_error( TString( "Could not read \"" ) + iname + "\"" );
   std::cout << "\"" << iname << "\" read in " << t << " s." << std::endl;
 
   // Synch seed
   if( stype == "point" )
-    this->m_Input.Get( )->TransformPhysicalPointToIndex( pnt, idx );
+    input.Get( )->TransformPhysicalPointToIndex( pnt, idx );
   else
-    this->m_Input.Get( )->TransformIndexToPhysicalPoint( idx, pnt );
+    input.Get( )->TransformIndexToPhysicalPoint( idx, pnt );
   this->m_Seed = TSeed( idx, pnt );
 }
 
 // -------------------------------------------------------------------------
+template< class _TInput, class _TVesselness >
 void CTBronchi::Process::
-_Vesselness( )
+_Vesselness( _TInput& input, _TVesselness& vesselness )
 {
-  std::string vname = this->m_BaseFileName + "_vesselness.mha";
-  double t = this->m_Vesselness.Load( vname );
+  TString iname = std::get< 0 >( this->m_StrArgs[ "vesselness" ] );
+  double t = vesselness.Load( iname );
   if( t < 0 )
   {
     t = 0;
 
-    // Arguments
-    std::stringstream v;
-    v << std::get< 0 >( this->m_DblArg[ "vesselness_sigma" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "vesselness_alpha1" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "vesselness_alpha2" ] );
-    std::istringstream w( v.str( ) );
-    TScalar s, a1, a2;
-    w >> s >> a1 >> a2;
-
     // Min-max
-    typedef itk::MinimumMaximumImageCalculator< TPixelImage::TImage > _TMinMax;
-    _TMinMax::Pointer minMax = _TMinMax::New( );
-    minMax->SetImage( this->m_Input.Get( ) );
+    typedef itk::MinimumMaximumImageCalculator< typename _TInput::TImage > _TMinMax;
+    typename _TMinMax::Pointer minMax = _TMinMax::New( );
+    minMax->SetImage( input.Get( ) );
     minMax->Compute( );
 
     // Invert intensities
-    typedef CTBronchi::Filter< itk::InvertIntensityImageFilter< TPixelImage::TImage > > _TInverter;
+    typedef CTBronchi::Filter< itk::InvertIntensityImageFilter< typename _TInput::TImage > > _TInverter;
     _TInverter inverter;
-    inverter.Get( )->SetInput( this->m_Input.Get( ) );
+    inverter.Get( )->SetInput( input.Get( ) );
     inverter.Get( )->SetMaximum( minMax->GetMaximum( ) );
     double t1 = inverter.Update( );
     t += t1;
     std::cout << "Inversion executed in " << t1 << " s" << std::endl;
 
     // Compute hessian image
-    typedef CTBronchi::Filter< itk::HessianRecursiveGaussianImageFilter< TPixelImage::TImage > > _THessian;
+    typedef CTBronchi::Filter< itk::HessianRecursiveGaussianImageFilter< typename _TInput::TImage > > _THessian;
     _THessian hessian;
     hessian.Get( )->SetInput( inverter.Get( )->GetOutput( ) );
-    hessian.Get( )->SetSigma( s );
+    hessian.Get( )->SetSigma(
+      std::get< 0 >( this->m_DblArgs[ "vesselness_sigma" ] )
+      );
     t1 = hessian.Update( );
     t += t1;
     std::cout << "Hessian executed in " << t1 << " s" << std::endl;
 
     // Vesselness
-    typedef CTBronchi::Filter< itk::Hessian3DToVesselnessMeasureImageFilter< TScalar > > _TVesselness;
-    _TVesselness vesselness;
-    vesselness.Get( )->SetInput( hessian.Get( )->GetOutput( ) );
-    vesselness.Get( )->SetAlpha1( a1 );
-    vesselness.Get( )->SetAlpha2( a2 );
-    t1 = vesselness.Update( );
+    typedef CTBronchi::Filter< itk::Hessian3DToVesselnessMeasureImageFilter< typename _TVesselness::TImage::PixelType > > _TVesselnessFilter;
+    _TVesselnessFilter vFilter;
+    vFilter.Get( )->SetInput( hessian.Get( )->GetOutput( ) );
+    vFilter.Get( )->SetAlpha1(
+      std::get< 0 >( this->m_DblArgs[ "vesselness_alpha1" ] )
+      );
+    vFilter.Get( )->SetAlpha2(
+      std::get< 0 >( this->m_DblArgs[ "vesselness_alpha2" ] )
+      );
+    t1 = vFilter.Update( );
     t += t1;
     std::cout << "Hessian measure computed in " << t1 << " s." << std::endl;
 
-    this->m_Vesselness.Set( vesselness.Get( )->GetOutput( ) );
-    t1 = this->m_Vesselness.Save( vname );
+    vesselness.Set( vFilter.Get( )->GetOutput( ) );
+    t1 = vesselness.Save( iname );
     t += t1;
-    std::cout << "\"" << vname << "\" saved in " << t1 << " s." << std::endl;
+    std::cout << "\"" << iname << "\" saved in " << t1 << " s." << std::endl;
 
   } // fi
   std::cout << "Vesselness computed in " << t << " s." << std::endl;
 }
 
 // -------------------------------------------------------------------------
+template< class _TInput, class _TMori, class _TSeed >
 void CTBronchi::Process::
-_Mori( )
+_Mori( _TInput& input, _TMori& mori, _TSeed& seed )
 {
-  std::string mname = this->m_BaseFileName + "_mori.mha";
-  double t = this->m_Mori.Load( mname );
+  TString iname = std::get< 0 >( this->m_StrArgs[ "mori" ] );
+  double t = mori.Load( iname );
   if( t < 0 )
   {
     t = 0;
 
-    // Arguments
-    std::stringstream v;
-    v << std::get< 0 >( this->m_DblArg[ "mori_min_thr" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "mori_kernel" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "mori_signal_thr" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "mori_signal_influence" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "mori_lower" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "mori_upper" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "mori_delta" ] );
-    std::istringstream w( v.str( ) );
-    TScalar mThr, sKernel, sThr, sInfluence, lower, upper, delta;
-    w >> mThr >> sKernel >> sThr >> sInfluence >> lower >> upper >> delta;
-
     // Mori segmentation
-    typedef CTBronchi::Filter< fpa::Filters::Image::Mori< TPixelImage::TImage, TLabelImage::TImage > > _TMori;
-    _TMori mori;
-    mori.Get( )->SetInput( this->m_Input.Get( ) );
-    mori.Get( )->SetSeed( this->m_Seed.second );
-    mori.Get( )->SetInsideValue( this->m_InsideLabel );
-    mori.Get( )->SetOutsideValue( this->m_UndefinedLabel );
-    mori.Get( )->SetMinimumThreshold( mThr );
-    mori.Get( )->SetSignalKernelSize( sKernel );
-    mori.Get( )->SetSignalThreshold( sThr );
-    mori.Get( )->SetSignalInfluence( sInfluence );
-    mori.Get( )->SetThresholds( lower, upper, delta );
-    double t1 = mori.Update( );
+    typedef CTBronchi::Filter< fpa::Filters::Image::Mori< TPixelImage::TImage, TLabelImage::TImage > > _TMoriFilter;
+    _TMoriFilter mFilter;
+    mFilter.Get( )->SetInput( input.Get( ) );
+    mFilter.Get( )->SetSeed( seed.second );
+    mFilter.Get( )->SetInsideValue( this->m_InsideLabel );
+    mFilter.Get( )->SetOutsideValue( this->m_UndefinedLabel );
+    mFilter.Get( )->SetMinimumThreshold(
+      std::get< 0 >( this->m_DblArgs[ "mori_min_thr" ] )
+      );
+    mFilter.Get( )->SetSignalKernelSize(
+      std::get< 0 >( this->m_DblArgs[ "mori_kernel" ] )
+      );
+    mFilter.Get( )->SetSignalThreshold(
+      std::get< 0 >( this->m_DblArgs[ "mori_signal_thr" ] )
+      );
+    mFilter.Get( )->SetSignalInfluence(
+      std::get< 0 >( this->m_DblArgs[ "mori_signal_influence" ] )
+      );
+    mFilter.Get( )->SetThresholds(
+      std::get< 0 >( this->m_DblArgs[ "mori_lower" ] ),
+      std::get< 0 >( this->m_DblArgs[ "mori_upper" ] ),
+      std::get< 0 >( this->m_DblArgs[ "mori_delta" ] )
+      );
+    double t1 = mFilter.Update( );
     t += t1;
     std::cout << "Segmentation computed in " << t1 << " s." << std::endl;
 
-    this->m_Mori.Set( mori.Get( )->GetOutput( ) );
-    t1 = this->m_Mori.Save( mname );
+    mori.Set( mFilter.Get( )->GetOutput( ) );
+    t1 = mori.Save( iname );
     t += t1;
-    std::cout << "\"" << mname << "\" saved in " << t1 << " s." << std::endl;
+    std::cout << "\"" << iname << "\" saved in " << t1 << " s." << std::endl;
 
   } // fi
   std::cout << "Mori segmentation computed in " << t << " s." << std::endl;
 }
 
 // -------------------------------------------------------------------------
+template< class _TInput, class _TMori, class _TVesselness, class _TLabels >
 void CTBronchi::Process::
-_MoriLabelling( )
+_MoriLabelling(
+  _TInput& input, _TMori& mori, _TVesselness& vesselness, _TLabels& labels
+  )
 {
-  std::string mname = this->m_BaseFileName + "_labels.mha";
-  double t = this->m_Labels.Load( mname );
+  TString iname = std::get< 0 >( this->m_StrArgs[ "labels" ] );
+  double t = labels.Load( iname );
   if( t < 0 )
   {
     t = 0;
 
-    // Arguments
-    std::stringstream v;
-    v << std::get< 0 >( this->m_DblArg[ "fastrw_thr" ] ) << " "
-      << std::get< 0 >( this->m_DblArg[ "labels_upper_thr" ] );
-    std::istringstream w( v.str( ) );
-    TScalar vThr, uThr;
-    w >> vThr >> uThr;
-
     // Mori labelling
-    typedef CTBronchi::Filter< CTBronchi::MoriLabelling< TPixelImage::TImage, TLabelImage::TImage, TScalarImage::TImage > > _TLabelling;
+    typedef CTBronchi::Filter< CTBronchi::MoriLabelling< typename _TInput::TImage, typename _TLabels::TImage, typename _TVesselness::TImage > > _TLabelling;
     _TLabelling labelling;
-    labelling.Get( )->SetInput( this->m_Input.Get( ) );
-    labelling.Get( )->SetInputLabels( this->m_Mori.Get( ) );
-    labelling.Get( )->SetInputVesselness( this->m_Vesselness.Get( ) );
-    labelling.Get( )->SetVesselnessThreshold( vThr );
-    labelling.Get( )->SetUpperThreshold( uThr );
+    labelling.Get( )->SetInput( input.Get( ) );
+    labelling.Get( )->SetInputLabels( mori.Get( ) );
+    labelling.Get( )->SetInputVesselness( vesselness.Get( ) );
+    labelling.Get( )->SetVesselnessThreshold( std::get< 0 >( this->m_DblArgs[ "fastrw_thr" ] ) );
+    labelling.Get( )->SetUpperThreshold( std::get< 0 >( this->m_DblArgs[ "labels_upper_thr" ] ) );
     labelling.Get( )->SetInsideValue( this->m_InsideLabel );
     labelling.Get( )->SetOutsideValue( this->m_OutsideLabel );
     labelling.Get( )->SetFillValue( this->m_OutsideLabel );
@@ -341,13 +383,156 @@ _MoriLabelling( )
     t += t1;
     std::cout << "Labelling computed in " << t1 << " s." << std::endl;
 
-    this->m_Labels.Set( labelling.Get( )->GetOutput( ) );
-    t1 = this->m_Labels.Save( mname );
+    labels.Set( labelling.Get( )->GetOutput( ) );
+    t1 = labels.Save( iname );
     t += t1;
-    std::cout << "\"" << mname << "\" saved in " << t1 << " s." << std::endl;
+    std::cout << "\"" << iname << "\" saved in " << t1 << " s." << std::endl;
 
   } // fi
   std::cout << "Mori labelling computed in " << t << " s." << std::endl;
 }
 
+// -------------------------------------------------------------------------
+template< class _TInput, class _TLabels, class _TFastRW >
+void CTBronchi::Process::
+_FastRW( _TInput& input, _TLabels& labels, _TFastRW& fastrw )
+{
+  TString iname = std::get< 0 >( this->m_StrArgs[ "fastrw" ] );
+  double t = fastrw.Load( iname );
+  if( t < 0 )
+  {
+    t = 0;
+
+    // Prepare weight functor
+    typedef fpa::Functors::Dijkstra::Image::Gaussian< typename _TInput::TImage, typename _TFastRW::TImage::PixelType > TWeight;
+    typename TWeight::Pointer weight = TWeight::New( );
+    weight->SetBeta( std::get< 0 >( this->m_DblArgs[ "beta" ] ) );
+    weight->SetEpsilon( std::get< 0 >( this->m_DblArgs[ "epsilon" ] ) );
+
+    // Random walk
+    typedef CTBronchi::Filter< fpa::Filters::Image::RandomWalker< typename _TInput::TImage, typename _TLabels::TImage, typename _TFastRW::TImage::PixelType > > TFilter;
+    TFilter filter;
+    filter.Get( )->SetInputImage( input.Get( ) );
+    filter.Get( )->SetInputLabels( labels.Get( ) );
+    filter.Get( )->SetWeightFunction( weight );
+    double t1 = filter.Update( );
+    t += t1;
+    std::cout << "Fast random walker executed in " << t1 << " s" << std::endl;
+
+    // Extract label
+    typedef CTBronchi::Filter< itk::BinaryThresholdImageFilter< typename _TLabels::TImage, typename _TLabels::TImage > > _TExtract;
+    _TExtract extract;
+    extract.Get( )->SetInput( filter.Get( )->GetOutputLabels( ) );
+    extract.Get( )->SetInsideValue( this->m_InsideLabel );
+    extract.Get( )->SetOutsideValue( this->m_UndefinedLabel );
+    extract.Get( )->SetLowerThreshold( this->m_InsideLabel );
+    extract.Get( )->SetUpperThreshold( this->m_InsideLabel );
+    t1 = extract.Update( );
+    t += t1;
+    std::cout << "Extract labels executed in " << t1 << " s" << std::endl;
+
+    fastrw.Set( extract.Get( )->GetOutput( ) );
+    t1 = fastrw.Save( iname );
+    t += t1;
+    std::cout << "\"" << iname << "\" saved in " << t1 << " s." << std::endl;
+
+  } // fi
+  std::cout << "Fast random walker computed in " << t << " s." << std::endl;
+}
+
+// -------------------------------------------------------------------------
+template< class _TInput, class _TLabels, class _TVesselness, class _TSliceRW >
+void CTBronchi::Process::
+_SliceRW(
+  _TInput& input, _TLabels& labels, _TVesselness& vesselness, _TSliceRW& slicerw
+  )
+{
+  TString iname = std::get< 0 >( this->m_StrArgs[ "slicerw" ] );
+  double t = slicerw.Load( iname );
+  if( t < 0 )
+  {
+    t = 0;
+
+    // Random walk
+    typedef CTBronchi::Filter< fpa::Common::SliceBySliceRandomWalker< typename _TInput::TImage, typename _TLabels::TImage, typename _TVesselness::TImage > > TFilter;
+    TFilter filter;
+    filter.Get( )->SetInput( input.Get( ) );
+    filter.Get( )->SetInputLabels( labels.Get( ) );
+    filter.Get( )->SetInputVesselness( vesselness.Get( ) );
+    filter.Get( )->SetBeta( std::get< 0 >( this->m_DblArgs[ "beta" ] ) );
+    filter.Get( )->SetVesselnessThreshold( std::get< 0 >( this->m_DblArgs[ "slicerw_thr" ] ) );
+    filter.Get( )->SetEpsilon( std::get< 0 >( this->m_DblArgs[ "epsilon" ] ) );
+    double t1 = filter.Update( );
+    t += t1;
+    std::cout << "Extract labels executed in " << t1 << " s" << std::endl;
+
+    slicerw.Set( filter.Get( )->GetOutput( ) );
+    t1 = slicerw.Save( iname );
+    t += t1;
+    std::cout << "\"" << iname << "\" saved in " << t1 << " s." << std::endl;
+
+  } // fi
+  std::cout << "Slice by slice random walker computed in " << t << " s." << std::endl;
+}
+
+// -------------------------------------------------------------------------
+template< class _TInput >
+void CTBronchi::Process::
+_AndImages( _TInput& a, _TInput& b, _TInput& c )
+{
+  TString iname = std::get< 0 >( this->m_StrArgs[ "andrw" ] );
+  double t = c.Load( iname );
+  if( t < 0 )
+  {
+    t = 0;
+
+    // Random walk
+    typedef CTBronchi::Filter< itk::AndImageFilter< typename _TInput::TImage > > TFilter;
+    TFilter filter;
+    filter.Get( )->SetInput( 0, a.Get( ) );
+    filter.Get( )->SetInput( 1, b.Get( ) );
+    double t1 = filter.Update( );
+    t += t1;
+    std::cout << "And segmentations executed in " << t1 << " s" << std::endl;
+
+    c.Set( filter.Get( )->GetOutput( ) );
+    t1 = c.Save( iname );
+    t += t1;
+    std::cout << "\"" << iname << "\" saved in " << t1 << " s." << std::endl;
+
+  } // fi
+  std::cout << "And segmentations computed in " << t << " s." << std::endl;
+}
+
+// -------------------------------------------------------------------------
+template< class _TInput, class _TSkeleton >
+void CTBronchi::Process::
+_Skeleton( _TInput& a, _TSkeleton& s, const TString& fname )
+{
+  double t = s.Load( fname );
+  if( t < 0 )
+  {
+    t = 0;
+
+    typedef CTBronchi::Filter< fpa::Filters::Image::ExtractSkeleton< typename _TInput::TImage > > TFilter;
+    TFilter filter;
+    filter.Get( )->SetInput( a.Get( ) );
+    filter.Get( )->SeedFromMaximumDistanceOff( );
+    filter.Get( )->SetSeed( this->m_Seed.first );
+    filter.Get( )->GetDistanceMap( )->InsideIsPositiveOn( );
+    filter.Get( )->GetDistanceMap( )->SquaredDistanceOff( );
+    filter.Get( )->GetDistanceMap( )->UseImageSpacingOn( );
+    double t1 = filter.Update( );
+    t += t1;
+    std::cout << "Skeleton executed in " << t1 << " s" << std::endl;
+
+    s.Set( filter.Get( )->GetOutput( ) );
+    t1 = s.Save( fname );
+    t += t1;
+    std::cout << "\"" << fname << "\" saved in " << t1 << " s." << std::endl;
+
+  } // fi
+  std::cout << "Skeleton computed in " << t << " s." << std::endl;
+}
+
 // eof - $RCSfile$