cmtkElasticRegistrationCommandLine.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2487 $
00026 //
00027 //  $LastChangedDate: 2010-10-21 14:18:48 -0700 (Thu, 21 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkElasticRegistrationCommandLine.h"
00034 
00035 #include <System/cmtkCommandLine.h>
00036 #include <System/cmtkConsole.h>
00037 #include <System/cmtkTimers.h>
00038 #include <System/cmtkThreads.h>
00039 #include <System/cmtkCompressedStream.h>
00040 #include <System/cmtkMountPoints.h>
00041 
00042 #include <IO/cmtkXformIO.h>
00043 #include <IO/cmtkClassStream.h>
00044 #include <IO/cmtkClassStreamAffineXform.h>
00045 #include <IO/cmtkVolumeIO.h>
00046 #include <IO/cmtkSplineWarpXformITKIO.h>
00047 
00048 #include <Base/cmtkAnatomicalOrientation.h>
00049 #include <Base/cmtkTransformChangeFromSpaceAffine.h>
00050 
00051 #include <Registration/cmtkVoxelMatchingElasticFunctional.h>
00052 #include <Registration/cmtkSymmetricElasticFunctional.h>
00053 #include <Registration/cmtkProtocolCallback.h>
00054 
00055 #ifdef CMTK_USE_SQLITE
00056 #  include <Registration/cmtkImageXformDB.h>
00057 #endif
00058 
00059 #include <stdlib.h>
00060 #include <stdio.h>
00061 #include <string.h>
00062 #include <signal.h>
00063 
00064 #include <iostream>
00065 #include <algorithm>
00066 
00067 #ifdef HAVE_SYS_TYPES_H
00068 #  include <sys/types.h>
00069 #endif
00070 
00071 #ifdef HAVE_SYS_STAT_H
00072 #  include <sys/stat.h>
00073 #endif
00074 
00075 #ifdef HAVE_SYS_UTSNAME_H
00076 #  include <sys/utsname.h>
00077 #endif
00078 
00079 #ifdef _MSC_VER
00080 #  include <direct.h>
00081 #endif // #ifdef _MSC_VER
00082 
00083 namespace
00084 cmtk
00085 {
00086 
00089 
00090 ElasticRegistrationCommandLine* ElasticRegistrationCommandLine::StaticThis = NULL;
00091 
00092 ElasticRegistrationCommandLine
00093 ::ElasticRegistrationCommandLine
00094 ( const int argc, const char *argv[] ) :
00095 #ifdef CMTK_USE_SQLITE
00096   m_UpdateDB( NULL ),
00097 #endif
00098   m_OutputPathITK( NULL ),
00099   m_ReformattedImagePath( NULL )
00100 {
00101   this->m_Metric = 0;
00102   this->m_Algorithm = 3;
00103 
00104   this->m_GridSpacing = 15;
00105   this->m_ExactGridSpacing = 0;
00106   Studylist = Protocol = Time = NULL;
00107 
00108   this->m_OutputIntermediate = 0;
00109   Verbose = 0;
00110 
00111   InputStudylist = NULL;
00112   const char *initialTransformationFile = NULL;
00113   IntermediateResultIndex = 0;
00114 
00115   this->RigidityConstraintMapFilename = NULL;
00116 
00117   bool forceOutsideFlag = false;
00118   Types::DataItem forceOutsideValue = 0;
00119 
00120   const char* clArg1 = NULL; // input studylist or reference image
00121   const char* clArg2 = NULL; // empty or floating image
00122   const char* clArg3 = NULL; // empty or initial transformation
00123 
00124   try
00125     {
00126     CommandLine cl( CommandLine::PROPS_XML );
00127     cl.SetProgramInfo( CommandLine::PRG_TITLE, "B-spline nonrigid registration" );
00128     cl.SetProgramInfo( CommandLine::PRG_DESCR, "This program performs nonrigid image registration using multi-resolution optimization of voxel-based image similarity measures "
00129                        "and a multi-resolution B-spline transformation model." );
00130     cl.SetProgramInfo( CommandLine::PRG_CATEG, "CMTK.Registration" );
00131 
00132     typedef CommandLine::Key Key;
00133     cl.BeginGroup( "Console", "Console output control" )->SetProperties( CommandLine::PROPS_NOXML );
00134     cl.AddSwitch( Key( 'v', "verbose" ), &this->Verbose, true, "Verbose peration" );
00135     cl.AddSwitch( Key( 'q', "quiet" ), &Verbose, false, "Quiet mode" );
00136     cl.EndGroup();
00137 
00138     cl.BeginGroup( "TransformationIO", "Transformation import/export" );
00139     cl.AddOption( Key( "initial" ), &initialTransformationFile, "Initialize transformation from given path" )->SetProperties( CommandLine::PROPS_XFORM );
00140     cl.AddOption( Key( "write-itk-xform" ), &this->m_OutputPathITK, "Output path for final transformation in ITK format" )
00141       ->SetProperties( CommandLine::PROPS_XFORM | CommandLine::PROPS_OUTPUT )
00142       ->SetAttribute( "type", "bspline" )->SetAttribute( "reference", "FloatingImage" );
00143     cl.AddOption( Key( "write-reformatted" ), &this->m_ReformattedImagePath, "Write reformatted floating image." )
00144       ->SetProperties( CommandLine::PROPS_IMAGE | CommandLine::PROPS_OUTPUT );
00145     cl.EndGroup();
00146 
00147     cl.BeginGroup( "Transformation", "Transformation parameters" );
00148     cl.AddOption( Key( 'g', "grid-spacing" ), &this->m_GridSpacing, "Control point grid spacing" );
00149     cl.AddSwitch( Key( "exact-spacing" ), &this->m_ExactGridSpacing, true, "Use exact control point spacing; do not modify spacing to fit reference image bounding box" );
00150     cl.AddOption( Key( "refine" ), &this->m_RefineGrid, "Number of refinements (control point grid resolution levels)" );
00151     cl.AddSwitch( Key( "delay-refine" ), &this->m_DelayRefineGrid, true, "Delay control point grid refinement; first switch to next higher image resolution" );
00152 
00153     cl.AddOption( Key( "ignore-edge" ), &this->IgnoreEdge, "Ignore n control point layers along each image face" );
00154     cl.AddOption( Key( "restrict" ), &this->RestrictToAxes, "Restrict deformation to coordinate dimension(s) [one or more of 'x','y','z']" );
00155 
00156     cl.AddSwitch( Key( "no-adaptive-fix" ), &this->m_AdaptiveFixParameters, false, "Disable adaptive fixing of control points; optimize all deformation parameters" );
00157     cl.AddOption( Key( "adaptive-fix-thresh" ), &this->m_AdaptiveFixThreshFactor, "Threshold factor for entropy criterion to fix local control points" );
00158     cl.AddSwitch( Key( "accurate" ), &this->m_FastMode, false, "Accurate computation mode: may give slightly better results after substantially longer computation" );
00159     cl.AddSwitch( Key( "fast" ), &this->m_FastMode, true, "Fast computation mode: may give slightly worse results than accurate mode, but saves substantial CPU time" );
00160 
00161     cl.AddSwitch( Key( 'S', "switch" ), &this->ForceSwitchVolumes, true, "Switch reference and floating image" );
00162     cl.EndGroup();
00163 
00164     cl.BeginGroup( "Regularization", "Regularization parameters" );
00165     cl.AddOption( Key( "jacobian-weight" ), &this->m_JacobianConstraintWeight, "Weight for Jacobian-based local volume preservation constraint" );
00166     cl.AddOption( Key( "energy-weight" ), &this->m_GridEnergyWeight, "Weight for grid bending energy constraint" );
00167     cl.AddOption( Key( "rigidity-weight" ), &this->m_RigidityConstraintWeight, "Weight for local rigidity constraint" );
00168     cl.AddOption( Key( "landmark-weight" ), &this->m_LandmarkErrorWeight, "Weight for landmark misregistration registration" );
00169     cl.AddOption( Key( "ic-weight" ), &this->m_InverseConsistencyWeight, "Weight for inverse consistency constraint" );
00170     cl.AddOption( Key( "relax" ), &this->m_RelaxWeight, "Weight relaxation factor for alternating under-constrained iterations" );
00171     cl.AddSwitch( Key( "relax-to-unfold" ), &this->m_RelaxToUnfold, true, "Before each resolution level, regularize negative-Jacobian areas of the deformation to unfold them." );
00172     cl.EndGroup();
00173 
00174     cl.BeginGroup( "Optimization", "Optimization parameters" );
00175     cl.AddOption( Key( 'e', "exploration" ), &this->m_Exploration, "Search space exploration (initial step size)" );
00176     cl.AddOption( Key( 'a', "accuracy" ), &this->m_Accuracy, "Search accuracy (initial step size)" );
00177     cl.AddOption( Key( 'f', "stepfactor" ), &this->OptimizerStepFactor, "Factor for search step size reduction. Must be > 0.0 and < 1.0 [default: 0.5]" );
00178     cl.AddOption( Key( "delta-f-threshold" ), &this->m_DeltaFThreshold, "Optional threshold to terminate optimization (level) if relative change of target function drops below this value." );
00179     cl.AddSwitch( Key( "no-maxnorm" ), &this->UseMaxNorm, false, "Use Euclid norm for gradient normalication in optimization, rather than maximum norm" );
00180     cl.EndGroup();
00181 
00182     cl.BeginGroup( "Resolution", "Image resolution parameters" );
00183     cl.AddOption( Key( 's', "sampling" ), &this->m_Sampling, "Image sampling (finest resampled image resolution)" );
00184     cl.AddOption( Key( "coarsest" ), &this->CoarsestResolution, "Upper limit for image sampling in multiresolution hierarchy" );
00185 
00186     cl.AddSwitch( Key( "omit-original-data" ), &this->m_UseOriginalData, false, "Do not use original data in full resolution for final registration stage." );
00187     cl.EndGroup();
00188 
00189     cl.BeginGroup( "Images", "Image data" );
00190     CommandLine::EnumGroup<int>::SmartPtr
00191       metricGroup = cl.AddEnum( "registration-metric", &this->m_Metric, "Registration metric for motion estimation by image-to-image registration." );
00192     metricGroup->AddSwitch( Key( "nmi" ), 0, "Normalized Mutual Information metric" );
00193     metricGroup->AddSwitch( Key( "mi" ), 1, "Standard Mutual Information metric" );
00194     metricGroup->AddSwitch( Key( "cr" ), 2, "Correlation Ratio metric" );
00195     metricGroup->AddSwitch( Key( "msd" ), 4, "Mean Squared Difference metric" );
00196     metricGroup->AddSwitch( Key( "ncc" ), 5, "Normalized Cross Correlation metric" );
00197 
00198     cl.AddSwitch( Key( "match-histograms" ), &this->m_MatchFltToRefHistogram, true, "Match floating image histogram to reference image histogram." );
00199     cl.AddOption( Key( "force-outside-value" ), &forceOutsideValue, "Force values outside field of view to this value rather than drop incomplete pixel pairs", &forceOutsideFlag );
00200 
00201     this->m_PreprocessorRef.AttachToCommandLine( cl );
00202     this->m_PreprocessorFlt.AttachToCommandLine( cl );
00203 
00204     cl.BeginGroup( "Output", "Output parameters" )->SetProperties( CommandLine::PROPS_NOXML );
00205     cl.AddOption( Key( 'o', "outlist" ), &this->Studylist, "Output path for final transformation" );
00206     cl.AddOption( Key( 'p', "protocol" ), &this->Protocol, "Optimization protocol output file name" );
00207     cl.AddOption( Key( 't', "time" ), &this->Time, "Computation time statistics output file name" );
00208     cl.AddSwitch( Key( "output-intermediate" ), &this->m_OutputIntermediate, true, "Write transformation for each level [default: only write final transformation]" );
00209     cl.EndGroup();
00210 
00211 #ifdef CMTK_USE_SQLITE
00212     cl.BeginGroup( "Database", "Image/Transformation Database" );
00213     cl.AddOption( Key( "db" ), &this->m_UpdateDB, "Path to image/transformation database that should be updated with the new registration and/or reformatted image." );
00214     cl.EndGroup();
00215 #endif
00216 
00217     cl.AddParameter( &clArg1, "ReferenceImage", "Reference (fixed) image path" )
00218       ->SetProperties( CommandLine::PROPS_IMAGE );
00219     cl.AddParameter( &clArg2, "FloatingImage", "Floating (moving) image path" )
00220       ->SetProperties( CommandLine::PROPS_IMAGE | CommandLine::PROPS_OPTIONAL);
00221     cl.AddParameter( &clArg3, "InitialXform", "Initial affine transformation from reference to floating image" )
00222       ->SetProperties( CommandLine::PROPS_NOXML | CommandLine::PROPS_XFORM | CommandLine::PROPS_OPTIONAL );
00223 
00224     cl.Parse( argc, argv );
00225     }
00226   catch ( const CommandLine::Exception& ex )
00227     {
00228     StdErr << ex << "\n";
00229     exit( 1 );
00230     }
00231 
00232   if ( (OptimizerStepFactor <= 0) || (OptimizerStepFactor >= 1) ) 
00233     {
00234     StdErr << "ERROR: step factor value " << OptimizerStepFactor << " is invalid. Must be in range (0..1)\n";
00235     exit( 1 );
00236     }
00237 
00238   if ( clArg2 ) 
00239     {
00240     this->SetInitialTransformation( AffineXform::SmartPtr( new AffineXform() ) );
00241     
00242     Study1 = const_cast<char*>( clArg1 );
00243     Study2 = const_cast<char*>( clArg2 );
00244 
00245     if ( clArg3 )
00246       {
00247       initialTransformationFile = clArg3;
00248       }
00249     }
00250   else 
00251     {
00252     InputStudylist = clArg1;
00253     
00254     if ( Verbose )
00255       fprintf( stderr, "Reading input studylist %s.\n", InputStudylist );
00256     
00257     ClassStream classStream( MountPoints::Translate(InputStudylist),"registration", ClassStream::READ );
00258     if ( ! classStream.IsValid() ) 
00259       {
00260       std::cerr << "Could not open studylist archive " << InputStudylist << ".\n";
00261       exit( 1 );
00262       }
00263     
00264     classStream.Seek ( "registration" );
00265     Study1 = classStream.ReadString( "reference_study" );
00266     Study2 = classStream.ReadString( "floating_study" );
00267     if ( Study2 )
00268       {
00269       AffineXform::SmartPtr affineXform;
00270       classStream >> affineXform;
00271       this->SetInitialTransformation( affineXform );
00272       }
00273     else
00274       {
00275       // legacy studylists have inverse transformation stored in them
00276       Study2 = classStream.ReadString( "model_study" );
00277       AffineXform::SmartPtr affineXform;
00278       classStream >> affineXform;
00279       this->SetInitialTransformation( affineXform->GetInverse() );
00280       }
00281     
00282     classStream.Close();
00283     }
00284 
00286   if ( initialTransformationFile ) 
00287     {
00288     Xform::SmartPtr initialXform( XformIO::Read( initialTransformationFile ) );
00289     AffineXform::SmartPtr affineXform = AffineXform::SmartPtr::DynamicCastFrom( initialXform );
00290     if ( affineXform )
00291       {
00292       this->SetInitialTransformation( affineXform );
00293       }
00294     else
00295       {
00296       InitialWarpXform = SplineWarpXform::SmartPtr::DynamicCastFrom( initialXform );
00297       }
00298     }
00299 
00300   // Did user ask for exchanged reference/floating images?
00301   if ( this->ForceSwitchVolumes ) 
00302     {
00303     std::swap( Study1, Study2 );
00304     this->SetInitialTransformation( AffineXform::SmartPtr( dynamic_cast<AffineXform*>( this->m_InitialTransformation->MakeInverse() ) ) );
00305     }
00306   
00307   UniformVolume::SmartPtr volume( VolumeIO::ReadOriented( Study1, Verbose ) );
00308   if ( !volume ) throw ConstructorFailed();
00309   this->SetVolume_1( UniformVolume::SmartPtr( this->m_PreprocessorRef.GetProcessedImage( volume ) ) );
00310 
00311   volume = UniformVolume::SmartPtr( VolumeIO::ReadOriented( Study2, Verbose ) );
00312   if ( !volume ) throw ConstructorFailed();
00313   this->SetVolume_2( UniformVolume::SmartPtr( this->m_PreprocessorFlt.GetProcessedImage( volume ) ) );
00314 
00315   AffineXform::SmartPtr affineXform( AffineXform::SmartPtr::DynamicCastFrom( this->m_InitialTransformation ) );
00316   if ( affineXform )
00317     {
00318     if ( affineXform->MetaKeyExists( META_SPACE ) && (affineXform->m_MetaInformation[META_SPACE] != AnatomicalOrientation::ORIENTATION_STANDARD ) )
00319       {
00320       TransformChangeFromSpaceAffine toStandardSpace( *affineXform, *(this->m_Volume_1), *(this->m_Volume_2), affineXform->m_MetaInformation[META_SPACE].c_str() );
00321       *affineXform = toStandardSpace.GetTransformation();
00322       affineXform->m_MetaInformation[META_SPACE] = AnatomicalOrientation::ORIENTATION_STANDARD;
00323       this->SetInitialTransformation( affineXform );
00324       }
00325     }
00326   
00327   if ( this->RigidityConstraintMapFilename )
00328     {
00329     UniformVolume::SmartPtr rigidityWeightMap( VolumeIO::ReadOriented( this->RigidityConstraintMapFilename, Verbose ) );
00330     if ( rigidityWeightMap )
00331       {
00332       this->SetRigidityConstraintMap( rigidityWeightMap );
00333       }
00334     else
00335       {
00336       StdErr << "ERROR: rigidity constraint mapcould not be read from " << this->RigidityConstraintMapFilename << "\n";
00337       exit( 1 );
00338       }
00339     }
00340 
00341   if ( forceOutsideFlag )
00342     {
00343     this->SetForceOutside( true, forceOutsideValue );
00344     }
00345 
00346   if ( Protocol )
00347     {
00348     RegistrationCallback::SmartPtr callback( new ProtocolCallback( Protocol ) );
00349     this->SetCallback( callback );
00350     }
00351 }
00352 
00353 ElasticRegistrationCommandLine::~ElasticRegistrationCommandLine ()
00354 {
00355 #ifdef HAVE_SIGRELSE
00356   // release signal handler
00357   sigrelse( SIGUSR1 );
00358 #endif
00359 }
00360 
00361 CallbackResult
00362 ElasticRegistrationCommandLine
00363 ::InitRegistration ()
00364 {
00365   CallbackResult result = this->Superclass::InitRegistration();
00366   if ( result != CALLBACK_OK )
00367     return result;
00368 
00369   if ( this->m_OutputIntermediate )
00370     this->OutputIntermediate();
00371   
00372   // register signal handler for intermediate result output.
00373   Self::StaticThis = this;
00374 #ifndef _MSC_VER
00375   signal( SIGUSR1, cmtkElasticRegistrationCommandLineDispatchSIGUSR1 );
00376 #endif
00377 
00378   return CALLBACK_OK;
00379 }
00380         
00381 void
00382 ElasticRegistrationCommandLine
00383 ::OutputResult
00384 ( const CoordinateVector* )
00385 {
00386   if ( Studylist ) 
00387     this->OutputWarp( Studylist );
00388 
00389   if ( this->m_OutputPathITK ) 
00390     {
00391     SplineWarpXformITKIO::Write( this->m_OutputPathITK, *(this->GetTransformation()), *(this->m_ReferenceVolume), *(this->m_FloatingVolume) );
00392     }
00393 
00394   if ( this->m_ReformattedImagePath )
00395     {
00396     VolumeIO::Write( *(this->GetReformattedFloatingImage()), this->m_ReformattedImagePath, this->Verbose );
00397     }
00398 
00399 #ifdef CMTK_USE_SQLITE
00400   if ( this->m_UpdateDB )
00401     {
00402     try
00403       {
00404       cmtk::ImageXformDB db( this->m_UpdateDB );
00405       
00406       if ( this->m_ReformattedImagePath )
00407         {
00408         db.AddImage( this->m_ReformattedImagePath, this->m_ReferenceVolume->GetMetaInfo( META_FS_PATH ) );
00409         }
00410       
00411       if ( this->Studylist )
00412         {
00413         if ( this->InputStudylist ) 
00414           {
00415           db.AddRefinedXform( this->Studylist, true /*invertible*/, this->InputStudylist, this->ForceSwitchVolumes );
00416           }
00417         else
00418           {
00419           db.AddImagePairXform( this->Studylist, true /*invertible*/, this->m_ReferenceVolume->GetMetaInfo( META_FS_PATH ), this->m_FloatingVolume->GetMetaInfo( META_FS_PATH ) );
00420           }
00421         }
00422       }
00423     catch ( const cmtk::ImageXformDB::Exception& ex )
00424       {
00425       StdErr << "DB ERROR: " << ex.what() << " on database " << this->m_UpdateDB << "\n";
00426       }
00427     }
00428 #endif
00429 }
00430 
00431 void
00432 ElasticRegistrationCommandLine
00433 ::EnterResolution
00434 ( CoordinateVector::SmartPtr& v, Functional::SmartPtr& f, 
00435   const int index, const int total )
00436 {
00437   if ( Verbose )
00438     fprintf( stderr, "\rEntering resolution level %d out of %d...\n", index, total );
00439   
00440   this->Superclass::EnterResolution( v, f, index, total );
00441 }
00442 
00443 int
00444 ElasticRegistrationCommandLine::DoneResolution
00445 ( CoordinateVector::SmartPtr& v, Functional::SmartPtr& f, const int index, const int total )
00446 {
00447   if ( this->m_OutputIntermediate )
00448     this->OutputIntermediate();
00449   return this->Superclass::DoneResolution( v, f, index, total );
00450 }
00451 
00452 void
00453 ElasticRegistrationCommandLine::OutputWarp ( const char* path ) const
00454 {
00455   ClassStream classStream( path, "studylist", ClassStream::WRITE );
00456   if ( ! classStream.IsValid() ) return;
00457 
00458   classStream.Begin( "studylist" );
00459   classStream.WriteInt( "num_sources", 2 );
00460   classStream.End();
00461 
00462   classStream.Begin( "source" );
00463   classStream.WriteString( "studyname", CompressedStream::GetBaseName( Study1 ) );
00464   classStream.End();
00465 
00466   classStream.Begin( "source" );
00467   classStream.WriteString( "studyname", CompressedStream::GetBaseName( Study2 ) );
00468   classStream.End();
00469 
00470   classStream.Close();
00471 
00472   classStream.Open( path, "settings", ClassStream::WRITE );
00473   classStream.WriteInt( "algorithm", this->m_Algorithm );
00474   classStream.WriteBool( "use_maxnorm", UseMaxNorm );
00475   classStream.WriteDouble( "exploration", this->m_Exploration );
00476   classStream.WriteDouble( "accuracy", this->m_Accuracy );
00477   classStream.WriteDouble( "min_sampling", this->m_Sampling );
00478   classStream.WriteDouble( "coarsest_resolution", CoarsestResolution );
00479   classStream.WriteBool( "use_original_data", this->m_UseOriginalData );
00480   classStream.WriteBool( "fast_mode", this->m_FastMode );
00481   classStream.WriteInt( "metric", this->m_Metric );
00482   classStream.WriteDouble( "optimizer_step_factor", OptimizerStepFactor );
00483   classStream.WriteDouble( "grid_spacing", this->m_GridSpacing );
00484   classStream.WriteInt( "ignore_edge", IgnoreEdge );
00485   classStream.WriteDouble( "jacobian_constraint_weight", this->m_JacobianConstraintWeight );
00486   classStream.WriteDouble( "rigidity_constraint_weight", this->m_RigidityConstraintWeight );
00487   if ( this->RigidityConstraintMapFilename )
00488     {
00489     classStream.WriteString( "rigidity_constraint_map_filename", RigidityConstraintMapFilename );
00490     }
00491   classStream.WriteDouble( "energy_constraint_weight", this->m_GridEnergyWeight );
00492   classStream.WriteDouble( "inverse_consistency_weight", this->m_InverseConsistencyWeight );
00493   classStream.WriteDouble( "weight_relaxation", this->m_RelaxWeight );
00494   classStream.WriteDouble( "landmark_error_weight", this->m_LandmarkErrorWeight );
00495   classStream.WriteBool( "force_switch", this->ForceSwitchVolumes );
00496   classStream.WriteInt( "refine_grid", this->m_RefineGrid );
00497   classStream.WriteBool( "delay_refine_grid", this->m_DelayRefineGrid );
00498   classStream.WriteBool( "adaptive_fix_parameters", this->m_AdaptiveFixParameters );
00499   classStream.WriteDouble( "adaptive_fix_parameters_thresh", this->m_AdaptiveFixThreshFactor );
00500 
00501   this->m_PreprocessorRef.WriteSettings( classStream );  
00502   this->m_PreprocessorFlt.WriteSettings( classStream );  
00503 
00504   classStream.Close();
00505       
00506   classStream.Open( path, "statistics", ClassStream::WRITE );
00507   classStream.WriteDouble( "time_level", this->GetLevelElapsedTime() );
00508   classStream.WriteDouble( "time_total", this->GetTotalElapsedTime() );
00509   classStream.WriteDouble( "walltime_level", this->GetLevelElapsedWalltime() );
00510   classStream.WriteDouble( "walltime_total", this->GetTotalElapsedWalltime() );
00511   classStream.WriteDouble( "thread_time_level", this->GetThreadLevelElapsedTime() );
00512   classStream.WriteDouble( "thread_time_total", this->GetThreadTotalElapsedTime() );
00513   classStream.WriteInt( "number_of_threads", Threads::NumberOfThreads );
00514   classStream.WriteInt( "number_of_cpus", Threads::GetNumberOfProcessors() );
00515 
00516 #ifndef _MSC_VER
00517   struct utsname name;
00518   if ( uname( &name ) >= 0 ) 
00519     {
00520     classStream.WriteString( "host", name.nodename );
00521     classStream.WriteString( "system", name.sysname );
00522     }
00523 #endif
00524   classStream.Close();
00525 
00526   const WarpXform::SmartPtr warp = WarpXform::SmartPtr::DynamicCastFrom( this->m_Xform );
00527   if ( warp ) 
00528     {
00529     classStream.Open( path, "registration", ClassStream::WRITE );
00530     if ( classStream.IsValid() ) 
00531       {
00532       classStream.Begin( "registration" );
00533       classStream.WriteString( "reference_study", CompressedStream::GetBaseName( Study1 ) );
00534       classStream.WriteString( "floating_study", CompressedStream::GetBaseName( Study2 ) );
00535       
00536       if ( warp->GetInitialAffineXform() ) 
00537         {
00538         classStream << (*warp->GetInitialAffineXform());
00539         } 
00540       else 
00541         {
00542         classStream << *this->m_InitialTransformation;
00543         }
00544       classStream << warp;
00545       classStream.End();
00546       }
00547     classStream.Close();
00548     }
00549 }
00550 
00551 void
00552 ElasticRegistrationCommandLine::OutputIntermediate( const bool incrementCount )
00553 {
00554   char path[PATH_MAX];
00555   if ( Studylist ) 
00556     {
00557     snprintf( path, sizeof( path ), "%s/level-%02d.list", Studylist, IntermediateResultIndex );
00558     } 
00559   else
00560     {
00561     snprintf( path, sizeof( path ), "level-%02d.list", IntermediateResultIndex );
00562     }
00563   this->OutputWarp( path );
00564   
00565   if ( incrementCount )
00566     ++IntermediateResultIndex;
00567 }
00568 
00569 CallbackResult ElasticRegistrationCommandLine::Register ()
00570 {
00571   const double baselineTime = Timers::GetTimeProcess();
00572   CallbackResult Result = this->Superclass::Register();
00573   const int elapsed = static_cast<int>( Timers::GetTimeProcess() - baselineTime );
00574 
00575   if ( Time ) 
00576     {
00577     FILE *tfp = fopen( Time, "w" );
00578     
00579     if ( tfp ) 
00580       {
00581       fprintf( tfp, "%d\n", elapsed );
00582       fclose( tfp );
00583       } 
00584     else
00585       {
00586       std::cerr << "Could not open time file " << Time << "\n";
00587       }
00588     }
00589   
00590   return Result;
00591 }
00592 
00593 } // namespace cmtk
00594 
00595 void
00596 cmtkElasticRegistrationCommandLineDispatchSIGUSR1( int sig )
00597 {
00598   fprintf( stderr, "Received USR1 (%d) signal. Writing intermediate result #%d.\nNote that this result is not final.\n", sig, cmtk::ElasticRegistrationCommandLine::StaticThis->IntermediateResultIndex );
00599 
00600 #ifndef _MSC_VER
00601   // set signal handler again.
00602   signal( sig, cmtkElasticRegistrationCommandLineDispatchSIGUSR1 );
00603 #endif
00604   
00605   // write intermediate result. give "false" flag for index increment to 
00606   // preserve to final numbering of levels.
00607   cmtk::ElasticRegistrationCommandLine::StaticThis->OutputIntermediate( true /* Increment count*/ );
00608 }
00609 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines