cmtkImageSymmetryPlaneCommandLineBase.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: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkImageSymmetryPlaneCommandLineBase.h"
00034 
00035 #include <IO/cmtkClassStream.h>
00036 #include <IO/cmtkVolumeIO.h>
00037 #include <IO/cmtkXformIO.h>
00038 
00039 #include <Registration/cmtkBestNeighbourOptimizer.h>
00040 #include <Registration/cmtkReformatVolume.h>
00041 
00042 #include <System/cmtkProgress.h>
00043 #include <System/cmtkProgressConsole.h>
00044 
00045 cmtk::ImageSymmetryPlaneCommandLineBase
00046 ::ImageSymmetryPlaneCommandLineBase()
00047   : m_Verbose( false ),
00048     m_MinValueSet( false ),
00049     m_MaxValueSet( false ),
00050     m_Sampling( 1.0 ),
00051     m_Accuracy( 0.1 ),
00052     m_Interpolation( Interpolators::LINEAR ),
00053     m_Levels( 4 ),
00054     m_DisableOptimization( false ),
00055     m_FixOffset( false ),
00056     m_MirrorOutFile( NULL ),
00057     m_AlignedOutFile( NULL ),
00058     m_MarkPlaneAligned( false ),
00059     m_MarkedOutFile( NULL ),
00060     m_DifferenceOutFile( NULL ),
00061     m_WriteXformPath( NULL ),
00062     m_MarkPlaneValue( 4095 ),
00063     m_PadOutValueSet( false ),
00064     m_SymmetryOutFileName( NULL ),
00065     m_SymmetryParameters( NULL ),
00066     m_SymmetryParametersFile( NULL ),
00067     m_InFileName( NULL ),
00068     m_InitialPlane( SYMPL_INIT_YZ ),
00069     m_CommandLine( CommandLine::PROPS_XML )
00070 {
00071   this->m_CommandLine.SetProgramInfo( CommandLine::PRG_TITLE, "Symmetry plane computation" );
00072   this->m_CommandLine.SetProgramInfo( CommandLine::PRG_DESCR, "Compute the approximate symmetry plane of an image to determine, for example, the mid-sagittal plane in human brain images. "
00073                                       "Various forms of output are supported, e.g., writing the input image with the symmetry plane drawn into it, or the input image realigned along the symmetry plane." );
00074   this->m_CommandLine.SetProgramInfo( CommandLine::PRG_CATEG, "CMTK.Registration" );
00075   
00076   typedef CommandLine::Key Key;
00077   this->m_CommandLine.AddSwitch( Key( 'v', "verbose" ), &this->m_Verbose, true, "Turn on verbosity mode." )->SetProperties( CommandLine::PROPS_NOXML );
00078   
00079   this->m_CommandLine.BeginGroup( "Optimization", "Optimization" );
00080   this->m_CommandLine.AddOption( Key( 'a', "accuracy" ), &this->m_Accuracy, "Accuracy (final optimization step size in [mm]." );
00081   this->m_CommandLine.AddOption( Key( 's', "sampling" ), &this->m_Sampling, "Resampled image resolution. This is the resolution [in mm] of the first (finest) resampled image in the multi-scale pyramid, "
00082                                  "which is derived directly from the original full-resolution images.");
00083   this->m_CommandLine.AddOption( Key( 'l', "levels" ), &this->m_Levels, "Number of resolution levels. The algorithm will create (levels-1) resampled images with increasingly coarse resolution and use these "
00084                                  "in successive order of increasing resolution before using the original images at the final level." );
00085   this->m_CommandLine.AddSwitch( Key( "fix-offset" ), &this->m_FixOffset, true, "Fix symmetry plane offset. Reduces computation time and forces symmetry plane to cross center of mass, but may lead to less-than-accurate result." );
00086   this->m_CommandLine.EndGroup();
00087   
00088   this->m_CommandLine.BeginGroup( "Initial", "Initial approximate symmetry plane orientation" );
00089   CommandLine::EnumGroup<InitialPlaneEnum>::SmartPtr
00090     initialPlane = this->m_CommandLine.AddEnum( "initial-plane", &this->m_InitialPlane, "Initial orientation of symmetry plane. This should be the closest orthogonal plane to the expected actual symmetry plane." );
00091   initialPlane->AddSwitch( Key( "initial-axial" ), SYMPL_INIT_XY, "Approximately axial symmetry" );
00092   initialPlane->AddSwitch( Key( "initial-coronal" ), SYMPL_INIT_XZ, "Approximately coronal symmetry" );
00093   initialPlane->AddSwitch( Key( "initial-sagittal" ), SYMPL_INIT_YZ, "Approximately sagittal symmetry" );
00094   initialPlane->AddSwitch( Key( "initial-xy" ), SYMPL_INIT_XY, "Approximately XY plane symmetry" );
00095   initialPlane->AddSwitch( Key( "initial-xz" ), SYMPL_INIT_XZ, "Approximately XZ plane symmetry" );
00096   initialPlane->AddSwitch( Key( "initial-yz" ), SYMPL_INIT_YZ, "Approximately YZ plane symmetry" );
00097   this->m_CommandLine.EndGroup();
00098   
00099   this->m_CommandLine.BeginGroup( "Pre-computed", "Pre-computed symmetry" )->SetProperties( CommandLine::PROPS_ADVANCED | CommandLine::PROPS_NOXML );
00100   this->m_CommandLine.AddOption( Key( "output-only" ), &this->m_SymmetryParameters, "Give symmetry parameters [Rho Theta Phi] as option, skip search.", &this->m_DisableOptimization );
00101   this->m_CommandLine.AddOption( Key( "output-only-file" ), &this->m_SymmetryParametersFile, "Read symmetry parameters from file, skip search.", &this->m_DisableOptimization );
00102   this->m_CommandLine.EndGroup();
00103   
00104   this->m_CommandLine.BeginGroup( "Preprocessing", "Data pre-processing" )->SetProperties( CommandLine::PROPS_ADVANCED );
00105   this->m_CommandLine.AddOption( Key( "min-value" ), &this->m_MinValue, "Force minumum data value.", &this->m_MinValueSet );
00106   this->m_CommandLine.AddOption( Key( "max-value" ), &this->m_MaxValue, "Force maximum data value.", &this->m_MaxValueSet );
00107   this->m_CommandLine.EndGroup();
00108   
00109   this->m_CommandLine.BeginGroup( "OutputImages", "Output of Images" );
00110   CommandLine::EnumGroup<Interpolators::InterpolationEnum>::SmartPtr interpGroup = this->m_CommandLine.AddEnum( "interpolation", &this->m_Interpolation, "Interpolation method used for reformatted output data" );
00111   interpGroup->AddSwitch( Key( 'L', "linear" ), Interpolators::LINEAR, "Use linear image interpolation for output." );
00112   interpGroup->AddSwitch( Key( 'C', "cubic" ), Interpolators::CUBIC, "Use cubic image interpolation for output." );
00113   interpGroup->AddSwitch( Key( 'S', "sinc" ), Interpolators::COSINE_SINC, "Use cosine-windowed sinc image interpolation for output." );
00114   
00115   this->m_CommandLine.AddOption( Key( 'P', "pad-out" ), &this->m_PadOutValue, "Padding value for output images.", &this->m_PadOutValueSet )->SetProperties( CommandLine::PROPS_ADVANCED );
00116   this->m_CommandLine.AddOption( Key( "mark-value" ), &this->m_MarkPlaneValue, "Data value to mark (draw) symmetry plane." );
00117   this->m_CommandLine.AddOption( Key( "write-marked" ), &this->m_MarkedOutFile, "File name for output image with marked symmetry plane." )->SetProperties( CommandLine::PROPS_IMAGE | CommandLine::PROPS_OUTPUT );
00118   this->m_CommandLine.AddOption( Key( "write-aligned" ), &this->m_AlignedOutFile, "File name for symmetry plane-aligned output image." )->SetProperties( CommandLine::PROPS_IMAGE | CommandLine::PROPS_OUTPUT );
00119   this->m_CommandLine.AddSwitch( Key( "mark-aligned" ), &this->m_MarkPlaneAligned, true, "Mark symmetry plane in aligned output image." );
00120   this->m_CommandLine.AddOption( Key( "write-subtract" ), &this->m_DifferenceOutFile, "File name for mirror subtraction image." )->SetProperties( CommandLine::PROPS_IMAGE | CommandLine::PROPS_OUTPUT );
00121   this->m_CommandLine.AddOption( Key( "write-mirror" ), &this->m_MirrorOutFile, "File name for image mirrored w.r.t. symmetry plane." )->SetProperties( CommandLine::PROPS_IMAGE | CommandLine::PROPS_OUTPUT );
00122   this->m_CommandLine.EndGroup();
00123   
00124   this->m_CommandLine.BeginGroup( "OutputParameters", "Output of Parameters" )->SetProperties( CommandLine::PROPS_ADVANCED );
00125   this->m_CommandLine.AddOption( Key( 'o', "outfile" ), &this->m_SymmetryOutFileName, "File name for symmetry plane parameter output." )->SetProperties( CommandLine::PROPS_FILENAME | CommandLine::PROPS_OUTPUT );
00126   this->m_CommandLine.AddOption( Key( "write-xform" ), &this->m_WriteXformPath, "Write affine alignment transformation to file" )
00127     ->SetProperties( CommandLine::PROPS_XFORM | CommandLine::PROPS_OUTPUT )
00128     ->SetAttribute( "reference", "InputImage" );
00129   this->m_CommandLine.EndGroup();
00130   
00131   this->m_CommandLine.AddParameter( &this->m_InFileName, "InputImage", "Input image path" )->SetProperties( CommandLine::PROPS_IMAGE );
00132 }
00133 
00134 int
00135 cmtk::ImageSymmetryPlaneCommandLineBase
00136 ::Run( const int argc, const char* argv[] )
00137 {
00138   if ( ! this->ParseCommandLine( argc, argv ) )
00139     return 2;
00140   
00141   UniformVolume::SmartPtr originalVolume( VolumeIO::ReadOriented( this->m_InFileName, this->m_Verbose ) );
00142   if ( !originalVolume ) 
00143     {
00144     StdErr.printf( "Could not read image file %s\n", this->m_InFileName );
00145     return 1;
00146     }
00147 
00148   CoordinateVector v( 6 );
00149   // initialize plane as the mid-sagittal with respect to image orientation --
00150   // distance from coordinate origin (image center) is 0:
00151   v[0] = 0;
00152   // and angles are chosen so that the plane normal is (1,0,0)
00153   switch ( this->m_InitialPlane )
00154     {
00155     case SYMPL_INIT_XY:
00156       v[1] = 0;
00157       v[2] = 0;
00158       break;
00159     case SYMPL_INIT_XZ:
00160       v[1] = 90;
00161       v[2] = 90;
00162       break;
00163     default:
00164     case SYMPL_INIT_YZ:
00165       v[1] = 0;
00166       v[2] = 90;
00167       break;
00168     }
00169   
00170   // set center of volume (crop region) as coordinate origin.
00171   Vector3D center = originalVolume->GetCenterOfMass();
00172   v[3] = center[0]; v[4] = center[1]; v[5] = center[2];
00173 
00174   if ( this->m_DisableOptimization ) 
00175     {
00176     v[0] = this->m_Rho;
00177     v[1] = this->m_Theta.Value();
00178     v[2] = this->m_Phi.Value();
00179     } 
00180   else
00181     {
00182     BestNeighbourOptimizer optimizer;
00183 
00184     // Instantiate programm progress indicator.
00185     ProgressConsole progressIndicator( "Symmetry Plane Computation" );
00186     Progress::Begin( 0, this->m_Levels, 1, "Symmetry Plane Computation" );
00187     
00188     for ( int level = 0; level < this->m_Levels; ++level ) 
00189       {      
00190       UniformVolume::SmartPtr volume;
00191       if ( level < this->m_Levels-1 ) 
00192         {
00193         Types::Coordinate voxelSize = this->m_Sampling * pow( 2.0, (this->m_Levels-level-2) );
00194         if ( this->m_Verbose )
00195           fprintf( stderr, "Entering level %d out of %d (%.2f mm voxel size)\n", level+1, this->m_Levels, voxelSize );
00196         
00197         volume = UniformVolume::SmartPtr( new UniformVolume( *originalVolume, voxelSize ) );
00198         } 
00199       else
00200         {
00201         if ( this->m_Verbose )
00202           fprintf(stderr,"Entering level %d out of %d (original voxel size)\n", level+1, this->m_Levels );
00203         volume = originalVolume; 
00204         }
00205       
00206       ImageSymmetryPlaneFunctionalBase::SmartPtr functional;
00207       if ( this->m_MinValueSet || this->m_MaxValueSet ) 
00208         {
00209         Types::DataItemRange valueRange = volume->GetData()->GetRange();
00210         
00211         if ( this->m_MinValueSet ) 
00212           valueRange.m_LowerBound = this->m_MinValue;
00213         if ( this->m_MaxValueSet ) 
00214           valueRange.m_UpperBound = this->m_MaxValue;
00215         
00216         functional = this->CreateFunctional( volume, valueRange );
00217         } 
00218       else
00219         {
00220         functional = this->CreateFunctional( volume );
00221         }
00222       
00223       functional->SetFixOffset( this->m_FixOffset );
00224       
00225       optimizer.SetFunctional( functional );
00226       optimizer.Optimize( v, pow( 2.0, this->m_Levels-level-1 ), this->m_Accuracy * pow( 2.0, this->m_Levels-level-1 ) );
00227 
00228       Progress::SetProgress( level );
00229       }
00230 
00231     Progress::Done();
00232 
00233     if ( this->m_Verbose )
00234       fprintf( stdout, "rho=%f, theta=%f, phi=%f\n", v[0], v[1], v[2] );
00235     }
00236   
00237   this->m_SymmetryPlane.SetParameters( v );
00238   
00239   if ( this->m_SymmetryOutFileName )
00240     {
00241     ClassStream stream( this->m_SymmetryOutFileName, ClassStream::WRITE );
00242     stream << this->m_SymmetryPlane;
00243     stream.Close();
00244     }
00245 
00246   if ( this->m_AlignedOutFile ) 
00247     this->WriteAligned( originalVolume );
00248 
00249   if ( this->m_MarkedOutFile ) 
00250     this->WriteMarkPlane( originalVolume );
00251 
00252   if ( this->m_DifferenceOutFile )
00253     this->WriteDifference( originalVolume );
00254 
00255   if ( this->m_MirrorOutFile )
00256     WriteMirror( originalVolume );
00257 
00258   if ( this->m_WriteXformPath )
00259     {
00260     AffineXform::SmartPtr alignment( this->m_SymmetryPlane.GetAlignmentXform( 0 ) );
00261     XformIO::Write( alignment, this->m_WriteXformPath, this->m_Verbose );
00262     }
00263   
00264   return 0;
00265 }
00266 
00267 bool
00268 cmtk::ImageSymmetryPlaneCommandLineBase
00269 ::ParseCommandLine( const int argc, const char* argv[] )
00270 {
00271   try
00272     {
00273     if ( ! this->m_CommandLine.Parse( argc, argv ) ) return false;
00274     
00275     if ( this->m_SymmetryParameters ) 
00276       {
00277       double rho, theta, phi;
00278       if ( 3 == sscanf( this->m_SymmetryParameters, "%lf %lf %lf", &rho, &theta, &phi ) ) 
00279         {
00280         this->m_Rho = rho; 
00281         this->m_Theta = Units::Degrees( theta );
00282         this->m_Phi = Units::Degrees( phi );
00283         }
00284       }
00285     
00286     if ( this->m_SymmetryParametersFile ) 
00287       {
00288       ClassStream inStream( this->m_SymmetryParametersFile, ClassStream::READ );
00289       if ( inStream.IsValid() ) 
00290         {
00291         ParametricPlane *plane = NULL;
00292         inStream >> plane;
00293         this->m_Rho = plane->GetRho(); 
00294         this->m_Theta = plane->GetTheta();
00295         this->m_Phi = plane->GetPhi();
00296         delete plane;
00297         } 
00298       else
00299         {
00300         StdErr.printf( "ERROR: Could not open symmetry parameter file %s\n", this->m_SymmetryParametersFile );
00301         }
00302       }
00303     }
00304   catch ( const CommandLine::Exception& ex ) 
00305     {
00306     StdErr << ex << "\n";
00307     return false;
00308     }
00309   
00310   return true;
00311 }
00312 
00313 void
00314 cmtk::ImageSymmetryPlaneCommandLineBase
00315 ::WriteDifference
00316 ( UniformVolume::SmartConstPtr& originalVolume ) const
00317 {
00318   UniformVolume::SmartPtr diffVolume( originalVolume->CloneGrid() );
00319   const TypedArray* originalData = originalVolume->GetData();
00320   TypedArray::SmartPtr diffData = TypedArray::SmartPtr( TypedArray::Create( GetSignedDataType( originalData->GetType() ), originalData->GetDataSize() ) );
00321   diffVolume->SetData( diffData );
00322 
00323   Types::DataItem dataV, dataW;
00324 
00325   const UniformVolumeInterpolatorBase::SmartPtr interpolator( ReformatVolume::CreateInterpolator( this->m_Interpolation, originalVolume ) );;
00326   
00327   int offset = 0;
00328   for ( int z = 0; z < originalVolume->GetDims()[2]; ++z )
00329     for ( int y = 0; y < originalVolume->GetDims()[1]; ++y )
00330       for ( int x = 0; x < originalVolume->GetDims()[0]; ++x, ++offset ) 
00331         {
00332         if ( ! originalData->Get( dataV, offset ) ) 
00333           {
00334           diffData->SetPaddingAt( offset );
00335           continue;
00336           }
00337         UniformVolume::CoordinateVectorType w = originalVolume->GetGridLocation( x, y, z );
00338         this->m_SymmetryPlane.MirrorInPlace( w );
00339 
00340         if ( interpolator->GetDataAt( w, dataW ) )
00341           {
00342           diffData->Set( fabs( dataV - dataW ), offset );
00343           }
00344         else
00345           {
00346           diffData->SetPaddingAt( offset );
00347           }
00348         }
00349   
00350   VolumeIO::Write( *diffVolume, this->m_DifferenceOutFile );
00351 }
00352 
00353 void
00354 cmtk::ImageSymmetryPlaneCommandLineBase
00355 ::WriteMirror
00356 ( UniformVolume::SmartConstPtr& originalVolume ) const
00357 {
00358   TypedArray::SmartPtr mirrorData = TypedArray::Create( originalVolume->GetData()->GetType(), originalVolume->GetData()->GetDataSize() );
00359 
00360   Types::DataItem data;
00361 
00362   const UniformVolumeInterpolatorBase::SmartPtr interpolator( ReformatVolume::CreateInterpolator( this->m_Interpolation, originalVolume ) );;
00363   
00364   int offset = 0;
00365   for ( int z = 0; z < originalVolume->GetDims()[2]; ++z ) 
00366     {
00367     for ( int y = 0; y < originalVolume->GetDims()[1]; ++y )
00368       for ( int x = 0; x < originalVolume->GetDims()[0]; ++x, ++offset ) 
00369         {
00370         UniformVolume::CoordinateVectorType v = originalVolume->GetGridLocation( x, y, z );
00371         this->m_SymmetryPlane.MirrorInPlace( v );
00372 
00373         if ( interpolator->GetDataAt( v, data ) )
00374           {
00375           mirrorData->Set( data, offset );
00376           }
00377         else
00378           {
00379           mirrorData->SetPaddingAt( offset );
00380           }
00381         }
00382     }
00383 
00384   UniformVolume::SmartPtr mirrorVolume( originalVolume->CloneGrid() );
00385   mirrorVolume->SetData( mirrorData );
00386   VolumeIO::Write( *mirrorVolume, this->m_MirrorOutFile );
00387 }
00388 
00389 void
00390 cmtk::ImageSymmetryPlaneCommandLineBase
00391 ::WriteMarkPlane
00392 ( UniformVolume::SmartConstPtr& originalVolume ) const
00393 {
00394   UniformVolume::SmartPtr markVolume( originalVolume->CloneGrid() );
00395   TypedArray::SmartPtr markData( originalVolume->GetData()->Clone() );
00396   markVolume->SetData( markData );
00397 
00398   int offset = 0;
00399   for ( int z = 0; z < originalVolume->GetDims()[2]; ++z ) 
00400     {
00401     for ( int y = 0; y < originalVolume->GetDims()[1]; ++y ) 
00402       {
00403       int currentSideOfPlane = 0;
00404       for ( int x = 0; x < originalVolume->GetDims()[0]; ++x, ++offset ) 
00405         {
00406         int newSideOfPlane = this->m_SymmetryPlane.GetWhichSide( originalVolume->GetGridLocation( x, y, z ) );
00407         if ( ( newSideOfPlane != currentSideOfPlane ) && x )
00408           markData->Set( this->m_MarkPlaneValue, offset );
00409         currentSideOfPlane = newSideOfPlane;
00410         }
00411       }    
00412     }
00413 
00414   VolumeIO::Write( *markVolume, this->m_MarkedOutFile );
00415 }
00416 
00417 void
00418 cmtk::ImageSymmetryPlaneCommandLineBase
00419 ::WriteAligned
00420 ( UniformVolume::SmartConstPtr& originalVolume ) const
00421 {
00422   const TypedArray* originalData = originalVolume->GetData();
00423 
00424   TypedArray::SmartPtr alignData = TypedArray::Create( originalData->GetType(), originalData->GetDataSize() );
00425   if ( this->m_PadOutValueSet )
00426     {
00427     alignData->SetPaddingValue( this->m_PadOutValue );
00428     }
00429 
00430   UniformVolume::SmartPtr alignVolume( originalVolume->CloneGrid() );
00431   alignVolume->SetData( alignData );
00432 
00433   const Types::DataItem maxData = originalData->GetRange().m_UpperBound;
00434 
00435   Types::DataItem data;
00436 
00437   int normalAxis = 0;
00438   switch ( this->m_InitialPlane )
00439     {
00440     case SYMPL_INIT_XY: normalAxis = 2; break;
00441     case SYMPL_INIT_XZ: normalAxis = 1; break;
00442     case SYMPL_INIT_YZ: normalAxis = 0; break;
00443     }
00444 
00445   const UniformVolumeInterpolatorBase::SmartPtr interpolator( ReformatVolume::CreateInterpolator( this->m_Interpolation, originalVolume ) );;
00446   
00447   AffineXform::SmartPtr alignment( this->m_SymmetryPlane.GetAlignmentXform( normalAxis ) );
00448   int offset = 0;
00449   for ( int z = 0; z < originalVolume->GetDims()[2]; ++z ) 
00450     {
00451     for ( int y = 0; y < originalVolume->GetDims()[1]; ++y ) 
00452       {
00453       for ( int x = 0; x < originalVolume->GetDims()[0]; ++x, ++offset ) 
00454         {
00455         UniformVolume::CoordinateVectorType v = originalVolume->GetGridLocation( x, y, z );
00456         alignment->ApplyInPlace( v );
00457 
00458         if ( interpolator->GetDataAt( v, data ) )
00459           {
00460           if ( this->m_MarkPlaneAligned && (x == ( originalVolume->GetDims()[0] / 2 )) )
00461             alignData->Set( 2 * maxData, offset );
00462           else
00463             alignData->Set( data, offset );
00464           }
00465         else
00466           {
00467           alignData->SetPaddingAt( offset );
00468           }
00469         }
00470       }
00471     }
00472 
00473   VolumeIO::Write( *alignVolume, this->m_AlignedOutFile );
00474 }
00475 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines