freTransformInitializer.h

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program:   F.R.E.E. - flexible registration evaluation engine
00004   Version:   v.1.0.0
00005   Date:      $Date: 2006/09/01 12:00:00 $
00006   Module:    $RCSfile: freTransformInitializer.h,v $
00007   Language:  C++
00008 
00009 
00010   Date:      $Date: 2004/10/03 $
00011   Version:   $Revision: 1.0 $
00012 
00013   Copyright (c) 2007 Ralf o Floca (Department of Medical Informatics,
00014   Institute for Medical Biometry and Informatics, University of Heidelberg,
00015   Germany). All rights reserved.
00016   See FREECopyright.txt or http://www.mi.med.uni-hd.de/free/copyright.htm
00017   for details.
00018 
00019      This software is distributed WITHOUT ANY WARRANTY; without even 
00020      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
00021      PURPOSE.  See the above copyright notices for more information.
00022 
00023 =========================================================================*/
00024 #ifndef __freTransformInitializer_h
00025 #define __freTransformInitializer_h
00026 
00027 #include "freElementals.h"
00028 #include "freImageTypes.h"
00029 #include "freExceptions.h"
00030 
00031 #include "itkImage.h"
00032 #include "itkVector.h"
00033 #include "itkPoint.h"
00034 #include "itkImageMomentsCalculator.h"
00035 #include "itkAffineTransform.h"
00036 
00037 namespace FREE
00038 {
00039 
00041 enum RotationAxisType 
00042 {
00043         RA_X = 0, 
00044         RA_Y = 1, 
00045         RA_Z = 2, 
00046 };
00047 
00048 // Define a postfix increment operator for RotationAxisType.
00049 inline RotationAxisType operator++( RotationAxisType &ra, int )
00050 {
00051    return ra = (RotationAxisType)(ra + 1);
00052 }
00053 
00054 // Define a postfix increment operator for RotationAxisType.
00055 inline RotationAxisType operator--( RotationAxisType &ra, int )
00056 {
00057    return ra = (RotationAxisType)(ra - 1);
00058 }
00059 
00086 template <typename TPixel, int iDimension>
00087 class CenterInitializer
00088 {
00089 public: 
00090   typedef itk::Point<ScalarType,iDimension> PointType;
00091   typedef itk::Vector<ScalarType,iDimension> VectorType;
00092   typedef itk::Image<TPixel,iDimension> TImage; //is same like InternalImage of free
00093 
00094   void GeometryOn()
00095   { 
00096           if (m_bUseMoments)
00097           {
00098             m_bUseMoments = false;
00099             m_bInitialized = false;
00100           }
00101   };
00102   
00103   void MomentsOn()
00104   { 
00105           if (!m_bUseMoments)
00106           {
00107             m_bUseMoments = true;
00108             m_bInitialized = false;
00109           }
00110   };
00111 
00112   void SetImage(TImage* pImage)
00113   { 
00114           m_pImage = pImage;
00115     m_bInitialized = false;
00116   };
00117 
00118   void ComputeCenter()
00119   {
00120           if( m_bUseMoments )
00121     {
00122             // Here use the center of mass for each image.
00123             typedef itk::ImageMomentsCalculator< TImage >  ImageCalculatorType;
00124 
00125             typename ImageCalculatorType::Pointer calculator = ImageCalculatorType::New();
00126 
00127             try
00128             {
00129                     calculator->SetImage(  m_pImage );
00130                     calculator->Compute();
00131     
00132                     m_Center = calculator->GetCenterOfGravity();
00133             }
00134             catch(...)
00135             {
00136                     //itk throws error if the mass is zero, so the image is all black ->
00137                     //use geometrical center.
00138                     m_bUseMoments = false;
00139             }
00140     }
00141         
00142           if( !m_bUseMoments )
00143     {
00144             // Here use the geometrical center of each image.
00145 
00146             const typename TImage::SpacingType& rSpacing = m_pImage->GetSpacing();
00147             const typename TImage::PointType& rOrigin = m_pImage->GetOrigin();
00148    
00149             typename TImage::SizeType size = m_pImage->GetLargestPossibleRegion().GetSize();
00150     
00151             for( unsigned int iIndex=0; iIndex<iDimension; iIndex++)
00152       {
00153                     m_Center[iIndex] = rOrigin[iIndex] + rSpacing[iIndex] * (size[iIndex] /2.0);
00154       }
00155     }
00156           m_bInitialized = true;
00157   };
00158 
00159   void GetCenter(VectorType& rVector)
00160   {
00161           if (!m_bInitialized) ComputeCenter();
00162 
00163           rVector = m_Center;
00164   };
00165 
00166   void GetCenter(ParameterArrayType& rVector)
00167   {
00168           if (!m_bInitialized) ComputeCenter();
00169 
00170           rVector.SetSize(iDimension);
00171           for (int iIndex = 0; iIndex<iDimension; iIndex++)
00172           {
00173             rVector.SetElement(iIndex,m_Center[iIndex]);
00174           }
00175   };
00176 
00177   CenterInitializer()
00178   {
00179           m_bUseMoments = true;
00180           m_bInitialized = false;
00181           m_pImage = NULL;
00182   };
00183 
00184   ~CenterInitializer() {};
00185 
00186 private:
00187   bool m_bUseMoments;
00188   bool m_bInitialized;
00189 
00190   VectorType m_Center;
00191 
00192   TImage* m_pImage;
00193 };
00194 
00213 template <int iDimension>
00214 class RotationInitializer
00215 {
00216 public: 
00217   typedef itk::Vector<ScalarType,iDimension> VectorType;
00218 
00219   void ClearSchedule(bool bToDefault = true) 
00220   { 
00221     m_Schedule.clear();
00222           if(bToDefault)
00223           {
00224       m_Schedule.push_back(RA_Z);
00225             m_Schedule.push_back(RA_Y);
00226             m_Schedule.push_back(RA_X);
00227           }
00228           m_bInitialized = false;
00229   };
00230   
00231   void AddToSchedule(RotationAxisType axis)
00232   { 
00233           m_Schedule.push_back(axis);
00234           m_bInitialized = false;
00235   };
00236 
00237   void SetMovingCenter(VectorType center)
00238   { 
00239           m_MovingCenter.Fill(0.0);
00240           for (int iIndex=0; iIndex<iDimension; iIndex++) m_MovingCenter.SetNthComponent(iIndex,center[iIndex]);
00241           m_bInitialized = false;
00242   };
00243 
00244   void SetFixedCenter(VectorType center)
00245   { 
00246           m_FixedCenter.Fill(0);
00247           for (int iIndex=0; iIndex<iDimension; iIndex++) m_FixedCenter.SetNthComponent(iIndex,center[iIndex]);
00248           m_bInitialized = false;
00249   };
00250 
00251   void SetCenterPair(VectorType movingCenter,VectorType fixedCenter)
00252   { 
00253     SetFixedCenter(fixedCenter);
00254     SetMovingCenter(movingCenter);
00255   };
00256 
00257   void SetCenterPair(ParameterArrayType movingCenter,ParameterArrayType fixedCenter)
00258   { 
00259           VectorType movingCenterVector;
00260           VectorType fixedCenterVector;
00261 
00262           for (int iIndex = 0; iIndex<iDimension; iIndex++)
00263           {
00264             movingCenterVector.SetNthComponent(iIndex,movingCenter[iIndex]);
00265             fixedCenterVector.SetNthComponent(iIndex,fixedCenter[iIndex]);
00266           };
00267 
00268     SetFixedCenter(fixedCenterVector);
00269     SetMovingCenter(movingCenterVector);
00270   };
00271 
00272   void ClearReferences()
00273   {
00274           this->m_FixedReferences.RemoveAll();
00275           this->m_MovingReferences.RemoveAll();
00276           m_bInitialized = false;
00277   };
00278 
00279   void AddReferencePair(VectorType movingReference,VectorType fixedReference)
00280   {
00281           Vector3DType movingVector3D;
00282           Vector3DType fixedVector3D;
00283 
00284           movingVector3D.Fill(0);
00285           fixedVector3D.Fill(0);
00286 
00287           for (int iIndex=0; iIndex<iDimension; iIndex++)
00288           {
00289             movingVector3D.SetNthComponent(iIndex,movingReference[iIndex]);
00290             fixedVector3D.SetNthComponent(iIndex,fixedReference[iIndex]);
00291           }
00292 
00293           m_FixedReferences.push_back(fixedVector3D);
00294           m_MovingReferences.push_back(movingVector3D);
00295           m_bInitialized = false;
00296   };
00297 
00298   void AddReferencePair(ParameterArrayType movingReference,ParameterArrayType fixedReference)
00299   { 
00300           VectorType movingReferenceVector;
00301           VectorType fixedReferenceVector;
00302 
00303           for (int iIndex = 0; iIndex<iDimension; iIndex++)
00304           {
00305             movingReferenceVector.SetNthComponent(iIndex,movingReference[iIndex]);
00306             fixedReferenceVector.SetNthComponent(iIndex,fixedReference[iIndex]);
00307           };
00308 
00309     AddReferencePair(movingReferenceVector,fixedReferenceVector);
00310   };
00311 
00312   void ComputeRotations()
00313   {
00314     typedef std::vector<double> AnglesArrayType;
00315           AnglesArrayType xAngles;
00316           AnglesArrayType yAngles;
00317           AnglesArrayType zAngles;
00318 
00319           for (int iIndex=0; iIndex<m_FixedReferences.size(); iIndex++)
00320           {
00321             //calculate ref points vector relative to the center points
00322             Vector3DType movingRef = m_MovingReferences[iIndex] - m_MovingCenter;
00323             Vector3DType fixedRef = m_FixedReferences[iIndex] - m_FixedCenter;
00324           
00325             //Calculating vector length for smart composing
00326             Vector3DType::ValueType lengthFixed = fixedRef.GetNorm();
00327             Vector3DType smartRef= fixedRef;
00328 
00329             //normalize
00330             movingRef.Normalize();
00331             fixedRef.Normalize();
00332 
00333             for (int iScheduleIndex=0; iScheduleIndex<m_Schedule.size(); iScheduleIndex++)
00334             {
00335                   RotationAxisType axis = m_Schedule[iScheduleIndex];
00336 
00337                     Vector3DType movingTmpRef =movingRef;
00338                     Vector3DType fixedTmpRef = fixedRef;
00339                     movingTmpRef[axis]=0;
00340                     fixedTmpRef[axis]=0;
00341 
00342                     //Calculating vector length for smart composing
00343                     Vector3DType smartTmpRef = smartRef;
00344                     smartTmpRef[axis]=0;
00345                     Vector3DType::ValueType length2DFixed = smartTmpRef.GetNorm();
00346                     ScalarType rotationWeight = length2DFixed/lengthFixed;
00347 
00348                     //Preparing angel calculation
00349                     movingTmpRef.Normalize();
00350                     fixedTmpRef.Normalize();
00351 
00352                     Vector3DType rotationAxis;
00353                     rotationAxis.Fill(0);
00354                     rotationAxis[axis]=1;
00355 
00356                     //calculate angel between ref vectors.
00357                     ScalarType dAngel = CalculateRotationAngel(fixedTmpRef,movingTmpRef,rotationAxis);
00358                 
00359                     /* Smart composing should prevent faulty extreme rotations, caused by a small distances between
00360                      * the reference point and the estimated center of gravity, so that small estimation errors
00361                      * could have a large impact in the angel. (e.g. if the 2D projection of the reference vector is
00362                      * only three pixels long, a missestimation of three Pixel could mean a rotation of 45. If
00363                      * the reference vector has a length of 30 pixel the impact of missestimation would be much smaller.
00364                      * To compensate this the Angles are weightened by ratio between the length of the reference vector
00365                      * and his 2D projection.*/
00366                     if (m_bUseRotationWeight) dAngel *= rotationWeight;//smart composing
00367 
00368                     //compute matrix for the rotation
00369                     typedef itk::AffineTransform<ScalarType,3> CalculateTransformType;
00370                     CalculateTransformType::Pointer oneRotation = CalculateTransformType::New();
00371                     oneRotation->Rotate3D(rotationAxis,dAngel);
00372 
00373                     //update fixedRef for next computation step
00374                     movingRef = oneRotation->TransformVector(movingRef);
00375 
00376                     //update original fixed referencefixedRef for smart computation in the next step
00377                     smartRef = oneRotation->TransformVector(smartRef);
00378 
00379                     switch (axis)
00380                     {
00381                       case RA_X: xAngles.push_back(dAngel); break;
00382                       case RA_Y: yAngles.push_back(dAngel); break;
00383                       case RA_Z: zAngles.push_back(dAngel); break;
00384                     };
00385             };
00386           };
00387 
00388           for (int iIndex=0; iIndex<xAngles.size(); iIndex++)
00389           {
00390             m_Angles[RA_X] += xAngles[iIndex];
00391           }
00392 
00393           for (int iIndex=0; iIndex<yAngles.size(); iIndex++)
00394           {
00395             m_Angles[RA_Y] += yAngles[iIndex];
00396           }
00397 
00398           for (int iIndex=0; iIndex<zAngles.size(); iIndex++)
00399           {
00400             m_Angles[RA_Z] += zAngles[iIndex];
00401           }
00402 
00403           if (xAngles.size()>0) m_Angles[RA_X] = m_Angles[RA_X]/ xAngles.size(); 
00404           if (yAngles.size()>0) m_Angles[RA_Y] = m_Angles[RA_Y]/ yAngles.size(); 
00405           if (zAngles.size()>0) m_Angles[RA_Z] = m_Angles[RA_Z]/ zAngles.size(); 
00406 
00407           m_bInitialized = true;
00408   };
00409 
00410   double GetRotation(RotationAxisType axis)
00411   {
00412           if (!m_bInitialized) ComputeRotations();
00413 
00414           return m_Angles[axis];
00415   };
00416 
00417   bool GetUseRotationWeight() {return m_bUseRotationWeight;};
00418 
00419   void SetUseRotationWeight(bool bUseWeight) 
00420   {
00421           m_bUseRotationWeight = bUseWeight;
00422         m_bInitialized = true;
00423   };
00424 
00425   RotationInitializer()
00426   {
00427           ClearSchedule();
00428           m_Angles[RA_X] = 0.0;
00429           m_Angles[RA_Y] = 0.0;
00430           m_Angles[RA_Z] = 0.0;
00431 
00432           m_bInitialized = false;
00433           m_bUseRotationWeight = false;
00434   };
00435 
00436   ~RotationInitializer() {};
00437 
00438 private:
00439   double m_Angles[3];
00440   bool m_bInitialized;
00441   bool m_bUseRotationWeight;
00442 
00443   typedef std::vector<Vector3DType> VectorArrayType;
00444   VectorArrayType m_FixedReferences;
00445   VectorArrayType m_MovingReferences;
00446 
00447   typedef std::vector<RotationAxisType> ScheduleType;
00448   
00449   ScheduleType m_Schedule;
00450 
00451   Vector3DType m_FixedCenter;
00452   Vector3DType m_MovingCenter;
00453 
00456   double CalculateRotationAngel(Vector3DType vector1, Vector3DType vector2,
00457                                                                 Vector3DType rotationAxis)
00458   {
00459           vector1.Normalize();
00460           vector2.Normalize();
00461 
00462           double dAngel = acos(vector1*vector2);
00463 
00464           //calculate the matrix
00465           typedef itk::AffineTransform<ScalarType,3> CalculateTransformType;
00466           CalculateTransformType::Pointer calcTransform = CalculateTransformType::New();
00467 
00468           calcTransform->Rotate3D(rotationAxis,dAngel);
00469           
00470           double dTestangel = acos((calcTransform->TransformVector(vector2))*vector1);
00471 
00472           if (dTestangel>dAngel)
00473           {
00474             //angel of scalar product wasn't the rotation from vector2 to vector1, but reverse
00475             dAngel = -1*dAngel;
00476           };
00477   
00478           return dAngel;
00479   };
00480 };
00481 
00482 } //end of namespace free
00483 #endif

Generated at Sat Oct 13 18:02:04 2007 for f.r.e.e. - Flexible Registration and Evaluation Engine by doxygen 1.5.3 written by Dimitri van Heesch, © 1997-2000