cmtkSplineWarpCongealingFunctional.txx

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: 2453 $
00026 //
00027 //  $LastChangedDate: 2010-10-18 10:33:06 -0700 (Mon, 18 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 namespace
00034 cmtk
00035 {
00036 
00039 
00040 SplineWarpCongealingFunctional::ReturnType
00041 SplineWarpCongealingFunctional
00042 ::EvaluateWithGradient
00043 ( CoordinateVector& v, CoordinateVector& g, const Types::Coordinate step )
00044 {
00045   const size_t numberOfThreads = Threads::GetNumberOfThreads();
00046   this->m_ThreadHistograms.resize( numberOfThreads );
00047   
00048   const Self::ReturnType baseValue = this->EvaluateAt( v );
00049 
00050   this->m_ControlPointIndexNext = 0;
00051   this->m_ControlPointIndexLast = this->m_ParametersPerXform / 3;
00052   
00053   if ( this->m_StaticThreadStorage.size() != numberOfThreads )
00054     {
00055     this->m_StaticThreadStorage.resize( numberOfThreads );
00056     for ( size_t thread = 0; thread < numberOfThreads; ++thread )
00057       {
00058       this->m_StaticThreadStorage[thread].Initialize( this );
00059       }
00060     }
00061   else
00062     {
00063     for ( size_t thread = 0; thread < numberOfThreads; ++thread )
00064       {
00065       this->m_StaticThreadStorage[thread].m_NeedToCopyXformParameters = true;
00066       }
00067     }
00068       
00069   ThreadParameterArray<Self,EvaluateLocalGradientThreadParameters> threadParams( this, numberOfThreads );
00070   for ( size_t thread = 0; thread < numberOfThreads; ++thread )
00071     {
00072     threadParams[thread].m_Step = step;
00073     threadParams[thread].m_Gradient = g.Elements;
00074     }
00075   threadParams.RunInParallel( EvaluateLocalGradientThreadFunc );
00076 
00077   if ( this->m_PartialGradientMode )
00078     {
00079     const Types::Coordinate gthresh = g.MaxNorm() * this->m_PartialGradientThreshold;
00080 #pragma omp parallel for
00081     for ( size_t param = 0; param < g.Dim; ++param )
00082       if ( fabs( g[param] ) < gthresh )
00083         {
00084         g[param] = this->m_ParamStepArray[param] = 0.0;
00085         }
00086     }
00087   
00088   if ( this->m_ForceZeroSum )
00089     {
00090     this->ForceZeroSumGradient( g );
00091     }
00092   
00093   return baseValue;
00094 }
00095 
00096 CMTK_THREAD_RETURN_TYPE
00097 SplineWarpCongealingFunctional
00098 ::EvaluateLocalGradientThreadFunc
00099 ( void* args )
00100 {
00101   EvaluateLocalGradientThreadParameters* threadParameters = static_cast<EvaluateLocalGradientThreadParameters*>( args );
00102   
00103   Self* This = threadParameters->thisObject;
00104   const Self* ThisConst = This;
00105   const size_t threadID = threadParameters->ThisThreadIndex;
00106   
00107   const size_t numberOfXforms = ThisConst->m_XformVector.size();
00108   const size_t parametersPerXform = ThisConst->m_ParametersPerXform;
00109   const size_t paramVectorDim = ThisConst->ParamVectorDim();
00110   
00111   const byte paddingValue = ThisConst->m_PaddingValue;
00112   const size_t imagesFrom = ThisConst->m_ActiveImagesFrom;
00113   const size_t imagesTo = ThisConst->m_ActiveImagesTo;
00114   const size_t numberOfImages = imagesTo - imagesFrom;
00115   const size_t numberOfImagesIncludingTemplate = ThisConst->m_UseTemplateData ? numberOfImages+1 : numberOfImages;
00116   
00117   Self::StaticThreadStorage* threadStorage = (&This->m_StaticThreadStorage[threadID]);
00118   if ( threadStorage->m_NeedToCopyXformParameters )
00119     {
00120     for ( size_t xi = 0; xi < numberOfXforms; ++xi )
00121       {
00122       threadStorage->m_Xforms[xi]->CopyParamVector( This->GetXformByIndex(xi) );
00123       threadStorage->m_NeedToCopyXformParameters = false;
00124       }
00125     }
00126     
00127   const UniformVolume* templateGrid = ThisConst->m_TemplateGrid;  
00128   const size_t numberOfControlPoints = ThisConst->m_ParametersPerXform / 3;
00129 
00130   size_t cpIndex;
00131 
00132   This->m_ControlPointIndexLock.Lock();
00133   while ( (cpIndex = This->m_ControlPointIndexNext) < This->m_ControlPointIndexLast )
00134     {
00135     ++This->m_ControlPointIndexNext;
00136     This->m_ControlPointIndexLock.Unlock();
00137 
00138     if ( !threadID && !(cpIndex % 1000) )
00139       {
00140       std::cerr << cpIndex << " / " << numberOfControlPoints << "\r";
00141       }    
00142     
00143     std::vector<DataGrid::RegionType>::const_iterator voi = ThisConst->m_VolumeOfInfluenceArray.begin() + cpIndex;
00144 
00145     const size_t pixelsPerLineVOI = (voi->To()[0]-voi->From()[0]);
00146 
00147     std::fill( threadStorage->m_FPlus.begin(), threadStorage->m_FPlus.end(), static_cast<Self::ReturnType>( 0 ) );
00148     std::fill( threadStorage->m_FMinus.begin(), threadStorage->m_FMinus.end(), static_cast<Self::ReturnType>( 0 ) );
00149     std::fill( threadStorage->m_CountByParameterPlus.begin(), threadStorage->m_CountByParameterPlus.end(), 0 );
00150     std::fill( threadStorage->m_CountByParameterMinus.begin(), threadStorage->m_CountByParameterMinus.end(), 0 );
00151     
00152     for ( int z = voi->From()[2]; (z < voi->To()[2]); ++z ) 
00153       {
00154       for ( int y = voi->From()[1]; (y < voi->To()[1]); ++y )
00155         {
00156         // evaluate baseline entropies for this row
00157         const size_t rowofs = templateGrid->GetOffsetFromIndex( voi->From()[0], y, z );
00158         
00159         size_t ofs = rowofs;
00160         for ( size_t x = 0; x < pixelsPerLineVOI; ++x, ++ofs )
00161           {
00162           threadStorage->m_Histogram[x].Reset();
00163           threadStorage->m_Count[x] = 0;
00164           
00165           const size_t kernelIdx = ThisConst->m_StandardDeviationByPixel[ofs];
00166           const size_t kernelRadius = ThisConst->m_HistogramKernelRadius[kernelIdx];
00167           const HistogramBinType* kernel = ThisConst->m_HistogramKernel[kernelIdx];
00168           
00169           if ( ThisConst->m_UseTemplateData )
00170             {
00171             const byte templateValue = ThisConst->m_TemplateData[ofs];
00172             if ( templateValue != paddingValue )
00173               {
00174               threadStorage->m_Histogram[x].AddWeightedSymmetricKernel( templateValue, kernelRadius, kernel );
00175               ++threadStorage->m_Count[x];
00176               }
00177             }
00178 
00179           for ( size_t img = imagesFrom; img < imagesTo; ++img )
00180             { 
00181             const byte dataThisPixel = ThisConst->m_Data[img][ofs];
00182             if ( dataThisPixel != paddingValue )
00183               {
00184               threadStorage->m_Histogram[x].AddWeightedSymmetricKernel( dataThisPixel, kernelRadius, kernel );
00185               ++threadStorage->m_Count[x];
00186               }
00187             }
00188           }
00189         
00190         size_t cparam = 3 * cpIndex;
00191         size_t currentParameter = 0;
00192         for ( size_t imageIdx = 0; imageIdx < numberOfXforms; ++imageIdx, cparam += parametersPerXform )
00193           {
00194           SplineWarpXform::SmartPtr xform = threadStorage->m_Xforms[imageIdx];
00195           const UniformVolume* target = ThisConst->m_ImageVector[imageIdx];
00196           const byte* dataPtr = static_cast<const byte*>( target->GetData()->GetDataPtr() );
00197           
00198           for ( size_t dim = 0; dim < 3; ++dim, ++currentParameter )
00199             {
00200             const size_t cdparam = cparam + dim;
00201             const size_t xfparam = 3 * cpIndex + dim;
00202             const Types::Coordinate pStep = ThisConst->m_ParamStepArray[cdparam] * threadParameters->m_Step;
00203             
00204             if ( pStep > 0 )
00205               {
00206               const Types::Coordinate v0 = xform->GetParameter( xfparam );
00207               for ( int delta = 0; delta < 2; ++delta )
00208                 {
00209                 Types::Coordinate vTest = v0 + (2*delta-1) * pStep;
00210                 xform->SetParameter( xfparam, vTest );
00211                 
00212                 xform->GetTransformedGridRow( pixelsPerLineVOI, &(threadStorage->m_VectorList[0]), voi->From()[0], y, z );
00213                 
00214                 size_t ofs = rowofs;
00215                 for ( size_t x = 0; x < pixelsPerLineVOI; ++x, ++ofs )
00216                   {
00217                   if ( threadStorage->m_Count[x] == numberOfImagesIncludingTemplate ) // full count?
00218                     {
00219                     const byte baselineData = ThisConst->m_Data[imageIdx][ofs];
00220                     HistogramType& workingHistogram = threadStorage->m_Histogram[x];
00221                     
00222                     const size_t kernelIdx = ThisConst->m_StandardDeviationByPixel[ofs];
00223                     const size_t kernelRadius = ThisConst->m_HistogramKernelRadius[kernelIdx];
00224                     const HistogramBinType* kernel = ThisConst->m_HistogramKernel[kernelIdx];
00225                     
00226                     byte value;
00227                     if ( (baselineData != paddingValue) && target->ProbeData( value, dataPtr, threadStorage->m_VectorList[x] ) )
00228                       {
00229                       if ( value != paddingValue )
00230                         {
00231                         if ( delta )
00232                           ++threadStorage->m_CountByParameterPlus[currentParameter];
00233                         else
00234                           ++threadStorage->m_CountByParameterMinus[currentParameter];
00235                         
00236                         if ( value != baselineData )
00237                           {
00238                           double fd = 0;
00239                           double invsamples = 1.0 / workingHistogram.SampleCount();
00240                           
00241                           const size_t idxMin = std::min( value, baselineData ) - kernelRadius;
00242                           const size_t idxMax = std::max( value, baselineData ) + kernelRadius + 1;
00243                           
00244                           for ( size_t idx = idxMin; idx < idxMax; ++idx )
00245                             {
00246                             const size_t idxV = abs((int)(idx - value));
00247                             const double kernelIn = ( idxV < kernelRadius ) ? kernel[idxV] : 0;
00248                             
00249                             const size_t idxB = abs((int)(idx - baselineData));
00250                             const double kernelOut = ( idxB < kernelRadius ) ? kernel[idxB] : 0;
00251                             
00252                             if ( (kernelIn > 0) || (kernelOut > 0) )
00253                               {
00254                               fd += MathUtil::plogp( invsamples * (workingHistogram[idx] - kernelOut + kernelIn) ) - MathUtil::plogp( invsamples * workingHistogram[idx] );
00255                               }
00256                             }
00257                           
00258                           if ( delta ) 
00259                             threadStorage->m_FPlus[currentParameter] += fd;
00260                           else
00261                             threadStorage->m_FMinus[currentParameter] += fd;
00262                           }
00263                         }
00264                       }
00265                     }
00266                   }
00267                 }
00268               xform->SetParameter( xfparam, v0 );
00269               }
00270             }
00271           }
00272         }
00273       }
00274     
00275     size_t imageDimIdx = 0;
00276     for ( size_t cparam = 3*cpIndex; cparam < paramVectorDim; cparam += parametersPerXform )
00277       {
00278       for ( size_t dim = 0; dim < 3; ++dim, ++imageDimIdx )
00279         {
00280         const size_t cdparam = cparam+dim;
00281         threadParameters->m_Gradient[cdparam] = 0.0;
00282         if ( threadStorage->m_CountByParameterPlus[imageDimIdx] && threadStorage->m_CountByParameterMinus[imageDimIdx] )
00283           {
00284           double upper = threadStorage->m_FPlus[imageDimIdx] / threadStorage->m_CountByParameterPlus[imageDimIdx];
00285           double lower = threadStorage->m_FMinus[imageDimIdx] / threadStorage->m_CountByParameterMinus[imageDimIdx];
00286           
00287           if ( (ThisConst->m_JacobianConstraintWeight > 0) || (ThisConst->m_BendingEnergyWeight > 0) )
00288             {
00289             const size_t warpParam = cdparam % parametersPerXform;
00290             const size_t imageIdx = cdparam / parametersPerXform;
00291             const SplineWarpXform* xform = ThisConst->GetXformByIndex(imageIdx);
00292             const Types::Coordinate pStep = ThisConst->m_ParamStepArray[cdparam] * threadParameters->m_Step;
00293 
00294             if ( ThisConst->m_JacobianConstraintWeight > 0 )
00295               {
00296               double upperJ, lowerJ;
00297               xform->GetJacobianConstraintDerivative( upperJ, lowerJ, warpParam, *(voi+warpParam), pStep );
00298               
00299               upper -= ThisConst->m_JacobianConstraintWeight * upperJ;
00300               lower -= ThisConst->m_JacobianConstraintWeight * lowerJ;
00301               }
00302             
00303             if ( ThisConst->m_BendingEnergyWeight > 0 )
00304               {
00305               double upperE, lowerE;
00306               xform->GetGridEnergyDerivative( upperE, lowerE, warpParam, pStep );
00307               
00308               upper -= ThisConst->m_BendingEnergyWeight * upperE;
00309               lower -= ThisConst->m_BendingEnergyWeight * lowerE;
00310               }
00311             }
00312           
00313           if ( (upper > 0) || (lower > 0))
00314             {
00315             threadParameters->m_Gradient[cparam+dim] = upper - lower;
00316             }
00317           }
00318         }
00319       }
00320     This->m_ControlPointIndexLock.Lock();
00321     }
00322   This->m_ControlPointIndexLock.Unlock();
00323 
00324   return CMTK_THREAD_RETURN_VALUE;
00325 }
00326 
00327 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines