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 #ifndef __cmtkVoxelMatchingElasticFunctional_h_included_
00034 #define __cmtkVoxelMatchingElasticFunctional_h_included_
00035
00036 #include <cmtkconfig.h>
00037
00038 #include <Registration/cmtkVoxelMatchingFunctional.h>
00039
00040 #include <Base/cmtkVector.h>
00041 #include <Base/cmtkSplineWarpXform.h>
00042 #include <Base/cmtkJointHistogram.h>
00043 #include <Base/cmtkUniformVolume.h>
00044 #include <Base/cmtkMacros.h>
00045 #include <Base/cmtkMathUtil.h>
00046
00047 #include <System/cmtkException.h>
00048
00049 #include <cassert>
00050 #include <vector>
00051
00052 #ifdef HAVE_IEEEFP_H
00053 # include <ieeefp.h>
00054 #endif
00055
00056 #ifdef HAVE_VALUES_H
00057 # include <values.h>
00058 #endif
00059
00060 namespace
00061 cmtk
00062 {
00063
00066
00071 class VoxelMatchingElasticFunctional :
00073 public VoxelMatchingFunctional
00074 {
00075 public:
00077 typedef VoxelMatchingElasticFunctional Self;
00078
00080 typedef SmartPointer<Self> SmartPtr;
00081
00083 typedef VoxelMatchingFunctional Superclass;
00084
00091 virtual void SetWarpXform( SplineWarpXform::SmartPtr& warp ) = 0;
00092
00094 virtual void SetForceOutside( const bool flag = true, const Types::DataItem value = 0 ) = 0;
00095
00097 virtual ~VoxelMatchingElasticFunctional ();
00098
00099 protected:
00101 VoxelMatchingElasticFunctional( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating );
00102
00108 cmtkGetSetMacroDefault(bool,AdaptiveFixParameters,true);
00109
00117 cmtkGetSetMacro(double,AdaptiveFixThreshFactor);
00118
00121 cmtkGetSetMacroString(ActiveCoordinates);
00122
00126 cmtkGetSetMacroDefault(double,JacobianConstraintWeight,0);
00127
00130 cmtkGetSetMacroDefault(double,RigidityConstraintWeight,0);
00131
00134 cmtkGetSetMacro(DataGrid::SmartPtr,RigidityConstraintMap);
00135
00140 cmtkGetSetMacroDefault(double,GridEnergyWeight,0);
00141
00144 cmtkGetSetMacroDefault(bool,Regularize,false);
00145
00151 bool WarpNeedsFixUpdate;
00152
00154 JointHistogram<unsigned int>::SmartPtr ConsistencyHistogram;
00155
00157 size_t Dim;
00158
00164 std::vector<Types::Coordinate> StepScaleVector;
00165
00172 DataGrid::RegionType *VolumeOfInfluence;
00173
00175 Vector3D ReferenceFrom;
00176
00178 Vector3D ReferenceTo;
00179
00181 Vector3D *VectorCache;
00182 };
00183
00205 template<class W>
00206 class VoxelMatchingElasticFunctional_WarpTemplate :
00208 public VoxelMatchingElasticFunctional
00209 {
00210 public:
00212 typedef VoxelMatchingElasticFunctional_WarpTemplate<W> Self;
00213
00215 typedef SmartPointer<Self> SmartPtr;
00216
00218 typedef VoxelMatchingElasticFunctional Superclass;
00219
00221 typename W::SmartPtr Warp;
00222
00223 protected:
00225 typename W::SmartPtr InverseTransformation;
00226
00228 double InverseConsistencyWeight;
00229
00230 public:
00232 void SetInverseTransformation( typename W::SmartPtr& inverseTransformation )
00233 {
00234 this->InverseTransformation = W::SmartPtr::DynamicCastFrom( inverseTransformation );
00235 }
00236
00238 void SetInverseConsistencyWeight( const double inverseConsistencyWeight )
00239 {
00240 this->InverseConsistencyWeight = inverseConsistencyWeight;
00241 }
00242
00243 protected:
00244
00246 typename Self::ReturnType WeightedTotal( const typename Self::ReturnType metric, const W* warp ) const
00247 {
00248 double result = metric;
00249 if ( this->m_JacobianConstraintWeight > 0 )
00250 {
00251 result -= this->m_JacobianConstraintWeight * warp->GetJacobianConstraint();
00252 }
00253
00254 if ( this->m_RigidityConstraintWeight > 0 )
00255 {
00256 if ( this->m_RigidityConstraintMap )
00257 {
00258 result -= this->m_RigidityConstraintWeight * warp->GetRigidityConstraint( this->m_RigidityConstraintMap );
00259 }
00260 else
00261 {
00262 result -= this->m_RigidityConstraintWeight * warp->GetRigidityConstraint();
00263 }
00264 }
00265
00266 if ( this->m_GridEnergyWeight > 0 )
00267 {
00268 result -= this->m_GridEnergyWeight * warp->GetGridEnergy();
00269 }
00270
00271 if ( !finite( result ) )
00272 return -FLT_MAX;
00273
00274 if ( this->m_MatchedLandmarkList )
00275 {
00276 result -= this->m_LandmarkErrorWeight * warp->GetLandmarksMSD( this->m_MatchedLandmarkList );
00277 }
00278
00279 if ( InverseTransformation )
00280 {
00281 result -= this->InverseConsistencyWeight * warp->GetInverseConsistencyError( this->InverseTransformation, this->ReferenceGrid );
00282 }
00283
00284 return static_cast<typename Self::ReturnType>( result );
00285 }
00286
00288 void WeightedDerivative( double& lower, double& upper, W& warp, const int param, const Types::Coordinate step ) const;
00289
00290 public:
00292 virtual Types::Coordinate GetParamStep( const size_t idx, const Types::Coordinate mmStep = 1 ) const
00293 {
00294 return Warp->GetParamStep( idx, Vector3D( this->FloatingSize ), mmStep );
00295 }
00296
00298 virtual size_t ParamVectorDim() const
00299 {
00300 return Warp->ParamVectorDim();
00301 }
00302
00304 virtual size_t VariableParamVectorDim() const
00305 {
00306 return Warp->VariableParamVectorDim();
00307 }
00308
00314 virtual void SetWarpXform ( typename W::SmartPtr& warp );
00315
00317 virtual void GetParamVector ( CoordinateVector& v )
00318 {
00319 Warp->GetParamVector( v );
00320 }
00321
00322 protected:
00324 VoxelMatchingElasticFunctional_WarpTemplate( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating )
00325 : VoxelMatchingElasticFunctional( reference, floating ),
00326 Warp( NULL ), InverseTransformation( NULL )
00327 {}
00328
00330 virtual ~VoxelMatchingElasticFunctional_WarpTemplate() {}
00331 };
00332
00342 template<class VM>
00343 class VoxelMatchingElasticFunctional_Template
00344 : public VoxelMatchingFunctional_Template<VM>,
00345 public VoxelMatchingElasticFunctional_WarpTemplate<SplineWarpXform>
00346 {
00347 public:
00349 typedef VoxelMatchingElasticFunctional_Template<VM> Self;
00350
00357 VoxelMatchingElasticFunctional_Template( UniformVolume::SmartPtr& reference, UniformVolume::SmartPtr& floating )
00358 : VoxelMatchingFunctional_Template<VM>( reference, floating ),
00359 VoxelMatchingElasticFunctional_WarpTemplate<SplineWarpXform>( reference, floating ),
00360 m_ForceOutsideFlag( false ),
00361 m_ForceOutsideValueRescaled( 0 )
00362 {
00363 IncrementalMetric = typename VM::SmartPtr( new VM( *(this->Metric) ) );
00364
00365 WarpedVolume = NULL;
00366
00367 DimsX = this->ReferenceGrid->GetDims()[0];
00368 DimsY = this->ReferenceGrid->GetDims()[1];
00369 DimsZ = this->ReferenceGrid->GetDims()[2];
00370
00371 FltDimsX = this->FloatingGrid->GetDims()[0];
00372 FltDimsY = this->FloatingGrid->GetDims()[1];
00373 }
00374
00376 virtual ~VoxelMatchingElasticFunctional_Template()
00377 {
00378 if ( WarpedVolume )
00379 Memory::DeleteArray( WarpedVolume );
00380 }
00381
00383 virtual void SetForceOutside
00384 ( const bool flag = true, const Types::DataItem value = 0 )
00385 {
00386 this->m_ForceOutsideFlag = flag;
00387 this->m_ForceOutsideValueRescaled = this->Metric->DataY.ValueToIndex( value );
00388 }
00389
00396 typename Self::ReturnType EvaluateIncremental( const SplineWarpXform* warp, SmartPointer<VM>& localMetric, const DataGrid::RegionType& voi )
00397 {
00398 Vector3D *pVec;
00399 int pX, pY, pZ, offset, r;
00400 int fltIdx[3];
00401 Types::Coordinate fltFrac[3];
00402
00403 int endLineIncrement = ( voi.From()[0] + (DimsX - voi.To()[0]) );
00404 int endPlaneIncrement = DimsX * ( voi.From()[1] + (DimsY - voi.To()[2]) );
00405
00406 const typename VM::Exchange unsetY = this->Metric->DataY.padding();
00407 *localMetric = *this->Metric;
00408 r = voi.From()[0] + DimsX * ( voi.From()[1] + DimsY * voi.From()[2] );
00409 for ( pZ = voi.From()[2]; pZ<voi.To()[2]; ++pZ )
00410 {
00411 for ( pY = voi.From()[1]; pY<voi.To()[1]; ++pY )
00412 {
00413 pVec = this->VectorCache;
00414 warp->GetTransformedGridRow( voi.From()[0]-voi.To()[0], pVec, voi.From()[0], pY, pZ );
00415 for ( pX = voi.From()[0]; pX<voi.To()[0]; ++pX, ++r, ++pVec )
00416 {
00417
00418 const typename VM::Exchange sampleX = this->Metric->GetSampleX( r );
00419 if ( this->WarpedVolume[r] != unsetY )
00420 localMetric->Decrement( sampleX, WarpedVolume[r] );
00421
00422
00423 *pVec *= this->FloatingInverseDelta;
00424 if ( this->FloatingGrid->FindVoxelByIndex( *pVec, fltIdx, fltFrac ) )
00425 {
00426
00427 offset = fltIdx[0] + FltDimsX * ( fltIdx[1] + FltDimsY * fltIdx[2] );
00428
00429
00430 localMetric->Increment( sampleX, this->Metric->GetSampleY( offset, fltFrac ) );
00431 }
00432 else
00433 {
00434 if ( this->m_ForceOutsideFlag )
00435 {
00436 localMetric->Increment( sampleX, this->m_ForceOutsideValueRescaled );
00437 }
00438 }
00439 }
00440 r += endLineIncrement;
00441 }
00442 r += endPlaneIncrement;
00443 }
00444
00445 return localMetric->Get();
00446 }
00447
00456 void UpdateWarpFixedParameters();
00457
00459 virtual typename Self::ReturnType EvaluateWithGradient( CoordinateVector& v, CoordinateVector& g, const Types::Coordinate step = 1 )
00460 {
00461 const typename Self::ReturnType current = this->EvaluateAt( v );
00462
00463 if ( this->m_AdaptiveFixParameters && this->WarpNeedsFixUpdate )
00464 {
00465 this->UpdateWarpFixedParameters();
00466 }
00467
00468 Types::Coordinate *p = this->Warp->m_Parameters;
00469
00470 Types::Coordinate pOld;
00471 double upper, lower;
00472 const DataGrid::RegionType *voi = this->VolumeOfInfluence;
00473 for ( size_t dim = 0; dim < this->Dim; ++dim, ++voi )
00474 {
00475 if ( this->StepScaleVector[dim] <= 0 )
00476 {
00477 g[dim] = 0;
00478 }
00479 else
00480 {
00481 pOld = p[dim];
00482
00483 Types::Coordinate thisStep = step * this->StepScaleVector[dim];
00484
00485 p[dim] += thisStep;
00486 upper = EvaluateIncremental( this->Warp, IncrementalMetric, *voi );
00487
00488 p[dim] = pOld - thisStep;
00489 lower = EvaluateIncremental( this->Warp, IncrementalMetric, *voi );
00490
00491 p[dim] = pOld;
00492 this->WeightedDerivative( lower, upper, *(this->Warp), dim, thisStep );
00493
00494 if ( (upper > current ) || (lower > current) )
00495 {
00496 g[dim] = upper-lower;
00497 }
00498 else
00499 {
00500 g[dim] = 0;
00501 }
00502 }
00503 }
00504
00505 return current;
00506 }
00507
00509 virtual typename Self::ReturnType EvaluateAt( CoordinateVector& v )
00510 {
00511 this->Warp->SetParamVector( v );
00512 return this->Evaluate();
00513 }
00514
00516 virtual typename Self::ReturnType Evaluate()
00517 {
00518 if ( ! WarpedVolume )
00519 WarpedVolume = Memory::AllocateArray<typename VM::Exchange>( DimsX * DimsY * DimsZ );
00520
00521 this->Metric->Reset();
00522 const typename VM::Exchange unsetY = this->Metric->DataY.padding();
00523
00524 Vector3D *pVec;
00525 int pX, pY, pZ;
00526 int fltIdx[3];
00527 Types::Coordinate fltFrac[3];
00528
00529 int r = 0;
00530 for ( pZ = 0; pZ<DimsZ; ++pZ )
00531 {
00532 for ( pY = 0; pY<DimsY; ++pY )
00533 {
00534 this->Warp->GetTransformedGridRow( DimsX, this->VectorCache, 0, pY, pZ );
00535 pVec = this->VectorCache;
00536 for ( pX = 0; pX<DimsX; ++pX, ++r, ++pVec )
00537 {
00538
00539 *pVec *= this->FloatingInverseDelta;
00540 if ( this->FloatingGrid->FindVoxelByIndex( *pVec, fltIdx, fltFrac ) )
00541 {
00542
00543
00544 const size_t offset = fltIdx[0] + FltDimsX * ( fltIdx[1] + FltDimsY * fltIdx[2] );
00545
00546
00547 this->WarpedVolume[r] = this->Metric->GetSampleY( offset, fltFrac );
00548 this->Metric->Increment( this->Metric->GetSampleX( r ), this->WarpedVolume[r] );
00549 }
00550 else
00551 {
00552 if ( this->m_ForceOutsideFlag )
00553 {
00554 this->WarpedVolume[r] = this->m_ForceOutsideValueRescaled;
00555 this->Metric->Increment( this->Metric->GetSampleX( r ), this->WarpedVolume[r] );
00556 }
00557 else
00558 {
00559 this->WarpedVolume[r] = unsetY;
00560 }
00561 }
00562 }
00563 }
00564 }
00565
00566 return this->WeightedTotal( this->Metric->Get(), this->Warp );
00567 }
00568
00569 protected:
00572 typename VM::Exchange *WarpedVolume;
00573
00575 bool m_ForceOutsideFlag;
00576
00578 typename VM::Exchange m_ForceOutsideValueRescaled;
00579
00586 SmartPointer<VM> IncrementalMetric;
00587
00589 DataGrid::IndexType::ValueType DimsX, DimsY, DimsZ;
00590
00592 DataGrid::IndexType::ValueType FltDimsX, FltDimsY;
00593 };
00594
00605 VoxelMatchingElasticFunctional* CreateElasticFunctional( const int metric, UniformVolume::SmartPtr& refVolume, UniformVolume::SmartPtr& fltVolume );
00606
00607 }
00608
00609 #endif // __cmtkVoxelMatchingElasticFunctional_h_included_