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