cmtkGroupwiseRegistrationRMIFunctional.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 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: 2731 $
00026 //
00027 //  $LastChangedDate: 2011-01-13 16:22:47 -0800 (Thu, 13 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include <Registration/cmtkGroupwiseRegistrationRMIFunctional.h>
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <System/cmtkThreadPool.h>
00037 
00038 #include <algorithm>
00039 
00040 namespace
00041 cmtk
00042 {
00043 
00046 
00047 template<class TXform>
00048 GroupwiseRegistrationRMIFunctional<TXform>
00049 ::GroupwiseRegistrationRMIFunctional()
00050 {
00051   this->SetNumberOfHistogramBins( 255 );
00052 }
00053 
00054 template<class TXform>
00055 GroupwiseRegistrationRMIFunctional<TXform>
00056 ::~GroupwiseRegistrationRMIFunctional()
00057 {
00058 }
00059 
00060 template<class TXform>
00061 void
00062 GroupwiseRegistrationRMIFunctional<TXform>
00063 ::SetTemplateGrid
00064 ( UniformVolume::SmartPtr& templateGrid,
00065   const int downsample, 
00066   const bool useTemplateData )
00067 {  
00068   this->Superclass::SetTemplateGrid( templateGrid, downsample, useTemplateData );
00069 }
00070 
00071 template<class TXform>
00072 typename GroupwiseRegistrationRMIFunctional<TXform>::ReturnType
00073 GroupwiseRegistrationRMIFunctional<TXform>
00074 ::Evaluate()
00075 {
00076   ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00077   const size_t numberOfImages = this->m_ImageVector.size();
00078 
00079   this->m_CovarianceMatrix.Resize( numberOfImages, numberOfImages ); // needs no reset
00080   this->m_TotalNumberOfSamples = 0;
00081 
00082   this->m_SumOfProductsMatrix.resize( numberOfImages * (1+numberOfImages) / 2 );
00083   std::fill( this->m_SumOfProductsMatrix.begin(), this->m_SumOfProductsMatrix.end(), 0 );
00084 
00085   this->m_SumsVector.resize( numberOfImages );
00086   std::fill( this->m_SumsVector.begin(), this->m_SumsVector.end(), 0 );
00087 
00088   this->m_ThreadSumOfProductsMatrix.resize( this->m_NumberOfThreads );
00089   this->m_ThreadSumsVector.resize( this->m_NumberOfThreads );
00090 
00091   std::vector<EvaluateThreadParameters> params( this->m_NumberOfTasks );
00092   for ( size_t taskIdx = 0; taskIdx < this->m_NumberOfTasks; ++taskIdx )
00093     {
00094     params[taskIdx].thisObject = this;
00095     }
00096   
00097   if ( this->m_ProbabilisticSamples.size() )
00098     threadPool.Run( EvaluateProbabilisticThread, params );
00099   else
00100     threadPool.Run( EvaluateThread, params );
00101   
00102 #ifdef CMTK_BUILD_MPI
00103   SumsAndProductsVectorType tmpVector( this->m_SumOfProductsMatrix.size() );
00104   MPI::COMM_WORLD.Allreduce( &(this->m_SumOfProductsMatrix[0]), &(tmpVector[0]), this->m_SumOfProductsMatrix.size(), MPI::LONG, MPI::SUM );
00105   std::copy( tmpVector.begin(), tmpVector.end(), this->m_SumOfProductsMatrix.begin() );
00106   
00107   tmpVector.resize( this->m_SumsVector.size() );
00108   MPI::COMM_WORLD.Allreduce( &(this->m_SumsVector[0]), &(tmpVector[0]), this->m_SumsVector.size(), MPI::LONG, MPI::SUM );
00109   std::copy( tmpVector.begin(), tmpVector.end(), this->m_SumsVector.begin() );
00110 
00111   unsigned int totalNumberOfSamples = this->m_TotalNumberOfSamples;
00112   MPI::COMM_WORLD.Allreduce( &totalNumberOfSamples, &this->m_TotalNumberOfSamples, 1, MPI::UNSIGNED, MPI::SUM );
00113 #endif
00114 
00115   const float result = this->GetMetric( this->m_SumOfProductsMatrix, this->m_SumsVector, this->m_TotalNumberOfSamples, this->m_CovarianceMatrix );
00116 
00117   return result;
00118 }
00119 
00120 template<class TXform>
00121 typename GroupwiseRegistrationRMIFunctional<TXform>::ReturnType
00122 GroupwiseRegistrationRMIFunctional<TXform>
00123 ::GetMetric
00124 ( const SumsAndProductsVectorType& sumOfProductsMatrix, 
00125   const SumsAndProductsVectorType& sumsVector,
00126   const unsigned int totalNumberOfSamples,
00127   typename GroupwiseRegistrationRMIFunctional<TXform>::CovarianceMatrixType& covarianceMatrix ) const
00128 {
00129   const size_t imagesFrom = this->m_ActiveImagesFrom;
00130   const size_t imagesTo = this->m_ActiveImagesTo;
00131   const size_t numberOfImages = imagesTo - imagesFrom;
00132 
00133   size_t midx = 0;
00134   for ( size_t j = 0; j < numberOfImages; ++j )
00135     {
00136     for ( size_t i = 0; i <= j; ++i, ++midx )
00137       {
00138       covarianceMatrix[i][j] = covarianceMatrix[j][i] = (sumOfProductsMatrix[midx] - ((1.0 * sumsVector[i] * sumsVector[j]) / totalNumberOfSamples)) / totalNumberOfSamples;
00139       }
00140     }
00141   
00142   std::vector<typename Self::ReturnType> eigenvalues( numberOfImages );
00143   MathUtil::ComputeEigenvalues<typename Self::ReturnType>( covarianceMatrix, eigenvalues );
00144 
00145   const typename Self::ReturnType EIGENVALUE_THRESHOLD = 1e-6;
00146   typename Self::ReturnType determinant = 1.0;
00147   for ( size_t i = 0; i < numberOfImages; ++i )
00148     {
00149     if ( eigenvalues[i] > EIGENVALUE_THRESHOLD )
00150       determinant *= eigenvalues[i];
00151     }
00152   
00153   if ( determinant > 0 )
00154     {
00155     const static double alpha = 1.41893853320467;
00156     typename Self::ReturnType metric = numberOfImages*alpha + .5*log( determinant );    
00157     return -metric;
00158     }
00159   else
00160     {
00161     return -FLT_MAX;
00162     }
00163 }
00164 
00165 template<class TXform>
00166 void
00167 GroupwiseRegistrationRMIFunctional<TXform>
00168 ::EvaluateThread
00169 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00170 {
00171   EvaluateThreadParameters* threadParameters = static_cast<EvaluateThreadParameters*>( args );
00172   
00173   Self* This = threadParameters->thisObject;
00174   const Self* ThisConst = threadParameters->thisObject;
00175   
00176   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00177   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00178   const size_t numberOfImages = imagesTo - imagesFrom;
00179   
00180   const byte paddingValue = ThisConst->m_PaddingValue;
00181 
00182   SumsAndProductsVectorType& sumOfProductsMatrix = This->m_ThreadSumOfProductsMatrix[threadIdx];
00183   sumOfProductsMatrix.resize( numberOfImages * (1+numberOfImages) / 2 );
00184   std::fill( sumOfProductsMatrix.begin(), sumOfProductsMatrix.end(), 0 );
00185   
00186   SumsAndProductsVectorType& sumsVector = This->m_ThreadSumsVector[threadIdx];
00187   sumsVector.resize( numberOfImages );
00188   std::fill( sumsVector.begin(), sumsVector.end(), 0 );
00189 
00190   size_t totalNumberOfSamples = 0;
00191 
00192   const size_t numberOfPixels = ThisConst->m_TemplateNumberOfPixels;
00193 #ifdef CMTK_BUILD_MPI  
00194   const size_t pixelsPerTask = 1+(numberOfPixels / ( taskCnt * ThisConst->m_SizeMPI ));
00195   const size_t pixelFrom = ( taskIdx + ThisConst->m_RankMPI * taskCnt ) * pixelsPerTask;
00196   const size_t pixelTo = std::min( numberOfPixels, pixelFrom + pixelsPerTask );
00197 #else
00198   const size_t pixelsPerTask = 1+(numberOfPixels / taskCnt);
00199   const size_t pixelFrom = taskIdx * pixelsPerTask;
00200   const size_t pixelTo = std::min( numberOfPixels, pixelFrom + pixelsPerTask );
00201 #endif
00202 
00203   for ( size_t ofs = pixelFrom; ofs < pixelTo; ++ofs )
00204     {
00205     bool allValid = This->m_Data[imagesFrom][ofs] != paddingValue;
00206     for ( size_t j = imagesFrom+1; allValid && (j < imagesTo); ++j )
00207       {
00208       allValid = This->m_Data[j][ofs] != paddingValue;
00209       }
00210 
00211     if ( allValid )
00212       {
00213       size_t midx = 0;
00214       for ( size_t j = imagesFrom; j < imagesTo; ++j )
00215         {
00216         const int dataJ = This->m_Data[j][ofs];
00217         sumsVector[j-imagesFrom] += dataJ;
00218           
00219         for ( size_t i = imagesFrom; i <= j; ++i, ++midx )
00220           {
00221           const int dataI = This->m_Data[i][ofs];
00222           sumOfProductsMatrix[midx] += dataI * dataJ;
00223           ++totalNumberOfSamples;
00224           }
00225         }
00226       }
00227     }
00228 
00229   // add our contribution to total results
00230   This->m_MutexLock.Lock();
00231   size_t midx = 0;
00232   for ( size_t j = imagesFrom; j < imagesTo; ++j )
00233     {
00234     This->m_SumsVector[j-imagesFrom] += sumsVector[j-imagesFrom];
00235     
00236     for ( size_t i = imagesFrom; i <= j; ++i, ++midx )
00237       {
00238       This->m_SumOfProductsMatrix[midx] += sumOfProductsMatrix[midx];
00239       }
00240     }
00241   This->m_TotalNumberOfSamples += totalNumberOfSamples;
00242   This->m_MutexLock.Unlock();
00243 }
00244 
00245 template<class TXform>
00246 void
00247 GroupwiseRegistrationRMIFunctional<TXform>
00248 ::EvaluateProbabilisticThread
00249 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00250 {
00251   EvaluateThreadParameters* threadParameters = static_cast<EvaluateThreadParameters*>( args );
00252   
00253   Self* This = threadParameters->thisObject;
00254   const Self* ThisConst = threadParameters->thisObject;
00255   
00256   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00257   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00258   const size_t numberOfImages = imagesTo - imagesFrom;
00259   
00260   const byte paddingValue = ThisConst->m_PaddingValue;
00261 
00262   SumsAndProductsVectorType& sumOfProductsMatrix = This->m_ThreadSumOfProductsMatrix[threadIdx];
00263   sumOfProductsMatrix.resize( numberOfImages * (1+numberOfImages) / 2 );
00264   std::fill( sumOfProductsMatrix.begin(), sumOfProductsMatrix.end(), 0 );
00265   
00266   SumsAndProductsVectorType& sumsVector = This->m_ThreadSumsVector[threadIdx];
00267   sumsVector.resize( numberOfImages );
00268   std::fill( sumsVector.begin(), sumsVector.end(), 0 );
00269 
00270   const size_t numberOfSamples = ThisConst->m_ProbabilisticSamples.size();
00271 #ifdef CMTK_BUILD_MPI  
00272   const size_t samplesPerTask = 1+(numberOfSamples / ( taskCnt * ThisConst->m_SizeMPI ));
00273   const size_t sampleFrom = ( taskIdx + ThisConst->m_RankMPI * taskCnt ) * samplesPerTask;
00274   const size_t sampleTo = std::min( numberOfSamples, sampleFrom + samplesPerTask );
00275 #else
00276   const size_t samplesPerTask = 1+(numberOfSamples / taskCnt);
00277   const size_t sampleFrom = taskIdx * samplesPerTask;
00278   const size_t sampleTo = std::min( numberOfSamples, sampleFrom + samplesPerTask );
00279 #endif
00280 
00281   size_t totalNumberOfSamples = 0;
00282   for ( size_t sample = sampleFrom; sample < sampleTo; ++sample )
00283     {
00284     bool allValid = This->m_Data[imagesFrom][sample] != paddingValue;
00285     for ( size_t j = imagesFrom+1; allValid && (j < imagesTo); ++j )
00286       {
00287       allValid = (This->m_Data[j][sample] != paddingValue);
00288       }
00289     
00290     if ( allValid )
00291       {
00292       size_t midx = 0;
00293       for ( size_t j = imagesFrom; j < imagesTo; ++j )
00294         {
00295         const int dataJ = This->m_Data[j][sample];
00296         sumsVector[j-imagesFrom] += dataJ;
00297           
00298         for ( size_t i = imagesFrom; i <= j; ++i, ++midx )
00299           {
00300           const int dataI = This->m_Data[i][sample];
00301           sumOfProductsMatrix[midx] += dataI * dataJ;
00302           ++totalNumberOfSamples;
00303           }
00304         }
00305       }
00306     }
00307   
00308   // add our contribution to total results
00309   This->m_MutexLock.Lock();
00310   size_t midx = 0;
00311   for ( size_t j = imagesFrom; j < imagesTo; ++j )
00312     {
00313     This->m_SumsVector[j-imagesFrom] += sumsVector[j-imagesFrom];
00314     for ( size_t i = imagesFrom; i <= j; ++i, ++midx )
00315       {
00316       This->m_SumOfProductsMatrix[midx] += sumOfProductsMatrix[midx];    
00317       }
00318     }
00319   This->m_TotalNumberOfSamples += totalNumberOfSamples;
00320   This->m_MutexLock.Unlock();
00321 }
00322 
00323 template<class TXform>
00324 typename GroupwiseRegistrationRMIFunctional<TXform>::ReturnType
00325 GroupwiseRegistrationRMIFunctional<TXform>
00326 ::EvaluateWithGradient
00327 ( CoordinateVector& v, CoordinateVector& g, const Types::Coordinate step )
00328 {
00329   const typename Self::ReturnType baseValue = this->EvaluateAt( v );
00330 
00331   for ( size_t param = 0; param < this->ParamVectorDim(); ++param )
00332     {
00333     g[param] = 0.0;
00334 
00335     const size_t imageIndex = param / this->m_ParametersPerXform;
00336     const size_t paramIndex = param % this->m_ParametersPerXform;
00337 
00338     const Types::Coordinate pStep = this->GetParamStep( param, step );
00339     if ( pStep > 0 )
00340       {
00341       byte* tmp = this->m_Data[imageIndex];
00342       this->m_Data[imageIndex] = &(this->m_TempData[0]);
00343 
00344       const Types::Coordinate p0 = v[param];
00345 
00346       this->SetParameter( imageIndex, paramIndex, p0 + pStep );
00347       this->InterpolateImage( imageIndex, this->m_Data[imageIndex] );
00348       const  typename Self::ReturnType upper = this->Evaluate();
00349 
00350       this->SetParameter( imageIndex, paramIndex, p0 - pStep );
00351       this->InterpolateImage( imageIndex, this->m_Data[imageIndex] );
00352       const  typename Self::ReturnType lower = this->Evaluate();
00353 
00354       this->m_Data[imageIndex] = tmp;
00355       this->SetParameter( imageIndex, paramIndex, p0 );
00356 
00357       if ( (upper > baseValue) || (lower > baseValue) )
00358         {
00359         g[param] = (upper - lower);
00360         }
00361       }
00362     }
00363 
00364   if ( this->m_ForceZeroSum )
00365     {
00366     this->ForceZeroSumGradient( g );
00367     }
00368 
00369   return baseValue;
00370 }
00371 
00372 template<class TXform>
00373 bool
00374 GroupwiseRegistrationRMIFunctional<TXform>
00375 ::Wiggle()
00376 {
00377   bool wiggle = this->Superclass::Wiggle();
00378 
00379   if ( wiggle )
00380     {
00381     }
00382   
00383   return wiggle;
00384 }
00385 
00387 
00388 } // namespace cmtk
00389 
00390 #include <Base/cmtkAffineXform.h>
00391 #include <Base/cmtkSplineWarpXform.h>
00392 
00393 template class cmtk::GroupwiseRegistrationRMIFunctional<cmtk::AffineXform>;
00394 template class cmtk::GroupwiseRegistrationRMIFunctional<cmtk::SplineWarpXform>;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines