cmtkCongealingFunctional.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: 2464 $
00026 //
00027 //  $LastChangedDate: 2010-10-19 09:54:33 -0700 (Tue, 19 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torsten_at_home $
00030 //
00031 */
00032 
00033 #include "cmtkCongealingFunctional.h"
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Registration/cmtkScaleHistogramValueTrait.h>
00037 
00038 namespace
00039 cmtk
00040 {
00041 
00044 
00045 template<class TXform>
00046 CongealingFunctional<TXform>::CongealingFunctional() 
00047   : m_NeedsUpdateStandardDeviationByPixel( true )
00048 {
00049   this->SetNumberOfHistogramBins( this->m_HistogramBins );
00050 }
00051 
00052 template<class TXform>
00053 CongealingFunctional<TXform>::~CongealingFunctional()
00054 {
00055   for ( size_t idx = 0; idx < this->m_HistogramKernel.size(); ++idx )
00056     if ( this->m_HistogramKernel[idx] )
00057       Memory::DeleteArray( this->m_HistogramKernel[idx] );
00058   this->m_HistogramKernel.clear();
00059 }
00060 
00061 template<class TXform>
00062 void
00063 CongealingFunctional<TXform>
00064 ::SetNumberOfHistogramBins( const size_t numberOfHistogramBins )
00065 {
00066   this->m_HistogramBins = numberOfHistogramBins;
00067   this->m_HistogramKernelRadiusMax = this->m_HistogramBins / 2;
00068   this->CreateGaussianKernels();
00069 
00070   this->Superclass::SetNumberOfHistogramBins( numberOfHistogramBins );
00071 }
00072 
00073 template<class TXform>
00074 void
00075 CongealingFunctional<TXform>::CreateGaussianKernels()
00076 {
00077   for ( size_t idx = 0; idx < this->m_HistogramKernel.size(); ++idx )
00078     if ( this->m_HistogramKernel[idx] )
00079       Memory::DeleteArray( this->m_HistogramKernel[idx] );
00080 
00081   this->m_HistogramKernel.resize( this->m_HistogramKernelRadiusMax+1 );
00082   this->m_HistogramKernelRadius.resize( this->m_HistogramKernelRadiusMax+1 );
00083   for ( size_t idx = 0; idx <= this->m_HistogramKernelRadiusMax; ++idx )
00084     {
00085     const size_t radius = idx + 1;
00086     const double sigma = idx;
00087     
00088     this->m_HistogramKernelRadius[idx] = radius;
00089     this->m_HistogramKernel[idx] = Memory::AllocateArray<HistogramBinType>( radius );
00090     
00091     if ( idx < 1.0 )
00092       {
00093       this->m_HistogramKernel[idx][0] = cmtk::ScaleHistogramValueTrait<HistogramBinType>::Scale( 1.0 );
00094       for ( size_t i = 1; i < radius; ++i )
00095         this->m_HistogramKernel[idx][i] = cmtk::ScaleHistogramValueTrait<HistogramBinType>::Scale( 0.0 );
00096       }
00097     else
00098       {
00099       const double normFactor = 1.0/(sqrt(2*M_PI) * sigma);
00100       for ( size_t i = 0; i < radius; ++i )
00101         {
00102         this->m_HistogramKernel[idx][i] = cmtk::ScaleHistogramValueTrait<HistogramBinType>::Scale( normFactor * exp( -MathUtil::Square( 1.0 * i / sigma ) / 2 ) );
00103         }
00104       }
00105     }
00106 }
00107 
00108 template<class TXform>
00109 void
00110 CongealingFunctional<TXform>::SetTemplateGrid
00111 ( UniformVolume::SmartPtr& templateGrid,
00112   const int downsample,
00113   const bool useTemplateData )
00114 {  
00115   this->Superclass::SetTemplateGrid( templateGrid, downsample, useTemplateData );
00116   this->m_NeedsUpdateStandardDeviationByPixel = true;
00117 }
00118 
00119 template<class TXform>
00120 typename CongealingFunctional<TXform>::ReturnType
00121 CongealingFunctional<TXform>::Evaluate()
00122 {
00123   if ( this->m_NeedsUpdateStandardDeviationByPixel )
00124     this->UpdateStandardDeviationByPixel();
00125   
00126   double entropy = 0;
00127   unsigned int count = 0;
00128 
00129   this->m_ThreadHistograms.resize( this->m_NumberOfThreads );
00130 
00131   std::vector<EvaluateThreadParameters> params( this->m_NumberOfTasks );
00132   for ( size_t idx = 0; idx < this->m_NumberOfTasks; ++idx )
00133     params[idx].thisObject = this;
00134   
00135   ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00136   if ( this->m_ProbabilisticSamples.size() )
00137     threadPool.Run( Self::EvaluateProbabilisticThread, params );
00138   else
00139     threadPool.Run( Self::EvaluateThread, params );
00140   
00141   // gather partial entropies from tasks
00142   for ( size_t task = 0; task < this->m_NumberOfTasks; ++task )
00143     {
00144     entropy += params[task].m_Entropy;
00145     count += params[task].m_Count;
00146     }
00147 
00148 #ifdef CMTK_BUILD_MPI
00149   double partialEntropy = entropy;
00150   MPI::COMM_WORLD.Allreduce( &partialEntropy, &entropy, 1, MPI::DOUBLE, MPI::SUM );
00151   
00152   unsigned int partialCount = count;
00153   MPI::COMM_WORLD.Allreduce( &partialCount, &count, 1, MPI::UNSIGNED, MPI::SUM );
00154 #endif
00155   
00156   if ( count )
00157     return static_cast<typename Self::ReturnType>( entropy / count );
00158   else
00159     return -FLT_MAX;
00160 }
00161 
00162 template<class TXform>
00163 void
00164 CongealingFunctional<TXform>::EvaluateThread
00165 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00166 {
00167   EvaluateThreadParameters* threadParameters = static_cast<EvaluateThreadParameters*>( args );
00168   
00169   Self* This = threadParameters->thisObject;
00170   const Self* ThisConst = threadParameters->thisObject;
00171   
00172   HistogramType& histogram = This->m_ThreadHistograms[threadIdx];
00173   histogram.Resize( ThisConst->m_HistogramBins + 2 * ThisConst->m_HistogramKernelRadiusMax, false /*reset*/ );
00174   
00175   double entropy = 0;
00176   unsigned int count = 0;
00177 
00178   const size_t numberOfPixels = ThisConst->m_TemplateNumberOfPixels;
00179 #ifdef CMTK_BUILD_MPI  
00180   const size_t pixelsPerThread = 1+numberOfPixels / ( taskCnt * ThisConst->m_SizeMPI );
00181   const size_t pixelFrom = ( taskIdx + ThisConst->m_RankMPI * taskCnt ) * pixelsPerThread;
00182   const size_t pixelTo = std::min( numberOfPixels, pixelFrom + pixelsPerThread );
00183 #else
00184   const size_t pixelsPerThread = 1+(numberOfPixels / taskCnt);
00185   const size_t pixelFrom = taskIdx * pixelsPerThread;
00186   const size_t pixelTo = std::min( numberOfPixels, pixelFrom + pixelsPerThread );
00187 #endif
00188 
00189   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00190   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00191   const byte paddingValue = ThisConst->m_PaddingValue;
00192   
00193   for ( size_t ofs = pixelFrom; ofs < pixelTo; ++ofs )
00194     {
00195     histogram.Reset();
00196     const size_t kernelIdx = ThisConst->m_StandardDeviationByPixel[ofs];
00197     const size_t kernelRadius = ThisConst->m_HistogramKernelRadius[kernelIdx];
00198     const HistogramBinType* kernel = ThisConst->m_HistogramKernel[kernelIdx];
00199 
00200     bool fullCount = true;
00201     if ( ThisConst->m_UseTemplateData )
00202       {
00203       const byte templateValue = ThisConst->m_TemplateData[ofs];
00204       if ( (fullCount = (templateValue != paddingValue )) )
00205         {
00206         histogram.AddWeightedSymmetricKernel( templateValue, kernelRadius, kernel );
00207         }
00208       }
00209     
00210     for ( size_t idx = imagesFrom; (idx < imagesTo) && fullCount; ++idx )
00211       {
00212       const byte value = ThisConst->m_Data[idx][ofs];
00213       if ( value != paddingValue )
00214         {
00215         histogram.AddWeightedSymmetricKernel( value, kernelRadius, kernel );
00216         }
00217       else
00218         {
00219         fullCount = false;
00220         }
00221       }
00222 
00223     if ( fullCount )
00224       {
00225       entropy -= histogram.GetEntropy();
00226       ++count;
00227       }
00228     }
00229   
00230   threadParameters->m_Entropy = entropy;
00231   threadParameters->m_Count = count;
00232 }
00233 
00234 template<class TXform>
00235 void
00236 CongealingFunctional<TXform>::EvaluateProbabilisticThread
00237 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00238 {
00239   EvaluateThreadParameters* threadParameters = static_cast<EvaluateThreadParameters*>( args );
00240   
00241   Self* This = threadParameters->thisObject;
00242   const Self* ThisConst = threadParameters->thisObject;
00243   
00244   HistogramType& histogram = This->m_ThreadHistograms[threadIdx];
00245   histogram.Resize( ThisConst->m_HistogramBins + 2 * ThisConst->m_HistogramKernelRadiusMax, false /*reset*/ );
00246 
00247   double entropy = 0;
00248   unsigned int count = 0;
00249 
00250   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00251   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00252   const byte paddingValue = ThisConst->m_PaddingValue;
00253 
00254   const size_t numberOfSamples = ThisConst->m_ProbabilisticSamples.size();
00255 #ifdef CMTK_BUILD_MPI  
00256   const size_t samplesPerThread = numberOfSamples / ( taskCnt * ThisConst->m_SizeMPI );
00257   const size_t sampleFrom = ( taskIdx + ThisConst->m_RankMPI * taskCnt ) * samplesPerThread;
00258   const size_t sampleTo = std::min( numberOfSamples, sampleFrom + samplesPerThread );
00259 #else
00260   const size_t samplesPerThread = numberOfSamples / taskCnt;
00261   const size_t sampleFrom = taskIdx * samplesPerThread;
00262   const size_t sampleTo = std::min( numberOfSamples, sampleFrom + samplesPerThread );
00263 #endif
00264 
00265   for ( size_t sample = sampleFrom; sample < sampleTo; ++sample )
00266     {
00267     histogram.Reset();
00268     bool fullCount = true;
00269     
00270     const size_t kernelIdx = ThisConst->m_StandardDeviationByPixel[sample];
00271     const size_t kernelRadius = ThisConst->m_HistogramKernelRadius[kernelIdx];
00272     const HistogramBinType* kernel = ThisConst->m_HistogramKernel[kernelIdx];
00273 
00274     if ( ThisConst->m_UseTemplateData )
00275       {
00276       const byte templateValue = ThisConst->m_TemplateData[sample];
00277       if ( (fullCount = (templateValue != paddingValue)) )
00278         {
00279         histogram.AddWeightedSymmetricKernel( templateValue, kernelRadius, kernel );
00280         }
00281       }
00282     
00283     for ( size_t idx = imagesFrom; (idx < imagesTo) && fullCount; ++idx )
00284       {
00285       const byte value = ThisConst->m_Data[idx][sample];
00286       if ( value != paddingValue )
00287         {
00288         histogram.AddWeightedSymmetricKernel( value, kernelRadius, kernel );
00289         }
00290       else
00291         {
00292         fullCount = false;
00293         }
00294       }
00295     
00296     if ( fullCount )
00297       {
00298       entropy -= histogram.GetEntropy();
00299       ++count;
00300       } 
00301     else
00302       {
00303       }
00304     }
00305     
00306   threadParameters->m_Entropy = entropy;
00307   threadParameters->m_Count = count;
00308 }
00309 
00310 template<class TXform>
00311 bool
00312 CongealingFunctional<TXform>
00313 ::Wiggle()
00314 {
00315   bool wiggle = this->Superclass::Wiggle();
00316 
00317   if ( wiggle )
00318     {
00319     this->m_NeedsUpdateStandardDeviationByPixel = true;
00320     }
00321   
00322   return wiggle;
00323 }
00324 
00325 template<class TXform>
00326 void
00327 CongealingFunctional<TXform>
00328 ::UpdateStandardDeviationByPixel()
00329 {
00330   if ( this->m_ProbabilisticSamples.size() )
00331     {
00332     const size_t numberOfSamples = this->m_ProbabilisticSamples.size();
00333 #ifdef CMTK_BUILD_MPI
00334     const size_t samplesPerNode = (numberOfSamples+this->m_SizeMPI-1) / this->m_SizeMPI;
00335     this->m_StandardDeviationByPixel.resize( samplesPerNode * this->m_SizeMPI );
00336     this->m_StandardDeviationByPixelMPI.resize( samplesPerNode );
00337 #else
00338     this->m_StandardDeviationByPixel.resize( numberOfSamples );
00339 #endif
00340     }
00341   else
00342     {
00343     const size_t numberOfPixels = this->m_TemplateNumberOfPixels;
00344 #ifdef CMTK_BUILD_MPI
00345     const size_t pixelsPerNode = (numberOfPixels+this->m_SizeMPI-1) / this->m_SizeMPI;
00346     this->m_StandardDeviationByPixel.resize( pixelsPerNode * this->m_SizeMPI );
00347     this->m_StandardDeviationByPixelMPI.resize( pixelsPerNode );
00348 #else
00349     this->m_StandardDeviationByPixel.resize( numberOfPixels );
00350 #endif
00351     }
00352 
00353   std::vector<ThreadParametersType> params( this->m_NumberOfTasks );
00354   for ( size_t idx = 0; idx < this->m_NumberOfTasks; ++idx )
00355     params[idx].thisObject = this;
00356 
00357   ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00358   threadPool.Run( Self::UpdateStandardDeviationByPixelThreadFunc, params );
00359   
00360 #ifdef CMTK_BUILD_MPI
00361   MPI::COMM_WORLD.Allgather( &this->m_StandardDeviationByPixelMPI[0], this->m_StandardDeviationByPixelMPI.size(), 
00362                              MPI::CHAR, &this->m_StandardDeviationByPixel[0], this->m_StandardDeviationByPixelMPI.size(), MPI::CHAR );
00363 #endif
00364   
00365   this->m_NeedsUpdateStandardDeviationByPixel = false;
00366 }
00367 
00368 template<class TXform>
00369 void
00370 CongealingFunctional<TXform>
00371 ::UpdateStandardDeviationByPixelThreadFunc
00372 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t, const size_t )
00373 {
00374   ThreadParametersType* taskParameters = static_cast<ThreadParametersType*>( args );
00375   
00376   Self* This = taskParameters->thisObject;
00377   const Self* ThisConst = taskParameters->thisObject;
00378 
00379   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00380   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00381   const byte paddingValue = ThisConst->m_PaddingValue;
00382   
00383   if ( ThisConst->m_ProbabilisticSamples.size() )
00384     {
00385     const size_t numberOfSamples = ThisConst->m_ProbabilisticSamples.size();
00386 #ifdef CMTK_BUILD_MPI
00387     const size_t samplesPerNode = (numberOfSamples+ThisConst->m_SizeMPI-1) / ThisConst->m_SizeMPI;
00388     const size_t samplesPerTask = 1 + (samplesPerNode / taskCnt);
00389     const size_t sampleFromNode = ThisConst->m_RankMPI * samplesPerNode;
00390     const size_t sampleFrom = sampleFromNode + taskIdx * samplesPerTask;
00391     const size_t sampleTo = std::min( numberOfSamples, std::min( sampleFromNode + samplesPerNode, sampleFrom + samplesPerTask ) );
00392     size_t mpiSmpl = taskIdx * samplesPerTask;
00393 #else
00394     const size_t samplesPerTask = 1 + (numberOfSamples / taskCnt );
00395     const size_t sampleFrom = taskIdx * samplesPerTask;
00396     const size_t sampleTo = std::min( numberOfSamples, sampleFrom + samplesPerTask );
00397 #endif
00398 
00399     for ( size_t smpl = sampleFrom; smpl < sampleTo; ++smpl )
00400       {
00401       double sum = 0, sumsq = 0;
00402       unsigned int count = 0;
00403 
00404       if ( ThisConst->m_UseTemplateData )
00405         {
00406         const byte templateValue = ThisConst->m_TemplateData[smpl];
00407         if ( templateValue != paddingValue )
00408           {
00409           sum += templateValue;
00410           sumsq += templateValue * templateValue;
00411           ++count;
00412           }
00413         }
00414 
00415       for ( size_t idx = imagesFrom; idx < imagesTo; ++idx )
00416         {
00417         const byte value = ThisConst->m_Data[idx][smpl];
00418         if ( value != paddingValue )
00419           {
00420           const double data = static_cast<double>( value );
00421           sum += data;
00422           sumsq += data * data;
00423           ++count;
00424           }
00425         }
00426       
00427       if ( count )
00428         {
00429         const double mu = sum / count;
00430         const byte sdev = std::min<byte>( ThisConst->m_HistogramKernelRadiusMax, (byte)(sqrt(( count * mu * mu - 2 * mu * sum + sumsq ) / (count-1)) ) );
00431 
00432 #ifdef CMTK_BUILD_MPI
00433         This->m_StandardDeviationByPixelMPI[mpiSmpl++] = sdev;
00434 #else
00435         This->m_StandardDeviationByPixel[smpl] = sdev;
00436 #endif
00437         }
00438       else
00439         {
00440         This->m_StandardDeviationByPixel[smpl] = 0;
00441         }
00442       }
00443     }
00444   else
00445     {
00446     const size_t numberOfPixels = ThisConst->m_TemplateNumberOfPixels;
00447 #ifdef CMTK_BUILD_MPI
00448     const size_t pixelsPerNode = (numberOfPixels+ThisConst->m_SizeMPI-1) / ThisConst->m_SizeMPI;
00449     const size_t pixelsPerTask = 1 + (pixelsPerNode / taskCnt);
00450     const size_t pixelFromNode = ThisConst->m_RankMPI * pixelsPerNode;
00451     const size_t pixelFrom = pixelFromNode + taskIdx * pixelsPerTask;
00452     const size_t pixelTo = std::min( numberOfPixels, std::min( pixelFromNode + pixelsPerNode, pixelFrom + pixelsPerTask ) );
00453     size_t mpiPx = taskIdx * pixelsPerTask;
00454 #else
00455     const size_t pixelsPerTask = 1 + (numberOfPixels / taskCnt);
00456     const size_t pixelFrom = taskIdx * pixelsPerTask;
00457     const size_t pixelTo = std::min( numberOfPixels, pixelFrom + pixelsPerTask );
00458 #endif
00459     for ( size_t px = pixelFrom; px < pixelTo; ++px )
00460       {
00461       double sum = 0, sumsq = 0;
00462       unsigned int count = 0;
00463 
00464       if ( ThisConst->m_UseTemplateData )
00465         {
00466         const byte templateValue = ThisConst->m_TemplateData[px];
00467         if ( templateValue != paddingValue )
00468           {
00469           sum += templateValue;
00470           sumsq += templateValue * templateValue;
00471           ++count;
00472           }
00473         }
00474 
00475       for ( size_t idx = imagesFrom; idx < imagesTo; ++idx )
00476         {
00477         const byte value = ThisConst->m_Data[idx][px];
00478         if ( value != paddingValue )
00479           {
00480           const double data = static_cast<double>( value );
00481           sum += data;
00482           sumsq += data * data;
00483           ++count;
00484           }
00485         }
00486       
00487       if ( count )
00488         {
00489         const double mu = sum / count;
00490         const byte sdev = std::min<byte>( ThisConst->m_HistogramKernelRadiusMax, (byte)(sqrt(( count * mu * mu - 2 * mu * sum + sumsq ) / (count-1)) ) );
00491 #ifdef CMTK_BUILD_MPI
00492         This->m_StandardDeviationByPixelMPI[mpiPx++] = sdev;
00493 #else
00494         This->m_StandardDeviationByPixel[px] = sdev;
00495 #endif
00496         }
00497       else
00498         {
00499         This->m_StandardDeviationByPixel[px] = 0;
00500         }
00501       }
00502     }
00503 }
00504 
00506 
00507 } // namespace cmtk
00508 
00509 #include <Base/cmtkAffineXform.h>
00510 #include <Base/cmtkSplineWarpXform.h>
00511 
00512 template class cmtk::CongealingFunctional<cmtk::AffineXform>;
00513 template class cmtk::CongealingFunctional<cmtk::SplineWarpXform>;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines