cmtkSplineWarpCongealingFunctional.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: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkSplineWarpCongealingFunctional.h"
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Base/cmtkMatrix.h>
00037 
00038 #include <System/cmtkThreadPool.h>
00039 #include <System/cmtkThreadParameterArray.h>
00040 
00041 #include <algorithm>
00042 
00043 namespace
00044 cmtk
00045 {
00046 
00049 
00050 void
00051 SplineWarpCongealingFunctional
00052 ::SetTemplateGrid
00053 ( UniformVolume::SmartPtr& templateGrid, 
00054   const int downsample,
00055   const bool useTemplateData )
00056 {
00057   this->Superclass::SetTemplateGrid( templateGrid, downsample, useTemplateData );
00058   // clear thread storage because we need to re-initialize these.
00059   this->m_StaticThreadStorage.resize(0);
00060 }
00061 
00062 void
00063 SplineWarpCongealingFunctional
00064 ::InitializeXformsFromAffine
00065 ( const Types::Coordinate gridSpacing, std::vector<AffineXform::SmartPtr> initialAffineXformsVector, const bool exactSpacing )
00066 {
00067   this->Superclass::InitializeXformsFromAffine( gridSpacing, initialAffineXformsVector, exactSpacing );
00068 
00069   // clear thread storage because we need to re-initialize these.
00070   this->m_StaticThreadStorage.resize(0);
00071 }
00072 
00073 void
00074 SplineWarpCongealingFunctional
00075 ::RefineTransformationGrids()
00076 {
00077   this->Superclass::RefineTransformationGrids();
00078   // clear thread storage because we need to re-initialize these.
00079   this->m_StaticThreadStorage.resize(0);
00080 }
00081 
00082 void
00083 SplineWarpCongealingFunctional
00084 ::UpdateStandardDeviationByPixel()
00085 {
00086   this->Superclass::UpdateStandardDeviationByPixel();
00087   this->UpdateActiveControlPoints();
00088   this->UpdateParamStepArray();
00089 }
00090 
00091 void
00092 SplineWarpCongealingFunctional
00093 ::UpdateActiveControlPoints()
00094 {
00095   if ( this->m_DeactivateUninformativeMode )
00096     {
00097     const size_t numberOfControlPoints = this->m_VolumeOfInfluenceArray.size();
00098     
00099     if ( numberOfControlPoints )
00100       {
00101       this->m_ActiveControlPointFlags.resize( numberOfControlPoints );
00102       this->m_NumberOfActiveControlPoints = 0;
00103       
00104       const Vector3D templateFrom( this->m_TemplateGrid->m_Offset );
00105       const Vector3D templateTo( this->m_TemplateGrid->m_Offset + this->m_TemplateGrid->Size );
00106       Vector3D fromVOI, toVOI;
00107       
00108       std::vector<DataGrid::RegionType>::const_iterator voi = this->m_VolumeOfInfluenceArray.begin();
00109       for ( size_t cp = 0; cp < numberOfControlPoints; ++cp, ++voi )
00110         {
00111         bool active = false;
00112         for ( int z = voi->From()[2]; (z < voi->To()[2]) && !active; ++z ) 
00113           {
00114           for ( int y = voi->From()[1]; (y < voi->To()[1]) && !active; ++y )
00115             {
00116             size_t ofs = this->m_TemplateGrid->GetOffsetFromIndex( voi->From()[0], y, z );
00117             for ( int x = voi->From()[0]; (x < voi->To()[0])  && !active; ++x, ++ofs )
00118               {
00119               if ( this->m_StandardDeviationByPixel[ofs] > 0 )
00120                 {
00121                 active = true;
00122                 }
00123               }
00124             }
00125           }
00126         this->m_ActiveControlPointFlags[cp] = active;
00127         if ( active ) ++this->m_NumberOfActiveControlPoints;
00128         }
00129 
00130       StdErr << "Enabled " << this->m_NumberOfActiveControlPoints << "/" << this->m_ParametersPerXform / 3 << " control points.\n";
00131       }
00132     }
00133   else
00134     {
00135     this->m_NumberOfActiveControlPoints = this->m_VolumeOfInfluenceArray.size();
00136     }
00137 }
00138 
00139 SplineWarpCongealingFunctional::ReturnType
00140 SplineWarpCongealingFunctional
00141 ::Evaluate()
00142 {
00143   if ( this->m_NeedsUpdateStandardDeviationByPixel )
00144     this->UpdateStandardDeviationByPixel();
00145 
00146   const size_t numberOfPixels = this->m_TemplateNumberOfPixels;
00147 #ifdef CMTK_BUILD_MPI
00148   const size_t pixelsPerNode = (numberOfPixels+this->m_SizeMPI-1) / this->m_SizeMPI;
00149   this->m_EntropyByPixel.resize( pixelsPerNode * this->m_SizeMPI );
00150   this->m_EntropyByPixelMPI.resize( pixelsPerNode );
00151 #else
00152   this->m_EntropyByPixel.resize( numberOfPixels );
00153 #endif
00154 
00155   double entropy = 0;
00156   unsigned int count = 0;
00157   
00158   ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00159   const size_t numberOfThreads = threadPool.GetNumberOfThreads();
00160   this->m_ThreadHistograms.resize( numberOfThreads );
00161 
00162   std::vector< EvaluateThreadParameters> params( numberOfThreads );
00163   for ( size_t taskIdx = 0; taskIdx < numberOfThreads; ++taskIdx )
00164     {
00165     params[taskIdx].thisObject = this;
00166     }
00167   threadPool.Run( EvaluateThread, params );
00168   
00169   // gather partial entropies from threads
00170   for ( size_t taskIdx = 0; taskIdx < numberOfThreads; ++taskIdx )
00171     {
00172     entropy += params[taskIdx].m_Entropy;
00173     count += params[taskIdx].m_Count;
00174     }
00175   
00176 #ifdef CMTK_BUILD_MPI
00177   double partialEntropy = entropy;
00178   MPI::COMM_WORLD.Allreduce( &partialEntropy, &entropy, 1, MPI::DOUBLE, MPI::SUM );
00179   
00180   unsigned int partialCount = count;
00181   MPI::COMM_WORLD.Allreduce( &partialCount, &count, 1, MPI::UNSIGNED, MPI::SUM );
00182 
00183   const size_t totalSize = sizeof( this->m_EntropyByPixelMPI[0] ) * this->m_EntropyByPixelMPI.size();
00184   MPI::COMM_WORLD.Allgather( &this->m_EntropyByPixelMPI[0], totalSize, MPI::CHAR, &this->m_EntropyByPixel[0], totalSize, MPI::CHAR );  
00185 #endif
00186   
00187   if ( count )
00188     {
00189     const double result = entropy / count;
00190     double constraint = 0;
00191     if ( this->m_JacobianConstraintWeight > 0 )
00192       {
00193       for ( size_t i = 0; i < this->m_XformVector.size(); ++i )
00194         {
00195         constraint += dynamic_cast<const SplineWarpXform*>( this->m_XformVector[i].GetPtr() )->GetJacobianConstraint();
00196         }
00197       }
00198     return result - this->m_JacobianConstraintWeight * constraint;
00199     }
00200   else
00201     return -FLT_MAX;
00202 }
00203 
00204 void
00205 SplineWarpCongealingFunctional
00206 ::EvaluateThread
00207 ( void *args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00208 {
00209   EvaluateThreadParameters* threadParameters = static_cast<EvaluateThreadParameters*>( args );
00210   
00211   Self* This = threadParameters->thisObject;
00212   const Self* ThisConst = threadParameters->thisObject;
00213   
00214   HistogramType& histogram = This->m_ThreadHistograms[threadIdx];
00215   histogram.Resize( ThisConst->m_HistogramBins + 2 * ThisConst->m_HistogramKernelRadiusMax, false /*reset*/ );
00216 
00217   double totalEntropy = 0;
00218   size_t count = 0;
00219 
00220   const size_t numberOfPixels = ThisConst->m_TemplateNumberOfPixels;
00221 #ifdef CMTK_BUILD_MPI  
00222   const size_t pixelsPerNode = (numberOfPixels+ThisConst->m_SizeMPI-1) / ThisConst->m_SizeMPI;
00223   const size_t pixelsPerThread = 1 + (pixelsPerNode / taskCnt);
00224   const size_t pixelFromNode = ThisConst->m_RankMPI * pixelsPerNode;
00225   const size_t pixelFrom = pixelFromNode + taskIdx * pixelsPerThread;
00226   const size_t pixelTo = std::min( numberOfPixels, std::min( pixelFromNode + pixelsPerNode, pixelFrom + pixelsPerThread ) );
00227   size_t mpiOfs = taskIdx * pixelsPerThread;
00228 #else
00229   const size_t pixelsPerThread = (numberOfPixels / taskCnt);
00230   const size_t pixelFrom = taskIdx * pixelsPerThread;
00231   const size_t pixelTo = std::min( numberOfPixels, pixelFrom + pixelsPerThread );
00232 #endif
00233   
00234   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00235   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00236   const byte paddingValue = ThisConst->m_PaddingValue;
00237   
00238   for ( size_t ofs = pixelFrom; ofs < pixelTo; ++ofs )
00239     {
00240     histogram.Reset();
00241     const size_t kernelIdx = ThisConst->m_StandardDeviationByPixel[ofs];
00242     const size_t kernelRadius = ThisConst->m_HistogramKernelRadius[kernelIdx];
00243     const HistogramBinType* kernel = ThisConst->m_HistogramKernel[kernelIdx];
00244 
00245     bool fullCount = true;
00246     
00247     if ( ThisConst->m_UseTemplateData )
00248       {
00249       const byte templateValue = ThisConst->m_TemplateData[ofs];
00250       if ( (fullCount = (templateValue != paddingValue)) )
00251         {
00252         histogram.AddWeightedSymmetricKernel( templateValue, kernelRadius, kernel );
00253         }
00254       }
00255 
00256     for ( size_t idx = imagesFrom; (idx < imagesTo) && fullCount; ++idx )
00257       {
00258       const byte value = ThisConst->m_Data[idx][ofs];
00259       if ( value != paddingValue )
00260         {
00261         histogram.AddWeightedSymmetricKernel( value, kernelRadius, kernel );
00262         }
00263       else
00264         {
00265         fullCount = false;
00266         }
00267       }
00268     
00269     if ( fullCount )
00270       {
00271       const double entropy = histogram.GetEntropy();
00272 #ifdef CMTK_BUILD_MPI
00273       This->m_EntropyByPixelMPI[mpiOfs++] = entropy;
00274 #else
00275       This->m_EntropyByPixel[ofs] = entropy;
00276 #endif
00277       totalEntropy -= entropy;
00278       ++count;
00279       }
00280     else
00281       {
00282 #ifdef CMTK_BUILD_MPI
00283       This->m_EntropyByPixelMPI[mpiOfs++] = 0;
00284 #else
00285       This->m_EntropyByPixel[ofs] = 0;
00286 #endif
00287       }
00288     }
00289   
00290   threadParameters->m_Entropy = totalEntropy;
00291   threadParameters->m_Count = count;
00292 }
00293 
00295 
00296 } // namespace cmtk
00297 
00298 #ifdef CMTK_BUILD_MPI
00299 #  include "cmtkSplineWarpCongealingFunctionalMPI.txx"
00300 #else
00301 #  include "cmtkSplineWarpCongealingFunctional.txx"
00302 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines