cmtkAffineXform.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: 2429 $
00026 //
00027 //  $LastChangedDate: 2010-10-08 16:18:42 -0700 (Fri, 08 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include <Base/cmtkAffineXform.h>
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Base/cmtkUniformVolume.h>
00037 
00038 #include <System/cmtkConsole.h>
00039 
00040 #include <algorithm>
00041 
00042 namespace
00043 cmtk
00044 {
00045 
00048 
00049 void
00050 AffineXform::MakeIdentityXform () 
00051 {
00052   this->m_ParameterVector->Clear();
00053   Types::Coordinate* scales = this->RetScales();
00054   if ( ! m_LogScaleFactors )
00055     scales[0] = scales[1] = scales[2] = 1;
00056   this->ComposeMatrix();
00057 }
00058 
00059 AffineXform::AffineXform ( const AffineXform& other ) :
00060   Xform( other ),
00061   Matrix( NULL ), 
00062   m_LogScaleFactors( false ),
00063   InverseXform( NULL )
00064 { 
00065   this->AllocateParameterVector( TotalNumberOfParameters );
00066   (*this->m_ParameterVector) = (*other.m_ParameterVector);
00067   this->m_LogScaleFactors = other.m_LogScaleFactors;
00068   this->NumberDOFs = other.NumberDOFs;
00069   this->ComposeMatrix();
00070 }
00071 
00072 AffineXform::AffineXform
00073 ( const Types::Coordinate matrix[4][4], const Types::Coordinate* center ) :
00074   Matrix( &matrix[0][0] ), 
00075   m_LogScaleFactors( false ),
00076   InverseXform( NULL )
00077 {
00078   this->AllocateParameterVector( TotalNumberOfParameters );
00079   this->NumberDOFs = this->DefaultNumberOfDOFs();
00080   if ( center )
00081     memcpy( this->RetCenter(), center, 3 * sizeof( Types::Coordinate ) );
00082   else
00083     memset( this->RetCenter(), 0, 3 * sizeof( Types::Coordinate ) );
00084   this->DecomposeMatrix();
00085 }
00086 
00087 AffineXform::AffineXform
00088 ( const MatrixType& matrix, const Types::Coordinate* center ) :
00089   Matrix( matrix ), 
00090   m_LogScaleFactors( false ),
00091   InverseXform( NULL )
00092 {
00093   this->AllocateParameterVector( TotalNumberOfParameters );
00094   this->NumberDOFs = this->DefaultNumberOfDOFs();
00095   if ( center )
00096     memcpy( this->RetCenter(), center, 3 * sizeof( Types::Coordinate ) );
00097   else
00098     memset( this->RetCenter(), 0, 3 * sizeof( Types::Coordinate ) );
00099   this->DecomposeMatrix();
00100 }
00101 
00102 AffineXform::AffineXform
00103 ( const Types::Coordinate matrix[4][4], const Types::Coordinate xlate[3],
00104   const Types::Coordinate center[3] ) :
00105   Matrix( &matrix[0][0] ), 
00106   m_LogScaleFactors( false ),
00107   InverseXform( NULL )
00108 {
00109   this->AllocateParameterVector( TotalNumberOfParameters );
00110   this->NumberDOFs = this->DefaultNumberOfDOFs();
00111   Types::Coordinate cM[3] = 
00112     {
00113       center[0]*Matrix[0][0] + center[1]*Matrix[1][0] + center[2]*Matrix[2][0],
00114       center[0]*Matrix[0][1] + center[1]*Matrix[1][1] + center[2]*Matrix[2][1],
00115       center[0]*Matrix[0][2] + center[1]*Matrix[1][2] + center[2]*Matrix[2][2]
00116     };
00117   
00118   Matrix[3][0] = xlate[0] + center[0] - cM[0];
00119   Matrix[3][1] = xlate[1] + center[1] - cM[1];
00120   Matrix[3][2] = xlate[2] + center[2] - cM[2];
00121 
00122   this->Matrix.Decompose( this->m_Parameters, center, this->m_LogScaleFactors );
00123 }
00124 
00125 AffineXform& 
00126 AffineXform::operator=( const AffineXform& other )
00127 {
00128   (*this->m_ParameterVector) = (*other.m_ParameterVector);
00129   this->NumberDOFs = other.NumberDOFs;
00130   this->m_LogScaleFactors = other.m_LogScaleFactors;
00131   this->ComposeMatrix();
00132   return *this;
00133 }
00134 
00135 void
00136 AffineXform::SetNumberDOFs ( const int numberDOFs ) 
00137 {
00138   this->NumberDOFs = numberDOFs; 
00139   if ( this->NumberDOFs == 7 )
00140     {
00141     this->m_Parameters[8] = (this->m_Parameters[7] = this->m_Parameters[6]);
00142     this->ComposeMatrix();
00143     }
00144 }
00145 
00146 void
00147 AffineXform::SetUseLogScaleFactors( const bool logScaleFactors )
00148 {
00149   if ( logScaleFactors != this->m_LogScaleFactors )
00150     {
00151     if ( logScaleFactors )
00152       {
00153       for ( int i = 6; i < 9; ++i )
00154         this->m_Parameters[i] = log( this->m_Parameters[i] );
00155       }
00156     else
00157       {
00158       for ( int i = 6; i < 9; ++i )
00159         this->m_Parameters[i] = exp( this->m_Parameters[i] );     
00160       }
00161     this->m_LogScaleFactors = logScaleFactors;
00162     }
00163 }
00164 
00165 void
00166 AffineXform::ComposeMatrix () 
00167 {
00168   // For 7 parameter form (rigid plus global scaling) be sure to use equal
00169   // scalings for all coordinates.
00170   if ( this->NumberDOFs == 7 ) 
00171     this->m_Parameters[8] = (this->m_Parameters[7] = this->m_Parameters[6]);
00172     
00173   // Now build matrix.
00174   this->Matrix.Compose( this->m_Parameters, this->m_LogScaleFactors );
00175   this->UpdateInverse();
00176 }
00177 
00178 bool
00179 AffineXform::DecomposeMatrix () 
00180 {
00181   return this->Matrix.Decompose( this->m_Parameters, this->RetCenter(), this->m_LogScaleFactors );
00182 }
00183 
00184 AffineXform::SpaceVectorType
00185 AffineXform::RotateScaleShear
00186 ( const Self::SpaceVectorType& v ) const
00187 {
00188   Self::SpaceVectorType Mv;
00189   for ( size_t i = 0; i<3; ++i )
00190     {
00191     Mv[i] = v[0] * Matrix[0][i] + v[1] * Matrix[1][i] + v[2] * Matrix[2][i];
00192     }
00193   return Mv;
00194 }
00195 
00196 AffineXform* 
00197 AffineXform::MakeInverse () const
00198 {
00199   Self* inverseXform = new AffineXform();
00200   inverseXform->m_LogScaleFactors = this->m_LogScaleFactors;
00201   inverseXform->SetNumberDOFs( this->NumberDOFs );
00202   inverseXform->Matrix = this->Matrix.GetInverse();
00203   inverseXform->DecomposeMatrix();
00204 
00205   const Self::SpaceVectorType newCenter = Self::SpaceVectorType( this->RetCenter() ) * this->Matrix;
00206   inverseXform->ChangeCenter( newCenter );
00207   
00208   if ( this->NumberDOFs == 7 ) 
00209     {
00210     inverseXform->m_Parameters[8] = (inverseXform->m_Parameters[7] = inverseXform->m_Parameters[6]);
00211     inverseXform->Matrix.Compose( inverseXform->m_Parameters, this->m_LogScaleFactors );
00212     }
00213   
00214   inverseXform->m_MetaInformation[META_SPACE] = this->m_MetaInformation[META_SPACE];
00215   inverseXform->m_MetaInformation[META_XFORM_FIXED_IMAGE_PATH] = this->m_MetaInformation[META_XFORM_FIXED_IMAGE_PATH];
00216   inverseXform->m_MetaInformation[META_XFORM_MOVING_IMAGE_PATH] = this->m_MetaInformation[META_XFORM_MOVING_IMAGE_PATH];
00217   
00218   return inverseXform;
00219 }
00220 
00221 void
00222 AffineXform::ChangeCenter ( const Self::SpaceVectorType& newCenter ) 
00223 {
00224   Types::Coordinate *const xlate = this->RetXlate();
00225   Types::Coordinate *const center = this->RetCenter();
00226   Self::SpaceVectorType deltaCenter = newCenter - Self::SpaceVectorType( center );
00227   
00228   for ( size_t i = 0; i<3; ++i )
00229     xlate[i] -= deltaCenter[i];
00230 
00231   deltaCenter = this->RotateScaleShear( deltaCenter );
00232 
00233   for ( size_t i = 0; i<3; ++i )
00234     {
00235     xlate[i] += deltaCenter[i];
00236     center[i] = newCenter[i];
00237     }
00238 }
00239 
00240 void
00241 AffineXform::SetMatrix( const MatrixType& matrix ) 
00242 {
00243   this->Matrix = matrix;
00244   this->DecomposeMatrix();
00245   this->UpdateInverse();
00246 }
00247 
00248 void
00249 AffineXform::SetMatrix( const float matrix[4][4] ) 
00250 {
00251   for ( unsigned int j = 0; j < 4; ++j )
00252     for ( unsigned int i = 0; i < 4; ++i )
00253       Matrix[j][i] = matrix[j][i];
00254   this->DecomposeMatrix();
00255   this->UpdateInverse();
00256 }
00257 
00258 void
00259 AffineXform::SetMatrix( const double matrix[4][4] ) 
00260 {
00261   for ( unsigned int j = 0; j < 4; ++j )
00262     for ( unsigned int i = 0; i < 4; ++i )
00263       Matrix[j][i] = matrix[j][i];
00264   this->DecomposeMatrix();
00265   this->UpdateInverse();
00266 }
00267 
00268 template<> 
00269 void
00270 AffineXform::GetMatrix( float (&matrix)[4][4] ) const
00271 {
00272   for ( unsigned int j = 0; j < 4; ++j )
00273     for ( unsigned int i = 0; i < 4; ++i )
00274       matrix[j][i] = static_cast<float>( Matrix[j][i] );
00275 }
00276 
00277 template<> 
00278 void 
00279 AffineXform::GetMatrix( double (&matrix)[4][4] ) const
00280 {
00281   for ( unsigned int j = 0; j < 4; ++j )
00282     for ( unsigned int i = 0; i < 4; ++i )
00283       matrix[j][i] = static_cast<double>( Matrix[j][i] );
00284 }
00285 
00286 void
00287 AffineXform::SetParamVector ( CoordinateVector& v )
00288 {
00289   Superclass::SetParamVector( v );
00290   this->CanonicalRotationRange();
00291   this->ComposeMatrix();
00292   v = (*this->m_ParameterVector);
00293 }
00294 
00295 void 
00296 AffineXform::SetParamVector ( const CoordinateVector& v )
00297 {
00298   Superclass::SetParamVector( v );
00299   this->CanonicalRotationRange();
00300   this->ComposeMatrix();
00301 }
00302 
00303 void
00304 AffineXform::SetParameter ( const size_t idx, const Types::Coordinate p )
00305 {
00306   Superclass::SetParameter( idx, p );
00307   this->CanonicalRotationRange();
00308   this->ComposeMatrix();
00309 }
00310 
00311 
00312 Types::Coordinate
00313 AffineXform::GetParamStep
00314 ( const size_t idx, const Self::SpaceVectorType& volSize, const Types::Coordinate mmStep ) 
00315   const
00316 {
00317   if ( (int)idx >= this->NumberDOFs ) return 0.0;
00318   
00319   switch ( idx )
00320     {
00321     case 0: case 1: case 2:
00322       return mmStep;
00323     case 3:
00324       return mmStep * 180 / (M_PI * sqrt( MathUtil::Square( volSize[1] ) + MathUtil::Square( volSize[2] ) ) );
00325     case 4:
00326       return mmStep * 180 / (M_PI * sqrt( MathUtil::Square( volSize[0] ) + MathUtil::Square( volSize[2] ) ) );
00327     case 5:
00328       return mmStep * 180 / (M_PI * sqrt( MathUtil::Square( volSize[0] ) + MathUtil::Square( volSize[1] ) ) );
00329     case 6: 
00330     case 7:
00331     case 8:
00332       if ( this->NumberDOFs == 603 )
00333         { // special case: 6 DOFs rigid plus 3 DOFs shear, but no scale
00334         return 0;
00335         }
00336       else
00337         {
00338         if ( this->m_LogScaleFactors )
00339           return log( 1 + 0.5 * mmStep / volSize.MaxValue() );
00340         else
00341           return 0.5 * mmStep / volSize.MaxValue();
00342         }
00343     case 9: 
00344     case 10:
00345     case 11:
00346       return 0.5 * mmStep / volSize.MaxValue();
00347     }
00348   return mmStep;
00349 }
00350 
00351 AffineXform::SmartPtr
00352 AffineXform::GetDifference( const AffineXform& other ) const
00353 {
00354   Self::SmartPtr result( this->MakeInverse() );
00355   result->Concat( other );
00356   return result;
00357 }
00358 
00359 void
00360 AffineXform::Concat( const AffineXform& other )
00361 {
00362   this->Matrix *= other.Matrix;
00363   this->DecomposeMatrix();
00364 }
00365 
00366 void
00367 AffineXform::Insert( const AffineXform& other )
00368 {
00369   Self::MatrixType composed( other.Matrix );
00370   composed *= this->Matrix;
00371   this->Matrix = composed;
00372   this->DecomposeMatrix();
00373 }
00374 
00375 void 
00376 AffineXform::RotateWXYZ
00377 ( const Units::Radians angle, const Self::SpaceVectorType& direction,
00378   const Types::Coordinate* center, Self::MatrixType *const accumulate )
00379 {
00380   Self::SpaceVectorType unit( direction );
00381 
00382   Self::SpaceVectorType center3D;
00383   if ( center ) 
00384     center3D = Self::SpaceVectorType( center );
00385   else
00386     center3D = Self::SpaceVectorType( this->RetCenter() );
00387 
00388   if ( accumulate ) 
00389     {
00390     unit += center3D;
00391     unit *= *accumulate;
00392     center3D *= *accumulate;
00393     unit -= center3D;
00394     }
00395 
00396   // translation into rotation center
00397   Self::MatrixType xlate;
00398   for ( int dim = 0; dim < 3; ++dim )
00399     xlate[3][dim] = -center3D[dim];
00400 
00401   if ( accumulate ) 
00402     {
00403     *accumulate *= xlate;
00404     }
00405 
00406   this->Matrix *= xlate;
00407 
00408   double x = unit[0];
00409   double y = unit[1];
00410   double z = unit[2];
00411 
00412   // make a normalized quaternion
00413   const double w = MathUtil::Cos(0.5*angle);
00414   const double f = MathUtil::Sin(0.5*angle)/sqrt(x*x+y*y+z*z);
00415   x *= f;
00416   y *= f;
00417   z *= f;
00418 
00419   // convert the quaternion to a matrix
00420   Self::MatrixType matrix;
00421 
00422   const double ww = w*w;
00423   const double wx = w*x;
00424   const double wy = w*y;
00425   const double wz = w*z;
00426 
00427   const double xx = x*x;
00428   const double yy = y*y;
00429   const double zz = z*z;
00430 
00431   const double xy = x*y;
00432   const double xz = x*z;
00433   const double yz = y*z;
00434 
00435   const double s = ww - xx - yy - zz;
00436 
00437   matrix[0][0] = xx*2 + s;
00438   matrix[1][0] = (xy + wz)*2;
00439   matrix[2][0] = (xz - wy)*2;
00440 
00441   matrix[0][1] = (xy - wz)*2;
00442   matrix[1][1] = yy*2 + s;
00443   matrix[2][1] = (yz + wx)*2;
00444 
00445   matrix[0][2] = (xz + wy)*2;
00446   matrix[1][2] = (yz - wx)*2;
00447   matrix[2][2] = zz*2 + s;
00448 
00449   this->Matrix *= matrix;
00450 
00451   xlate = xlate.GetInverse();
00452   this->Matrix *= xlate;
00453   this->DecomposeMatrix();
00454 
00455   if ( accumulate ) 
00456     {
00457     *accumulate *= matrix;
00458     *accumulate *= xlate;
00459     }
00460 }
00461 
00462 const AffineXform::SmartPtr
00463 AffineXform::GetInverse() const
00464 {
00465   if ( !InverseXform ) 
00466     {
00467     InverseXform = AffineXform::SmartPtr( this->MakeInverse() );
00468     } 
00469   else 
00470     {
00471     this->UpdateInverse();
00472     }
00473   
00474   return InverseXform;
00475 }
00476 
00477 void
00478 AffineXform::UpdateInverse() const
00479 {
00480   if ( InverseXform ) 
00481     {
00482     InverseXform->NumberDOFs = this->NumberDOFs;
00483     InverseXform->m_LogScaleFactors = this->m_LogScaleFactors;
00484     InverseXform->Matrix = this->Matrix.GetInverse();
00485     InverseXform->DecomposeMatrix();
00486     }
00487 }
00488 
00489 void
00490 AffineXform::CanonicalRotationRange()
00491 {
00492   for ( int rotIdx = 0; rotIdx<3; ++rotIdx ) 
00493     {
00494     while ( this->m_Parameters[3+rotIdx] >  180 ) 
00495       this->m_Parameters[3+rotIdx] -= 360;
00496     while ( this->m_Parameters[3+rotIdx] < -180 ) 
00497       this->m_Parameters[3+rotIdx] += 360;
00498     }
00499 }
00500 
00501 void
00502 AffineXform::Print() const
00503 {
00504   StdErr.printf( "AffineXform at %p:\n", this );
00505   StdErr.printf( "\tNumber DOFs: %d\n", NumberDOFs );
00506   StdErr.printf( "\tTranslation: [%f,%f,%f]\n", this->m_Parameters[0], this->m_Parameters[1], this->m_Parameters[2] );
00507   StdErr.printf( "\tRotation: [%f,%f,%f] around [%f,%f,%f]\n", 
00508                     this->m_Parameters[3], this->m_Parameters[4], this->m_Parameters[5], 
00509                     this->m_Parameters[12], this->m_Parameters[13], this->m_Parameters[14] );
00510   StdErr.printf( "\tScale: [%f,%f,%f]\n", this->m_Parameters[6], this->m_Parameters[7], this->m_Parameters[8] );
00511   StdErr.printf( "\tShear: [%f,%f,%f]\n", this->m_Parameters[9], this->m_Parameters[10], this->m_Parameters[11] );
00512 
00513   this->Matrix.Print( StdErr );
00514 }
00515 
00516 } // namespace
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines