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 <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 );
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
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
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 }
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>;