cmtkVoxelMatchingElasticFunctional.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2010 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: 2663 $
00026 //
00027 //  $LastChangedDate: 2010-12-14 21:28:06 -0800 (Tue, 14 Dec 2010) $
00028 //
00029 //  $LastChangedBy: torsten_at_home $
00030 //
00031 */
00032 
00033 #include <Registration/cmtkVoxelMatchingElasticFunctional.h>
00034 
00035 #ifdef CMTK_BUILD_SMP
00036 #  include <Registration/cmtkParallelElasticFunctional.h>
00037 #endif
00038 
00039 #include <Registration/cmtkVoxelMatchingMutInf.h>
00040 #include <Registration/cmtkVoxelMatchingNormMutInf.h>
00041 #include <Registration/cmtkVoxelMatchingCorrRatio.h>
00042 #include <Registration/cmtkVoxelMatchingMeanSquaredDifference.h>
00043 #include <Registration/cmtkVoxelMatchingCrossCorrelation.h>
00044 
00045 #include <Base/cmtkInterpolator.h>
00046 #include <Base/cmtkSplineWarpXform.h>
00047 
00048 #include <vector>
00049 
00050 namespace
00051 cmtk
00052 {
00053 
00056 
00057 VoxelMatchingElasticFunctional::VoxelMatchingElasticFunctional
00058 ( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating )
00059   : VoxelMatchingFunctional( reference, floating ),
00060     m_ActiveCoordinates( NULL )
00061 {
00062   Dim = 0;
00063 
00064   ReferenceFrom = UniformVolume::CoordinateVectorType( UniformVolume::CoordinateVectorType::Init( 0 ) );
00065   ReferenceTo = reference->Size;
00066 
00067   this->m_AdaptiveFixParameters = false;
00068   this->m_AdaptiveFixThreshFactor = 0.5;
00069 
00070   VectorCache = Memory::AllocateArray<Vector3D>( ReferenceDims[0] );
00071   VolumeOfInfluence = NULL;
00072 }
00073 
00074 VoxelMatchingElasticFunctional::~VoxelMatchingElasticFunctional()
00075 {
00076   Memory::DeleteArray( VectorCache );
00077 }
00078 
00079 template<class W>
00080 void
00081 VoxelMatchingElasticFunctional_WarpTemplate<W>::WeightedDerivative
00082 ( double& lower, double& upper, W& warp, const int param, const Types::Coordinate step ) const
00083 {
00084   if ( this->m_JacobianConstraintWeight > 0 )
00085     {
00086     double lowerConstraint = 0, upperConstraint = 0;
00087     warp.GetJacobianConstraintDerivative( lowerConstraint, upperConstraint, param, VolumeOfInfluence[param], step );
00088     lower -= this->m_JacobianConstraintWeight * lowerConstraint;
00089     upper -= this->m_JacobianConstraintWeight * upperConstraint;
00090     } 
00091 
00092   if ( this->m_RigidityConstraintWeight > 0 )
00093     {
00094     double lowerConstraint = 0, upperConstraint = 0;
00095 
00096     if ( this->m_RigidityConstraintMap )
00097       {
00098       warp.GetRigidityConstraintDerivative( lowerConstraint, upperConstraint, param, VolumeOfInfluence[param], step, this->m_RigidityConstraintMap );
00099       }
00100     else
00101       {
00102       warp.GetRigidityConstraintDerivative( lowerConstraint, upperConstraint, param, VolumeOfInfluence[param], step );
00103       }
00104     lower -= this->m_RigidityConstraintWeight * lowerConstraint;
00105     upper -= this->m_RigidityConstraintWeight * upperConstraint;
00106     } 
00107   
00108   if ( this->m_GridEnergyWeight > 0 ) 
00109     {
00110     double lowerEnergy = 0, upperEnergy = 0;
00111     warp.GetGridEnergyDerivative( lowerEnergy, upperEnergy, param, step );
00112     lower -= this->m_GridEnergyWeight * lowerEnergy;
00113     upper -= this->m_GridEnergyWeight * upperEnergy;
00114     }
00115 
00116   // Catch infinite values that result from a folding grid. Effectively
00117   // prevent this by setting the gradient term to 0.
00118   if ( !finite(upper) || !finite(lower) ) 
00119     {
00120     lower = upper = 0;
00121     }
00122   else
00123     {
00124     if ( this->m_MatchedLandmarkList.GetPtr() ) 
00125       {
00126       double lowerMSD, upperMSD;
00127       warp.GetDerivativeLandmarksMSD( lowerMSD, upperMSD, this->m_MatchedLandmarkList, param, step );
00128       lower -= this->m_LandmarkErrorWeight * lowerMSD;
00129       upper -= this->m_LandmarkErrorWeight * upperMSD;
00130       }
00131     if ( InverseTransformation ) 
00132       {
00133       double lowerIC, upperIC;
00134       warp.GetDerivativeInverseConsistencyError( lowerIC, upperIC, this->InverseTransformation, this->ReferenceGrid, &(this->VolumeOfInfluence[param]), param, step );
00135       lower -= InverseConsistencyWeight * lowerIC;
00136       upper -= InverseConsistencyWeight * upperIC;
00137       }
00138     }
00139 }
00140 
00141 template<class W> 
00142 void
00143 VoxelMatchingElasticFunctional_WarpTemplate<W>::SetWarpXform
00144 ( typename W::SmartPtr& warp )
00145 {
00146   Warp = W::SmartPtr::DynamicCastFrom( warp );
00147   if ( Warp )
00148     {
00149     Warp->RegisterVolume( ReferenceGrid );
00150     
00151     if ( Dim != Warp->VariableParamVectorDim() ) 
00152       {
00153       if ( VolumeOfInfluence ) 
00154         Memory::DeleteArray( VolumeOfInfluence );
00155       Dim = Warp->VariableParamVectorDim();
00156       this->StepScaleVector.resize( Dim );
00157       this->VolumeOfInfluence = Memory::AllocateArray<DataGrid::RegionType>( Dim );
00158       }
00159     
00160     DataGrid::RegionType *VOIptr = this->VolumeOfInfluence;
00161     Vector3D fromVOI, toVOI;
00162     for ( size_t dim=0; dim<Dim; ++dim, ++VOIptr ) 
00163       {
00164       StepScaleVector[dim] = this->GetParamStep( dim );
00165       Warp->GetVolumeOfInfluence( dim, ReferenceFrom, ReferenceTo, fromVOI, toVOI );
00166        *VOIptr = this->GetReferenceGridRange( fromVOI, toVOI );
00167       }
00168     
00169     WarpNeedsFixUpdate = true;
00170   }
00171 }
00172 
00173 template<class VM>
00174 void
00175 VoxelMatchingElasticFunctional_Template<VM>::UpdateWarpFixedParameters() 
00176 {
00177   if ( !this->ConsistencyHistogram ) 
00178     {
00179     this->ConsistencyHistogram = JointHistogram<unsigned int>::SmartPtr( new JointHistogram<unsigned int>() );
00180     const unsigned int numSamplesX = this->Metric->DataX.NumberOfSamples;
00181     const Types::DataItemRange rangeX = this->Metric->DataX.GetValueRange();
00182     const unsigned int numBinsX = this->ConsistencyHistogram->CalcNumBins( numSamplesX, rangeX );
00183     
00184     const unsigned int numSamplesY = this->Metric->DataY.NumberOfSamples;
00185     const Types::DataItemRange rangeY = this->Metric->DataY.GetValueRange();
00186     unsigned int numBinsY = this->ConsistencyHistogram->CalcNumBins( numSamplesY, rangeY );
00187     
00188     this->ConsistencyHistogram->Resize( numBinsX, numBinsY );
00189     this->ConsistencyHistogram->SetRangeX( rangeX );
00190     this->ConsistencyHistogram->SetRangeY( rangeY );
00191     }
00192   
00193   int numCtrlPoints = this->Dim / 3;
00194   
00195   std::vector<double> mapRef( numCtrlPoints );
00196   std::vector<double> mapMod( numCtrlPoints );
00197 
00198   Vector3D fromVOI, toVOI;
00199   int pX, pY, pZ;
00200 
00201   int inactive = 0;
00202 
00203   const typename VM::Exchange unsetY = this->Metric->DataY.padding();
00204 
00205   if ( this->ReferenceDataClass == DATACLASS_LABEL ) 
00206     {
00207     if ( this->m_ActiveCoordinates )
00208       this->Warp->SetParametersActive( this->m_ActiveCoordinates );
00209     else
00210       this->Warp->SetParametersActive();
00211     
00212     for ( int ctrl = 0; ctrl < numCtrlPoints; ++ctrl ) 
00213       {
00216       this->Warp->GetVolumeOfInfluence( 3 * ctrl, this->ReferenceFrom, this->ReferenceTo, fromVOI, toVOI, 0 );
00217       const DataGrid::RegionType voi = this->GetReferenceGridRange( fromVOI, toVOI );
00218       
00219       int r = voi.From()[0] + this->DimsX * ( voi.From()[1] + this->DimsY * voi.From()[2] );
00220       
00221       bool active = false;
00222       for ( pZ = voi.From()[2]; (pZ < voi.To()[2]) && !active; ++pZ ) 
00223         {
00224         for ( pY = voi.From()[1]; (pY < voi.To()[1]) && !active; ++pY ) 
00225           {
00226           for ( pX = voi.From()[0]; (pX < voi.To()[0]); ++pX, ++r ) 
00227             {
00228             if ( ( this->Metric->GetSampleX( r ) != 0 ) || ( ( this->WarpedVolume[r] != unsetY ) && ( this->WarpedVolume[r] != 0 ) ) ) 
00229               {
00230               active = true;
00231               break;
00232               }
00233             }
00234           r += ( voi.From()[0] + ( this->DimsX-voi.To()[0] ) );
00235           }
00236         r += this->DimsX * ( voi.From()[1] + ( this->DimsY-voi.To()[1] ) );
00237         }
00238       
00239       if ( !active ) 
00240         {
00241         inactive += 3;
00242         
00243         int dim = 3 * ctrl;
00244         for ( int idx=0; idx<3; ++idx, ++dim ) 
00245           {
00246           this->Warp->SetParameterInactive( dim );
00247           }
00248         }
00249       }
00250     } 
00251   else
00252     {
00253     for ( int ctrl = 0; ctrl < numCtrlPoints; ++ctrl ) 
00254       {
00255       this->ConsistencyHistogram->Reset();
00256       
00257       // We cannot use the precomputed table of VOIs here because in "fast"
00258       // mode, these VOIs are smaller than we want them here.
00259       this->Warp->GetVolumeOfInfluence( 3 * ctrl, this->ReferenceFrom, this->ReferenceTo, fromVOI, toVOI, 0 );
00260       const DataGrid::RegionType voi = this->GetReferenceGridRange( fromVOI, toVOI );
00261       
00262       int r = voi.From()[0] + this->DimsX * ( voi.From()[1] + this->DimsY * voi.From()[2] );
00263       
00264       const int endOfLine = ( voi.From()[0] + ( this->DimsX-voi.To()[0]) );
00265       const int endOfPlane = this->DimsX * ( voi.From()[1] + (this->DimsY-voi.To()[1]) );
00266       
00267       for ( pZ = voi.From()[2]; pZ<voi.To()[2]; ++pZ ) 
00268         {
00269         for ( pY = voi.From()[1]; pY<voi.To()[1]; ++pY ) 
00270           {
00271           for ( pX = voi.From()[0]; pX<voi.To()[0]; ++pX, ++r ) 
00272             {
00273             // Continue metric computation.
00274             if ( WarpedVolume[r] != unsetY ) 
00275               {
00276               this->ConsistencyHistogram->Increment
00277                 ( this->ConsistencyHistogram->ValueToBinX( this->Metric->GetSampleX( r ) ), 
00278                   this->ConsistencyHistogram->ValueToBinY( this->WarpedVolume[r] ) );
00279               }
00280             }
00281           r += endOfLine;
00282           }
00283         r += endOfPlane;
00284         }
00285       this->ConsistencyHistogram->GetMarginalEntropies( mapRef[ctrl], mapMod[ctrl] );
00286       }
00287     
00288     double refMin = HUGE_VAL, refMax = -HUGE_VAL;
00289     double modMin = HUGE_VAL, modMax = -HUGE_VAL;
00290     for ( int ctrl=0; ctrl<numCtrlPoints; ++ctrl ) 
00291       {
00292       if ( mapRef[ctrl] < refMin ) refMin = mapRef[ctrl];
00293       if ( mapRef[ctrl] > refMax ) refMax = mapRef[ctrl];
00294       if ( mapMod[ctrl] < modMin ) modMin = mapMod[ctrl];
00295       if ( mapMod[ctrl] > modMax ) modMax = mapMod[ctrl];
00296       }
00297     
00298     const double refThresh = refMin + this->m_AdaptiveFixThreshFactor * (refMax - refMin);
00299     const double modThresh = modMin + this->m_AdaptiveFixThreshFactor * (modMax - modMin);
00300       
00301     if ( this->m_ActiveCoordinates )
00302       this->Warp->SetParametersActive( this->m_ActiveCoordinates );
00303     else
00304       this->Warp->SetParametersActive();
00305           
00306     for ( int ctrl=0; ctrl<numCtrlPoints; ++ctrl ) 
00307       {
00308       if (  ( mapRef[ctrl] < refThresh ) && ( mapMod[ctrl] < modThresh ) ) 
00309         {
00310         int dim = 3 * ctrl;
00311         for ( int idx=0; idx<3; ++idx, ++dim ) 
00312           {
00313           this->Warp->SetParameterInactive( dim );
00314           }
00315         inactive += 3;
00316         }
00317       }
00318     }
00319   
00320   for ( size_t idx = 0; idx < this->Dim; ++idx ) 
00321     {
00322 
00323     if ( this->Warp->GetParameterActive( idx ) )
00324       {
00325       this->StepScaleVector[idx] = this->GetParamStep( idx );
00326       }
00327     else
00328       {
00329       this->StepScaleVector[idx] = 0;
00330       }
00331     }
00332   
00333   fprintf( stderr, "Deactivated %d out of %d parameters.\n", inactive, (int)this->Dim );
00334   
00335   this->WarpNeedsFixUpdate = false;
00336 }
00337 
00338 VoxelMatchingElasticFunctional* 
00339 CreateElasticFunctional
00340 ( const int metric,
00341   UniformVolume::SmartPtr& refVolume, 
00342   UniformVolume::SmartPtr& fltVolume )
00343 {
00344 #ifdef CMTK_BUILD_SMP
00345   switch ( fltVolume->GetData()->GetDataClass() ) 
00346     {
00347     case DATACLASS_UNKNOWN :
00348     case DATACLASS_GREY :
00349       switch ( metric ) 
00350         {
00351         case 0:
00352           return new ParallelElasticFunctional< VoxelMatchingNormMutInf_Trilinear>( refVolume, fltVolume );
00353         case 1:
00354           return new ParallelElasticFunctional<VoxelMatchingMutInf_Trilinear>( refVolume, fltVolume );
00355         case 2:
00356           return new ParallelElasticFunctional<VoxelMatchingCorrRatio_Trilinear>( refVolume, fltVolume );
00357         case 3:
00358           return NULL; // masked nmi retired
00359         case 4:
00360           return new ParallelElasticFunctional<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00361         case 5:
00362           return new ParallelElasticFunctional<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00363         default:
00364           return NULL;
00365         }
00366     case DATACLASS_LABEL:
00367       switch ( metric ) 
00368         {
00369         case 0:
00370           return new ParallelElasticFunctional< VoxelMatchingNormMutInf_NearestNeighbor >( refVolume, fltVolume );
00371         case 1:
00372           return new ParallelElasticFunctional<VoxelMatchingMutInf_NearestNeighbor>( refVolume, fltVolume );
00373         case 2:
00374           return new ParallelElasticFunctional<VoxelMatchingCorrRatio_NearestNeighbor>( refVolume, fltVolume );
00375         case 3:
00376           return NULL; // masked nmi retired
00377         case 4:
00378           return new ParallelElasticFunctional<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00379         case 5:
00380           return new ParallelElasticFunctional<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00381         default:
00382           return NULL;
00383         }
00384     }
00385 
00386 #else // single processing
00387 
00388   switch ( fltVolume->GetData()->GetDataClass() ) 
00389     {
00390     case DATACLASS_UNKNOWN :
00391     case DATACLASS_GREY :
00392       switch ( metric ) 
00393         {
00394         case 0:
00395           return new VoxelMatchingElasticFunctional_Template< VoxelMatchingNormMutInf_Trilinear>( refVolume, fltVolume );
00396         case 1:
00397           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_Trilinear>( refVolume, fltVolume );
00398         case 2:
00399           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_Trilinear>( refVolume, fltVolume );
00400         case 3:
00401           return NULL; // masked nmi retired
00402         case 4:
00403           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00404         case 5:
00405           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00406         default:
00407           return NULL;
00408         }
00409     case DATACLASS_LABEL:    
00410       switch ( metric ) 
00411         {
00412         case 0:
00413           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingNormMutInf_NearestNeighbor>( refVolume, fltVolume );
00414         case 1:
00415           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_NearestNeighbor>( refVolume, fltVolume );
00416         case 2:
00417           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_NearestNeighbor>( refVolume, fltVolume );
00418         case 3:
00419           return NULL; // masked nmi retired
00420         case 4:
00421           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00422         case 5:
00423           return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00424       default:
00425         return NULL;
00426         }
00427     }
00428 #endif
00429   
00430   return NULL;
00431 }
00432 
00433 template class VoxelMatchingElasticFunctional_WarpTemplate<SplineWarpXform>;
00434 
00435 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingNormMutInf_Trilinear>;
00436 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingNormMutInf_NearestNeighbor>;
00437 
00438 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_Trilinear>;
00439 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_NearestNeighbor>;
00440 
00441 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_Trilinear>;
00442 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_NearestNeighbor>;
00443 
00444 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingCrossCorrelation>;
00445 
00446 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingMeanSquaredDifference>;
00447 
00448 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines