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/cmtkVoxelMatchingElasticFunctional.h>
00034
00035 #ifdef CMTK_BUILD_SMP
00036 # include <Registration/cmtkParallelElasticFunctional.h>
00037 #endif
00038
00039 #include <Registration/cmtkVoxelMatchingMutInf.h>
00040 #include <Registration/cmtkVoxelMatchingNormMutInf.h>
00041 #include <Registration/cmtkVoxelMatchingCorrRatio.h>
00042 #include <Registration/cmtkVoxelMatchingMeanSquaredDifference.h>
00043 #include <Registration/cmtkVoxelMatchingCrossCorrelation.h>
00044
00045 #include <Base/cmtkInterpolator.h>
00046 #include <Base/cmtkSplineWarpXform.h>
00047
00048 #include <vector>
00049
00050 namespace
00051 cmtk
00052 {
00053
00056
00057 VoxelMatchingElasticFunctional::VoxelMatchingElasticFunctional
00058 ( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating )
00059 : VoxelMatchingFunctional( reference, floating ),
00060 m_ActiveCoordinates( NULL )
00061 {
00062 Dim = 0;
00063
00064 ReferenceFrom = UniformVolume::CoordinateVectorType( UniformVolume::CoordinateVectorType::Init( 0 ) );
00065 ReferenceTo = reference->Size;
00066
00067 this->m_AdaptiveFixParameters = false;
00068 this->m_AdaptiveFixThreshFactor = 0.5;
00069
00070 VectorCache = Memory::AllocateArray<Vector3D>( ReferenceDims[0] );
00071 VolumeOfInfluence = NULL;
00072 }
00073
00074 VoxelMatchingElasticFunctional::~VoxelMatchingElasticFunctional()
00075 {
00076 Memory::DeleteArray( VectorCache );
00077 }
00078
00079 template<class W>
00080 void
00081 VoxelMatchingElasticFunctional_WarpTemplate<W>::WeightedDerivative
00082 ( double& lower, double& upper, W& warp, const int param, const Types::Coordinate step ) const
00083 {
00084 if ( this->m_JacobianConstraintWeight > 0 )
00085 {
00086 double lowerConstraint = 0, upperConstraint = 0;
00087 warp.GetJacobianConstraintDerivative( lowerConstraint, upperConstraint, param, VolumeOfInfluence[param], step );
00088 lower -= this->m_JacobianConstraintWeight * lowerConstraint;
00089 upper -= this->m_JacobianConstraintWeight * upperConstraint;
00090 }
00091
00092 if ( this->m_RigidityConstraintWeight > 0 )
00093 {
00094 double lowerConstraint = 0, upperConstraint = 0;
00095
00096 if ( this->m_RigidityConstraintMap )
00097 {
00098 warp.GetRigidityConstraintDerivative( lowerConstraint, upperConstraint, param, VolumeOfInfluence[param], step, this->m_RigidityConstraintMap );
00099 }
00100 else
00101 {
00102 warp.GetRigidityConstraintDerivative( lowerConstraint, upperConstraint, param, VolumeOfInfluence[param], step );
00103 }
00104 lower -= this->m_RigidityConstraintWeight * lowerConstraint;
00105 upper -= this->m_RigidityConstraintWeight * upperConstraint;
00106 }
00107
00108 if ( this->m_GridEnergyWeight > 0 )
00109 {
00110 double lowerEnergy = 0, upperEnergy = 0;
00111 warp.GetGridEnergyDerivative( lowerEnergy, upperEnergy, param, step );
00112 lower -= this->m_GridEnergyWeight * lowerEnergy;
00113 upper -= this->m_GridEnergyWeight * upperEnergy;
00114 }
00115
00116
00117
00118 if ( !finite(upper) || !finite(lower) )
00119 {
00120 lower = upper = 0;
00121 }
00122 else
00123 {
00124 if ( this->m_MatchedLandmarkList.GetPtr() )
00125 {
00126 double lowerMSD, upperMSD;
00127 warp.GetDerivativeLandmarksMSD( lowerMSD, upperMSD, this->m_MatchedLandmarkList, param, step );
00128 lower -= this->m_LandmarkErrorWeight * lowerMSD;
00129 upper -= this->m_LandmarkErrorWeight * upperMSD;
00130 }
00131 if ( InverseTransformation )
00132 {
00133 double lowerIC, upperIC;
00134 warp.GetDerivativeInverseConsistencyError( lowerIC, upperIC, this->InverseTransformation, this->ReferenceGrid, &(this->VolumeOfInfluence[param]), param, step );
00135 lower -= InverseConsistencyWeight * lowerIC;
00136 upper -= InverseConsistencyWeight * upperIC;
00137 }
00138 }
00139 }
00140
00141 template<class W>
00142 void
00143 VoxelMatchingElasticFunctional_WarpTemplate<W>::SetWarpXform
00144 ( typename W::SmartPtr& warp )
00145 {
00146 Warp = W::SmartPtr::DynamicCastFrom( warp );
00147 if ( Warp )
00148 {
00149 Warp->RegisterVolume( ReferenceGrid );
00150
00151 if ( Dim != Warp->VariableParamVectorDim() )
00152 {
00153 if ( VolumeOfInfluence )
00154 Memory::DeleteArray( VolumeOfInfluence );
00155 Dim = Warp->VariableParamVectorDim();
00156 this->StepScaleVector.resize( Dim );
00157 this->VolumeOfInfluence = Memory::AllocateArray<DataGrid::RegionType>( Dim );
00158 }
00159
00160 DataGrid::RegionType *VOIptr = this->VolumeOfInfluence;
00161 Vector3D fromVOI, toVOI;
00162 for ( size_t dim=0; dim<Dim; ++dim, ++VOIptr )
00163 {
00164 StepScaleVector[dim] = this->GetParamStep( dim );
00165 Warp->GetVolumeOfInfluence( dim, ReferenceFrom, ReferenceTo, fromVOI, toVOI );
00166 *VOIptr = this->GetReferenceGridRange( fromVOI, toVOI );
00167 }
00168
00169 WarpNeedsFixUpdate = true;
00170 }
00171 }
00172
00173 template<class VM>
00174 void
00175 VoxelMatchingElasticFunctional_Template<VM>::UpdateWarpFixedParameters()
00176 {
00177 if ( !this->ConsistencyHistogram )
00178 {
00179 this->ConsistencyHistogram = JointHistogram<unsigned int>::SmartPtr( new JointHistogram<unsigned int>() );
00180 const unsigned int numSamplesX = this->Metric->DataX.NumberOfSamples;
00181 const Types::DataItemRange rangeX = this->Metric->DataX.GetValueRange();
00182 const unsigned int numBinsX = this->ConsistencyHistogram->CalcNumBins( numSamplesX, rangeX );
00183
00184 const unsigned int numSamplesY = this->Metric->DataY.NumberOfSamples;
00185 const Types::DataItemRange rangeY = this->Metric->DataY.GetValueRange();
00186 unsigned int numBinsY = this->ConsistencyHistogram->CalcNumBins( numSamplesY, rangeY );
00187
00188 this->ConsistencyHistogram->Resize( numBinsX, numBinsY );
00189 this->ConsistencyHistogram->SetRangeX( rangeX );
00190 this->ConsistencyHistogram->SetRangeY( rangeY );
00191 }
00192
00193 int numCtrlPoints = this->Dim / 3;
00194
00195 std::vector<double> mapRef( numCtrlPoints );
00196 std::vector<double> mapMod( numCtrlPoints );
00197
00198 Vector3D fromVOI, toVOI;
00199 int pX, pY, pZ;
00200
00201 int inactive = 0;
00202
00203 const typename VM::Exchange unsetY = this->Metric->DataY.padding();
00204
00205 if ( this->ReferenceDataClass == DATACLASS_LABEL )
00206 {
00207 if ( this->m_ActiveCoordinates )
00208 this->Warp->SetParametersActive( this->m_ActiveCoordinates );
00209 else
00210 this->Warp->SetParametersActive();
00211
00212 for ( int ctrl = 0; ctrl < numCtrlPoints; ++ctrl )
00213 {
00216 this->Warp->GetVolumeOfInfluence( 3 * ctrl, this->ReferenceFrom, this->ReferenceTo, fromVOI, toVOI, 0 );
00217 const DataGrid::RegionType voi = this->GetReferenceGridRange( fromVOI, toVOI );
00218
00219 int r = voi.From()[0] + this->DimsX * ( voi.From()[1] + this->DimsY * voi.From()[2] );
00220
00221 bool active = false;
00222 for ( pZ = voi.From()[2]; (pZ < voi.To()[2]) && !active; ++pZ )
00223 {
00224 for ( pY = voi.From()[1]; (pY < voi.To()[1]) && !active; ++pY )
00225 {
00226 for ( pX = voi.From()[0]; (pX < voi.To()[0]); ++pX, ++r )
00227 {
00228 if ( ( this->Metric->GetSampleX( r ) != 0 ) || ( ( this->WarpedVolume[r] != unsetY ) && ( this->WarpedVolume[r] != 0 ) ) )
00229 {
00230 active = true;
00231 break;
00232 }
00233 }
00234 r += ( voi.From()[0] + ( this->DimsX-voi.To()[0] ) );
00235 }
00236 r += this->DimsX * ( voi.From()[1] + ( this->DimsY-voi.To()[1] ) );
00237 }
00238
00239 if ( !active )
00240 {
00241 inactive += 3;
00242
00243 int dim = 3 * ctrl;
00244 for ( int idx=0; idx<3; ++idx, ++dim )
00245 {
00246 this->Warp->SetParameterInactive( dim );
00247 }
00248 }
00249 }
00250 }
00251 else
00252 {
00253 for ( int ctrl = 0; ctrl < numCtrlPoints; ++ctrl )
00254 {
00255 this->ConsistencyHistogram->Reset();
00256
00257
00258
00259 this->Warp->GetVolumeOfInfluence( 3 * ctrl, this->ReferenceFrom, this->ReferenceTo, fromVOI, toVOI, 0 );
00260 const DataGrid::RegionType voi = this->GetReferenceGridRange( fromVOI, toVOI );
00261
00262 int r = voi.From()[0] + this->DimsX * ( voi.From()[1] + this->DimsY * voi.From()[2] );
00263
00264 const int endOfLine = ( voi.From()[0] + ( this->DimsX-voi.To()[0]) );
00265 const int endOfPlane = this->DimsX * ( voi.From()[1] + (this->DimsY-voi.To()[1]) );
00266
00267 for ( pZ = voi.From()[2]; pZ<voi.To()[2]; ++pZ )
00268 {
00269 for ( pY = voi.From()[1]; pY<voi.To()[1]; ++pY )
00270 {
00271 for ( pX = voi.From()[0]; pX<voi.To()[0]; ++pX, ++r )
00272 {
00273
00274 if ( WarpedVolume[r] != unsetY )
00275 {
00276 this->ConsistencyHistogram->Increment
00277 ( this->ConsistencyHistogram->ValueToBinX( this->Metric->GetSampleX( r ) ),
00278 this->ConsistencyHistogram->ValueToBinY( this->WarpedVolume[r] ) );
00279 }
00280 }
00281 r += endOfLine;
00282 }
00283 r += endOfPlane;
00284 }
00285 this->ConsistencyHistogram->GetMarginalEntropies( mapRef[ctrl], mapMod[ctrl] );
00286 }
00287
00288 double refMin = HUGE_VAL, refMax = -HUGE_VAL;
00289 double modMin = HUGE_VAL, modMax = -HUGE_VAL;
00290 for ( int ctrl=0; ctrl<numCtrlPoints; ++ctrl )
00291 {
00292 if ( mapRef[ctrl] < refMin ) refMin = mapRef[ctrl];
00293 if ( mapRef[ctrl] > refMax ) refMax = mapRef[ctrl];
00294 if ( mapMod[ctrl] < modMin ) modMin = mapMod[ctrl];
00295 if ( mapMod[ctrl] > modMax ) modMax = mapMod[ctrl];
00296 }
00297
00298 const double refThresh = refMin + this->m_AdaptiveFixThreshFactor * (refMax - refMin);
00299 const double modThresh = modMin + this->m_AdaptiveFixThreshFactor * (modMax - modMin);
00300
00301 if ( this->m_ActiveCoordinates )
00302 this->Warp->SetParametersActive( this->m_ActiveCoordinates );
00303 else
00304 this->Warp->SetParametersActive();
00305
00306 for ( int ctrl=0; ctrl<numCtrlPoints; ++ctrl )
00307 {
00308 if ( ( mapRef[ctrl] < refThresh ) && ( mapMod[ctrl] < modThresh ) )
00309 {
00310 int dim = 3 * ctrl;
00311 for ( int idx=0; idx<3; ++idx, ++dim )
00312 {
00313 this->Warp->SetParameterInactive( dim );
00314 }
00315 inactive += 3;
00316 }
00317 }
00318 }
00319
00320 for ( size_t idx = 0; idx < this->Dim; ++idx )
00321 {
00322
00323 if ( this->Warp->GetParameterActive( idx ) )
00324 {
00325 this->StepScaleVector[idx] = this->GetParamStep( idx );
00326 }
00327 else
00328 {
00329 this->StepScaleVector[idx] = 0;
00330 }
00331 }
00332
00333 fprintf( stderr, "Deactivated %d out of %d parameters.\n", inactive, (int)this->Dim );
00334
00335 this->WarpNeedsFixUpdate = false;
00336 }
00337
00338 VoxelMatchingElasticFunctional*
00339 CreateElasticFunctional
00340 ( const int metric,
00341 UniformVolume::SmartPtr& refVolume,
00342 UniformVolume::SmartPtr& fltVolume )
00343 {
00344 #ifdef CMTK_BUILD_SMP
00345 switch ( fltVolume->GetData()->GetDataClass() )
00346 {
00347 case DATACLASS_UNKNOWN :
00348 case DATACLASS_GREY :
00349 switch ( metric )
00350 {
00351 case 0:
00352 return new ParallelElasticFunctional< VoxelMatchingNormMutInf_Trilinear>( refVolume, fltVolume );
00353 case 1:
00354 return new ParallelElasticFunctional<VoxelMatchingMutInf_Trilinear>( refVolume, fltVolume );
00355 case 2:
00356 return new ParallelElasticFunctional<VoxelMatchingCorrRatio_Trilinear>( refVolume, fltVolume );
00357 case 3:
00358 return NULL;
00359 case 4:
00360 return new ParallelElasticFunctional<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00361 case 5:
00362 return new ParallelElasticFunctional<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00363 default:
00364 return NULL;
00365 }
00366 case DATACLASS_LABEL:
00367 switch ( metric )
00368 {
00369 case 0:
00370 return new ParallelElasticFunctional< VoxelMatchingNormMutInf_NearestNeighbor >( refVolume, fltVolume );
00371 case 1:
00372 return new ParallelElasticFunctional<VoxelMatchingMutInf_NearestNeighbor>( refVolume, fltVolume );
00373 case 2:
00374 return new ParallelElasticFunctional<VoxelMatchingCorrRatio_NearestNeighbor>( refVolume, fltVolume );
00375 case 3:
00376 return NULL;
00377 case 4:
00378 return new ParallelElasticFunctional<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00379 case 5:
00380 return new ParallelElasticFunctional<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00381 default:
00382 return NULL;
00383 }
00384 }
00385
00386 #else // single processing
00387
00388 switch ( fltVolume->GetData()->GetDataClass() )
00389 {
00390 case DATACLASS_UNKNOWN :
00391 case DATACLASS_GREY :
00392 switch ( metric )
00393 {
00394 case 0:
00395 return new VoxelMatchingElasticFunctional_Template< VoxelMatchingNormMutInf_Trilinear>( refVolume, fltVolume );
00396 case 1:
00397 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_Trilinear>( refVolume, fltVolume );
00398 case 2:
00399 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_Trilinear>( refVolume, fltVolume );
00400 case 3:
00401 return NULL;
00402 case 4:
00403 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00404 case 5:
00405 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00406 default:
00407 return NULL;
00408 }
00409 case DATACLASS_LABEL:
00410 switch ( metric )
00411 {
00412 case 0:
00413 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingNormMutInf_NearestNeighbor>( refVolume, fltVolume );
00414 case 1:
00415 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_NearestNeighbor>( refVolume, fltVolume );
00416 case 2:
00417 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_NearestNeighbor>( refVolume, fltVolume );
00418 case 3:
00419 return NULL;
00420 case 4:
00421 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingMeanSquaredDifference>( refVolume, fltVolume );
00422 case 5:
00423 return new VoxelMatchingElasticFunctional_Template<VoxelMatchingCrossCorrelation>( refVolume, fltVolume );
00424 default:
00425 return NULL;
00426 }
00427 }
00428 #endif
00429
00430 return NULL;
00431 }
00432
00433 template class VoxelMatchingElasticFunctional_WarpTemplate<SplineWarpXform>;
00434
00435 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingNormMutInf_Trilinear>;
00436 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingNormMutInf_NearestNeighbor>;
00437
00438 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_Trilinear>;
00439 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingMutInf_NearestNeighbor>;
00440
00441 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_Trilinear>;
00442 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingCorrRatio_NearestNeighbor>;
00443
00444 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingCrossCorrelation>;
00445
00446 template class VoxelMatchingElasticFunctional_Template<VoxelMatchingMeanSquaredDifference>;
00447
00448 }