Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
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
00070 this->m_StaticThreadStorage.resize(0);
00071 }
00072
00073 void
00074 SplineWarpCongealingFunctional
00075 ::RefineTransformationGrids()
00076 {
00077 this->Superclass::RefineTransformationGrids();
00078
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
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 );
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 }
00297
00298 #ifdef CMTK_BUILD_MPI
00299 # include "cmtkSplineWarpCongealingFunctionalMPI.txx"
00300 #else
00301 # include "cmtkSplineWarpCongealingFunctional.txx"
00302 #endif