cmtkVoxelMatchingElasticFunctional.h

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2010 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2011 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: 2752 $
00026 //
00027 //  $LastChangedDate: 2011-01-17 11:33:31 -0800 (Mon, 17 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #ifndef __cmtkVoxelMatchingElasticFunctional_h_included_
00034 #define __cmtkVoxelMatchingElasticFunctional_h_included_
00035 
00036 #include <cmtkconfig.h>
00037 
00038 #include <Registration/cmtkVoxelMatchingFunctional.h>
00039 
00040 #include <Base/cmtkVector.h>
00041 #include <Base/cmtkSplineWarpXform.h>
00042 #include <Base/cmtkJointHistogram.h>
00043 #include <Base/cmtkUniformVolume.h>
00044 #include <Base/cmtkMacros.h>
00045 #include <Base/cmtkMathUtil.h>
00046 
00047 #include <System/cmtkException.h>
00048 
00049 #include <cassert>
00050 #include <vector>
00051 
00052 #ifdef HAVE_IEEEFP_H
00053 #  include <ieeefp.h>
00054 #endif
00055 
00056 #ifdef HAVE_VALUES_H
00057 #  include <values.h>
00058 #endif
00059 
00060 namespace
00061 cmtk
00062 {
00063 
00066 
00071 class VoxelMatchingElasticFunctional : 
00073   public VoxelMatchingFunctional 
00074 {
00075 public:
00077   typedef VoxelMatchingElasticFunctional Self;
00078 
00080   typedef SmartPointer<Self> SmartPtr;
00081 
00083   typedef VoxelMatchingFunctional Superclass;
00084 
00091   virtual void SetWarpXform( SplineWarpXform::SmartPtr& warp ) = 0;
00092 
00094   virtual void SetForceOutside( const bool flag = true, const Types::DataItem value = 0 ) = 0;
00095 
00097   virtual ~VoxelMatchingElasticFunctional ();
00098 
00099 protected:
00101   VoxelMatchingElasticFunctional( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating );
00102 
00108   cmtkGetSetMacroDefault(bool,AdaptiveFixParameters,true);
00109 
00117   cmtkGetSetMacro(double,AdaptiveFixThreshFactor);
00118 
00121   cmtkGetSetMacroString(ActiveCoordinates);
00122 
00126   cmtkGetSetMacroDefault(double,JacobianConstraintWeight,0);
00127 
00130   cmtkGetSetMacroDefault(double,RigidityConstraintWeight,0);
00131 
00134   cmtkGetSetMacro(DataGrid::SmartPtr,RigidityConstraintMap);
00135 
00140   cmtkGetSetMacroDefault(double,GridEnergyWeight,0);
00141 
00144   cmtkGetSetMacroDefault(bool,Regularize,false);
00145 
00151   bool WarpNeedsFixUpdate;
00152 
00154   JointHistogram<unsigned int>::SmartPtr ConsistencyHistogram;
00155 
00157   size_t Dim;
00158 
00164   std::vector<Types::Coordinate> StepScaleVector;
00165 
00172   DataGrid::RegionType *VolumeOfInfluence;
00173 
00175   Vector3D ReferenceFrom;
00176 
00178   Vector3D ReferenceTo;
00179 
00181   Vector3D *VectorCache;
00182 };
00183 
00205 template<class W> 
00206 class VoxelMatchingElasticFunctional_WarpTemplate :
00208   public VoxelMatchingElasticFunctional 
00209 {
00210 public:
00212   typedef VoxelMatchingElasticFunctional_WarpTemplate<W> Self;
00213 
00215   typedef SmartPointer<Self> SmartPtr;
00216 
00218   typedef VoxelMatchingElasticFunctional Superclass;
00219 
00221   typename W::SmartPtr Warp;
00222 
00223 protected:
00225   typename W::SmartPtr InverseTransformation;
00226 
00228   double InverseConsistencyWeight;
00229 
00230 public:
00232   void SetInverseTransformation( typename W::SmartPtr& inverseTransformation ) 
00233   {
00234     this->InverseTransformation = W::SmartPtr::DynamicCastFrom( inverseTransformation );
00235   }
00236 
00238   void SetInverseConsistencyWeight( const double inverseConsistencyWeight ) 
00239   {
00240     this->InverseConsistencyWeight = inverseConsistencyWeight;
00241   }
00242 
00243 protected:
00244 
00246         typename Self::ReturnType WeightedTotal( const typename Self::ReturnType metric, const W* warp ) const 
00247   {
00248     double result = metric;
00249     if ( this->m_JacobianConstraintWeight > 0 ) 
00250       {
00251       result -= this->m_JacobianConstraintWeight * warp->GetJacobianConstraint();
00252       } 
00253     
00254     if ( this->m_RigidityConstraintWeight > 0 ) 
00255       {
00256       if ( this->m_RigidityConstraintMap )
00257         {
00258         result -= this->m_RigidityConstraintWeight * warp->GetRigidityConstraint( this->m_RigidityConstraintMap );
00259         }
00260       else
00261         {
00262         result -= this->m_RigidityConstraintWeight * warp->GetRigidityConstraint();
00263         }
00264       } 
00265     
00266     if ( this->m_GridEnergyWeight > 0 ) 
00267       {
00268       result -= this->m_GridEnergyWeight * warp->GetGridEnergy();
00269       }
00270     
00271     if ( !finite( result ) ) 
00272       return -FLT_MAX;
00273     
00274     if ( this->m_MatchedLandmarkList ) 
00275       {
00276       result -= this->m_LandmarkErrorWeight * warp->GetLandmarksMSD( this->m_MatchedLandmarkList );
00277       }
00278 
00279     if ( InverseTransformation ) 
00280       {
00281       result -= this->InverseConsistencyWeight * warp->GetInverseConsistencyError( this->InverseTransformation, this->ReferenceGrid );
00282       }
00283     
00284     return static_cast<typename Self::ReturnType>( result );
00285   }
00286   
00288   void WeightedDerivative( double& lower, double& upper, W& warp, const int param, const Types::Coordinate step ) const;
00289 
00290 public:
00292   virtual Types::Coordinate GetParamStep( const size_t idx, const Types::Coordinate mmStep = 1 ) const 
00293   {
00294     return Warp->GetParamStep( idx, Vector3D( this->FloatingSize ), mmStep );
00295   }
00296 
00298   virtual size_t ParamVectorDim() const 
00299   {
00300     return Warp->ParamVectorDim();
00301   }
00302 
00304   virtual size_t VariableParamVectorDim() const 
00305   {
00306     return Warp->VariableParamVectorDim();
00307   }
00308 
00314   virtual void SetWarpXform ( typename W::SmartPtr& warp );
00315 
00317   virtual void GetParamVector ( CoordinateVector& v ) 
00318   {
00319     Warp->GetParamVector( v );
00320   }
00321 
00322 protected:
00324   VoxelMatchingElasticFunctional_WarpTemplate( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating )
00325     : VoxelMatchingElasticFunctional( reference, floating ),
00326       Warp( NULL ), InverseTransformation( NULL )
00327   {}
00328   
00330   virtual ~VoxelMatchingElasticFunctional_WarpTemplate() {}
00331 };
00332 
00342 template<class VM> 
00343 class VoxelMatchingElasticFunctional_Template 
00344   : public VoxelMatchingFunctional_Template<VM>,
00345     public VoxelMatchingElasticFunctional_WarpTemplate<SplineWarpXform> 
00346 {
00347 public:
00349   typedef VoxelMatchingElasticFunctional_Template<VM> Self;
00350 
00357   VoxelMatchingElasticFunctional_Template( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating )
00358     : VoxelMatchingFunctional_Template<VM>( reference, floating ), 
00359       VoxelMatchingElasticFunctional_WarpTemplate<SplineWarpXform>( reference, floating ),
00360       m_ForceOutsideFlag( false ),
00361       m_ForceOutsideValueRescaled( 0 )
00362   {
00363     IncrementalMetric = typename VM::SmartPtr( new VM( *(this->Metric) ) );
00364 
00365     WarpedVolume = NULL;
00366 
00367     DimsX = this->ReferenceGrid->GetDims()[0];
00368     DimsY = this->ReferenceGrid->GetDims()[1];
00369     DimsZ = this->ReferenceGrid->GetDims()[2];
00370 
00371     FltDimsX = this->FloatingGrid->GetDims()[0];
00372     FltDimsY = this->FloatingGrid->GetDims()[1];
00373   }
00374 
00376   virtual ~VoxelMatchingElasticFunctional_Template() 
00377   {
00378     if ( WarpedVolume ) 
00379       Memory::DeleteArray( WarpedVolume );
00380   }
00381 
00383   virtual void SetForceOutside
00384   ( const bool flag = true, const Types::DataItem value = 0 )
00385   {
00386     this->m_ForceOutsideFlag = flag;
00387     this->m_ForceOutsideValueRescaled = this->Metric->DataY.ValueToIndex( value );
00388   }
00389 
00396   typename Self::ReturnType EvaluateIncremental( const SplineWarpXform* warp, SmartPointer<VM>& localMetric, const DataGrid::RegionType& voi ) 
00397   {
00398     Vector3D *pVec;
00399     int pX, pY, pZ, offset, r;
00400     int fltIdx[3];
00401     Types::Coordinate fltFrac[3];
00402 
00403     int endLineIncrement = ( voi.From()[0] + (DimsX - voi.To()[0]) );
00404     int endPlaneIncrement = DimsX * ( voi.From()[1] + (DimsY - voi.To()[2]) );
00405     
00406     const typename VM::Exchange unsetY = this->Metric->DataY.padding();
00407     *localMetric = *this->Metric;
00408     r = voi.From()[0] + DimsX * ( voi.From()[1] + DimsY * voi.From()[2] );
00409     for ( pZ = voi.From()[2]; pZ<voi.To()[2]; ++pZ ) 
00410       {
00411       for ( pY = voi.From()[1]; pY<voi.To()[1]; ++pY ) 
00412         {
00413         pVec = this->VectorCache;
00414         warp->GetTransformedGridRow( voi.From()[0]-voi.To()[0], pVec, voi.From()[0], pY, pZ );
00415         for ( pX = voi.From()[0]; pX<voi.To()[0]; ++pX, ++r, ++pVec ) 
00416           {
00417           // Remove this sample from incremental metric according to "ground warp" image.
00418           const typename VM::Exchange sampleX = this->Metric->GetSampleX( r );
00419           if ( this->WarpedVolume[r] != unsetY )
00420             localMetric->Decrement( sampleX, WarpedVolume[r] );
00421             
00422           // Tell us whether the current location is still within the floating volume and get the respective voxel.
00423           *pVec *= this->FloatingInverseDelta;
00424           if ( this->FloatingGrid->FindVoxelByIndex( *pVec, fltIdx, fltFrac ) ) 
00425             {
00426             // Compute data index of the floating voxel in the floating volume.
00427             offset = fltIdx[0] + FltDimsX * ( fltIdx[1] + FltDimsY * fltIdx[2] );
00428             
00429             // Continue metric computation.
00430             localMetric->Increment( sampleX, this->Metric->GetSampleY( offset, fltFrac ) );
00431             } 
00432           else 
00433             {
00434             if ( this->m_ForceOutsideFlag )
00435               {
00436               localMetric->Increment( sampleX, this->m_ForceOutsideValueRescaled );
00437               }
00438             }
00439           }
00440         r += endLineIncrement;
00441         }
00442       r += endPlaneIncrement;
00443       }
00444     
00445     return localMetric->Get();
00446   }
00447 
00456   void UpdateWarpFixedParameters();
00457 
00459   virtual typename Self::ReturnType EvaluateWithGradient( CoordinateVector& v, CoordinateVector& g, const Types::Coordinate step = 1 ) 
00460   {
00461     const typename Self::ReturnType current = this->EvaluateAt( v );
00462 
00463     if ( this->m_AdaptiveFixParameters && this->WarpNeedsFixUpdate ) 
00464       {
00465       this->UpdateWarpFixedParameters();
00466       }
00467     
00468     Types::Coordinate *p = this->Warp->m_Parameters;
00469 
00470     Types::Coordinate pOld;
00471     double upper, lower;
00472     const DataGrid::RegionType *voi = this->VolumeOfInfluence;
00473     for ( size_t dim = 0; dim < this->Dim; ++dim, ++voi ) 
00474       {
00475       if ( this->StepScaleVector[dim] <= 0 ) 
00476         {
00477         g[dim] = 0;
00478         } 
00479       else
00480         {
00481         pOld = p[dim];
00482         
00483         Types::Coordinate thisStep = step * this->StepScaleVector[dim];
00484         
00485         p[dim] += thisStep;
00486         upper = EvaluateIncremental( this->Warp, IncrementalMetric, *voi );
00487         
00488         p[dim] = pOld - thisStep;
00489         lower = EvaluateIncremental( this->Warp, IncrementalMetric, *voi );
00490         
00491         p[dim] = pOld;
00492         this->WeightedDerivative( lower, upper, *(this->Warp), dim, thisStep );
00493         
00494         if ( (upper > current ) || (lower > current) ) 
00495           {
00496           g[dim] = upper-lower;
00497           } 
00498         else 
00499           {
00500           g[dim] = 0;
00501           }
00502         }
00503       }
00504     
00505     return current;
00506   }
00507   
00509   virtual typename Self::ReturnType EvaluateAt( CoordinateVector& v )
00510   {
00511     this->Warp->SetParamVector( v );
00512     return this->Evaluate();
00513   }
00514 
00516   virtual typename Self::ReturnType Evaluate()
00517   {
00518     if ( ! WarpedVolume ) 
00519       WarpedVolume = Memory::AllocateArray<typename VM::Exchange>(  DimsX * DimsY * DimsZ  );
00520 
00521     this->Metric->Reset();
00522     const typename VM::Exchange unsetY = this->Metric->DataY.padding();
00523 
00524     Vector3D *pVec;
00525     int pX, pY, pZ;
00526     int fltIdx[3];
00527     Types::Coordinate fltFrac[3];
00528 
00529     int r = 0;
00530     for ( pZ = 0; pZ<DimsZ; ++pZ ) 
00531       {
00532       for ( pY = 0; pY<DimsY; ++pY )
00533         {
00534         this->Warp->GetTransformedGridRow( DimsX, this->VectorCache, 0, pY, pZ );
00535         pVec = this->VectorCache;
00536         for ( pX = 0; pX<DimsX; ++pX, ++r, ++pVec )
00537           {
00538           // Tell us whether the current location is still within the floating volume and get the respective voxel.
00539           *pVec *= this->FloatingInverseDelta;
00540           if ( this->FloatingGrid->FindVoxelByIndex( *pVec, fltIdx, fltFrac ) ) 
00541             {
00542             // Compute data index of the floating voxel in the
00543             // floating volume.
00544             const size_t offset = fltIdx[0] + FltDimsX * ( fltIdx[1] + FltDimsY * fltIdx[2] );
00545             
00546             // Continue metric computation.
00547             this->WarpedVolume[r] = this->Metric->GetSampleY( offset, fltFrac );
00548             this->Metric->Increment( this->Metric->GetSampleX( r ), this->WarpedVolume[r] );
00549             }
00550           else 
00551             {
00552             if ( this->m_ForceOutsideFlag )
00553               {
00554               this->WarpedVolume[r] = this->m_ForceOutsideValueRescaled;
00555               this->Metric->Increment( this->Metric->GetSampleX( r ), this->WarpedVolume[r] );
00556               }
00557             else
00558               {
00559               this->WarpedVolume[r] = unsetY;
00560               }
00561             }
00562           }
00563         }
00564       }
00565     
00566     return this->WeightedTotal( this->Metric->Get(), this->Warp );
00567   }
00568 
00569 protected:
00572   typename VM::Exchange *WarpedVolume;
00573 
00575   bool m_ForceOutsideFlag;
00576 
00578   typename VM::Exchange m_ForceOutsideValueRescaled;
00579 
00586    SmartPointer<VM> IncrementalMetric;
00587    
00589    DataGrid::IndexType::ValueType DimsX, DimsY, DimsZ;
00590    
00592    DataGrid::IndexType::ValueType FltDimsX, FltDimsY;
00593 };
00594 
00605 VoxelMatchingElasticFunctional* CreateElasticFunctional( const int metric, UniformVolume::SmartPtr& refVolume, UniformVolume::SmartPtr& fltVolume );
00606 
00607 } // namespace
00608 
00609 #endif // __cmtkVoxelMatchingElasticFunctional_h_included_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines