00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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;
00121 const char* clArg2 = NULL;
00122 const char* clArg3 = NULL;
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
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
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
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
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 , this->InputStudylist, this->ForceSwitchVolumes );
00416 }
00417 else
00418 {
00419 db.AddImagePairXform( this->Studylist, true , 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 }
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
00602 signal( sig, cmtkElasticRegistrationCommandLineDispatchSIGUSR1 );
00603 #endif
00604
00605
00606
00607 cmtk::ElasticRegistrationCommandLine::StaticThis->OutputIntermediate( true );
00608 }
00609