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 "cmtkSplineWarpXform.h"
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Base/cmtkBitVector.h>
00037 
00038 #include <vector>
00039 #include <cassert>
00040 
00041 namespace
00042 cmtk
00043 {
00044 
00047 
00048 SplineWarpXform::SplineWarpXform()
00049 {
00050   this->Init();
00051 }
00052 
00053 void SplineWarpXform::Init () 
00054 {
00055   this->GlobalScaling = 1.0;
00056 }
00057 
00058 SplineWarpXform::SplineWarpXform 
00059 ( const FixedVector<3,Types::Coordinate>& domain, const Types::Coordinate delta, const AffineXform* initialXform, const bool exactDelta  )
00060 {
00061   this->Init( domain, delta, initialXform, exactDelta );
00062 }
00063 
00064 void
00065 SplineWarpXform
00066 ::Init
00067 ( const Self::SpaceVectorType& domain, const Types::Coordinate delta, const AffineXform* initialXform, const bool exactDelta  )
00068 {
00069   this->Init();
00070   this->Domain = domain;
00071   this->m_InitialAffineXform = initialXform->Clone();
00072 
00073   if ( exactDelta ) 
00074     {
00075     for ( int dim=0; dim<3; ++dim ) 
00076       {
00077       Spacing[dim] = delta;
00078       this->m_Dims[dim] = static_cast<int>( 4 + (Domain[dim] / Spacing[dim]) );
00079       Domain[dim] = (this->m_Dims[dim] - 3) * Spacing[dim];
00080       }
00081     } 
00082   else
00083     {
00084     for ( int dim=0; dim<3; ++dim )
00085       this->m_Dims[dim] = 2 + std::max( 2, 1+static_cast<int>( domain[dim]/delta ) );
00086     }
00087   
00088   NumberOfControlPoints = this->m_Dims[0] * this->m_Dims[1] * this->m_Dims[2];
00089   this->AllocateParameterVector( 3 * NumberOfControlPoints );
00090   
00091   this->Update( exactDelta );
00092   this->InitControlPoints( this->m_InitialAffineXform );
00093 }
00094 
00095 SplineWarpXform::SplineWarpXform
00096 ( const FixedVector<3,Types::Coordinate>& domain, const Self::IndexType& dims, CoordinateVector::SmartPtr& parameters, const AffineXform* initialXform )
00097 {
00098   this->Init();
00099   this->Domain = domain;
00100   this->m_Dims = dims;
00101 
00102   if ( initialXform )
00103     {
00104     this->m_InitialAffineXform = initialXform->Clone();
00105     GlobalScaling = this->m_InitialAffineXform->GetGlobalScaling();
00106     } 
00107   else
00108     {
00109     this->m_InitialAffineXform = AffineXform::SmartPtr( NULL );
00110     }
00111 
00112   NumberOfControlPoints = this->m_Dims[0] * this->m_Dims[1] * this->m_Dims[2];
00113   this->m_NumberOfParameters = 3 * NumberOfControlPoints;
00114 
00115   if ( !parameters )
00116     this->m_ParameterVector = CoordinateVector::SmartPtr( new CoordinateVector( this->m_NumberOfParameters ) );
00117   else
00118     this->m_ParameterVector = parameters;
00119   this->m_Parameters = this->m_ParameterVector->Elements;
00120 
00121   this->Update( false  );
00122 
00123   if ( !parameters )
00124     this->InitControlPoints( this->m_InitialAffineXform );
00125 }
00126 
00127 void
00128 SplineWarpXform::InitControlPoints( const AffineXform* affineXform )
00129 {
00130   Types::Coordinate *ofs = this->m_Parameters;
00131   Types::Coordinate pZ = -Spacing[2];
00132   for ( int z=0; z<this->m_Dims[2]; ++z, pZ+=Spacing[2] ) 
00133     {
00134     Types::Coordinate pY = -Spacing[1];
00135     for ( int y=0; y<this->m_Dims[1]; ++y, pY+=Spacing[1] ) 
00136       {
00137       Types::Coordinate pX = -Spacing[0];
00138       for ( int x=0; x<this->m_Dims[0]; ++x, pX+=Spacing[0], ofs+=3 ) 
00139         {
00140         ofs[0] = pX;
00141         ofs[1] = pY;
00142         ofs[2] = pZ;
00143         }
00144       }
00145     }
00146   
00147   if ( affineXform ) 
00148     {
00149     ofs = this->m_Parameters;
00150     for ( unsigned int idx = 0; idx < NumberOfControlPoints; ++idx, ofs+=3 ) 
00151       {
00152       Self::SpaceVectorType p( ofs );
00153       affineXform->ApplyInPlace( p );
00154       ofs[0] = p[0];
00155       ofs[1] = p[1];
00156       ofs[2] = p[2];
00157       }
00158     
00159     affineXform->GetScales( this->InverseAffineScaling );
00160     GlobalScaling = affineXform->GetGlobalScaling();
00161     } 
00162   else
00163     {
00164     InverseAffineScaling[0] = InverseAffineScaling[1] = InverseAffineScaling[2] = GlobalScaling = 1.0;
00165     }
00166 }
00167 
00168 void
00169 SplineWarpXform::Update 
00170 ( const bool exactDelta ) 
00171 {
00172   this->WarpXform::Update();
00173 
00174   for ( int dim=0; dim<3; ++dim ) 
00175     {
00176     assert( this->m_Dims[dim] > 3 );
00177     if ( exactDelta ) 
00178       {
00179       InverseSpacing[dim] = 1.0 / Spacing[dim];
00180       } 
00181     else
00182       {
00183       Spacing[dim] = Domain[dim] / (this->m_Dims[dim]-3);
00184       InverseSpacing[dim] = 1.0*(this->m_Dims[dim]-3) / Domain[dim];
00185       }
00186     m_Offset[dim] = -Spacing[dim];
00187     }
00188   
00189   int dml = 0;
00190   for ( int dim = 0; dim<3; ++dim )
00191     for ( int m = 0; m < 4; ++m )
00192       for ( int l = 0; l < 4; ++l, ++dml )
00193         GridPointOffset[dml] = dim + l * nextJ + m * nextK;
00194 }
00195 
00196 SplineWarpXform* 
00197 SplineWarpXform::CloneVirtual() const
00198 {
00199   SplineWarpXform *newXform = new SplineWarpXform();
00200 
00201   newXform->m_ParameterVector = CoordinateVector::SmartPtr( this->m_ParameterVector->Clone() );
00202   newXform->m_Parameters = newXform->m_ParameterVector->Elements;
00203   newXform->m_NumberOfParameters = this->m_NumberOfParameters;
00204   newXform->NumberOfControlPoints = this->NumberOfControlPoints;
00205   
00206   newXform->m_Dims = this->m_Dims;
00207   newXform->Domain = this->Domain;
00208   memcpy( newXform->Spacing, Spacing, sizeof( newXform->Spacing ) );
00209   memcpy( newXform->InverseSpacing, InverseSpacing, sizeof( newXform->InverseSpacing ) );
00210   newXform->m_Offset = this->m_Offset;
00211 
00212   if ( this->m_ActiveFlags ) 
00213     {
00214     BitVector::SmartPtr activeFlags( this->m_ActiveFlags->Clone() );
00215     newXform->SetActiveFlags( activeFlags );
00216     }
00217   newXform->m_IgnoreEdge = this->m_IgnoreEdge;
00218   newXform->m_FastMode = this->m_FastMode;
00219 
00220   if ( this->m_InitialAffineXform ) 
00221     {
00222     newXform->m_InitialAffineXform = AffineXform::SmartPtr( this->m_InitialAffineXform->Clone() );
00223     }
00224   
00225   newXform->GlobalScaling = this->GlobalScaling;
00226 
00227   newXform->nextI = this->nextI;
00228   newXform->nextJ = this->nextJ;
00229   newXform->nextK = this->nextK;
00230   newXform->nextIJ = this->nextIJ;
00231   newXform->nextIK = this->nextIK;
00232   newXform->nextJK = this->nextJK;
00233   newXform->nextIJK = this->nextIJK;
00234   memcpy( newXform->GridPointOffset, this->GridPointOffset, sizeof( this->GridPointOffset ) );
00235 
00236   newXform->VolumeDims = this->VolumeDims;
00237 
00238   newXform->gX = this->gX;
00239   newXform->gY = this->gY;
00240   newXform->gZ = this->gZ;
00241 
00242   newXform->splineX = this->splineX;
00243   newXform->splineY = this->splineY;
00244   newXform->splineZ = this->splineZ;
00245 
00246   newXform->dsplineX = this->dsplineX;
00247   newXform->dsplineY = this->dsplineY;
00248   newXform->dsplineZ = this->dsplineZ;
00249 
00250   return newXform;
00251 }
00252 
00253 void
00254 SplineWarpXform::Refine()
00255 {
00256   if ( !this->m_ParameterVector ) return;
00257 
00258   Self::IndexType newDims;
00259   for ( int dim=0; dim<3; ++dim ) 
00260     newDims[dim] = 2 * this->m_Dims[dim] - 3;
00261 
00262   const int newNumSamples = newDims[0] * newDims[1] * newDims[2];
00263   const int newNumCoefficients = 3 * newNumSamples;
00264 
00265   CoordinateVector::SmartPtr newParameters( new CoordinateVector( newNumCoefficients ) );
00266   Types::Coordinate* newCoefficients = newParameters->Elements;
00267 
00268   Types::Coordinate newSpacing[3];
00269   for ( int dim=0; dim<3; ++dim ) 
00270     {
00271     newSpacing[dim] = Domain[dim] / (newDims[dim]-3);
00272     }
00273 
00274   
00275   const int newNextI = 3;
00276   const int newNextJ = newNextI * newDims[0];
00277   const int newNextK = newNextJ * newDims[1];
00278   const int newNextIJ = newNextJ + newNextI;
00279   const int newNextIK = newNextK + newNextI;
00280   const int newNextJK = newNextK + newNextJ;
00281   const int newNextIJK = newNextJK + newNextI;
00282 
00283   Types::Coordinate level0[3][3];
00284   memset( level0, 0, sizeof( level0 ) );
00285   Types::Coordinate level1[3];
00286   memset( level1, 0, sizeof( level1 ) );
00287 
00288   Types::Coordinate *ncoeff = newCoefficients;
00289   for ( int z = 0; z<newDims[2]; ++z ) 
00290     {
00291     for ( int y = 0; y<newDims[1]; ++y ) 
00292       {
00293       for ( int x = 0; x<newDims[0]; ++x ) 
00294         {
00295         const int oldX = ((x+1)/2), oldY = ((y+1)/2), oldZ = ((z+1)/2);
00296         const int oddX = x%2, oddY = y%2, oddZ = z%2;
00297         
00298         const Types::Coordinate *coeff = m_Parameters + oldX*nextI + oldY*nextJ + oldZ*nextK;
00299         
00300         for ( int dim=0; dim<3; ++dim, ++coeff, ++ncoeff ) 
00301           {       
00302           for ( int k=0; k<3; ++k ) 
00303             {
00304             int ofsJK = (k-1) * nextK - nextJ;
00305             for ( int j=0; j<3; ++j, ofsJK += nextJ ) 
00306               {
00307               if ( (oddY || j) && (oddZ || k) ) 
00308                 {
00309                 if ( oddX ) 
00310                   {
00311                   level0[k][j] = (coeff[ofsJK-nextI] + 6 * coeff[ofsJK] + coeff[ofsJK+nextI]) / 8;
00312                   } 
00313                 else
00314                   {
00315                   level0[k][j] = (coeff[ofsJK] + coeff[ofsJK+nextI]) / 2;
00316                   }
00317                 }
00318               }
00319             }
00320           
00321           for ( int k=0; k<3; ++k )
00322             {
00323             if ( oddZ || k )
00324               {
00325               if ( oddY ) 
00326                 {
00327                 level1[k] = (level0[k][0] + 6 * level0[k][1] + level0[k][2]) / 8;
00328                 } 
00329               else
00330                 {
00331                 level1[k] = (level0[k][1] + level0[k][2]) / 2;
00332                 }
00333               }
00334             }
00335           
00336           if ( oddZ ) 
00337             {
00338             *ncoeff = (level1[0] + 6 * level1[1] + level1[2]) / 8;
00339             } 
00340           else
00341             {
00342             *ncoeff = (level1[1] + level1[2]) / 2;
00343             } 
00344           }
00345         }
00346       }
00347     }
00348 
00349   NumberOfControlPoints = newNumSamples;
00350   this->m_NumberOfParameters = newNumCoefficients;
00351 
00352   this->m_ParameterVector = newParameters;
00353   this->m_Parameters = newCoefficients;
00354 
00355   this->DeleteParameterActiveFlags();
00356   this->m_Dims = newDims;
00357 
00358   for ( int dim=0; dim<3; ++dim ) 
00359     {
00360     assert( this->m_Dims[dim] > 1 );
00361     Spacing[dim] = newSpacing[dim];
00362     InverseSpacing[dim] = 1.0 / Spacing[dim];
00363     m_Offset[dim] = -Spacing[dim];
00364     }
00365   
00366   
00367   
00368   nextI = newNextI;
00369   nextJ = newNextJ;
00370   nextK = newNextK;
00371   nextIJ = newNextIJ;
00372   nextIK = newNextIK;
00373   nextJK = newNextJK;
00374   nextIJK = newNextIJK;
00375 
00376   int dml = 0;
00377   for ( int dim = 0; dim<3; ++dim )
00378     for ( int m = 0; m < 4; ++m )
00379       for ( int l = 0; l < 4; ++l, ++dml )
00380         GridPointOffset[dml] = dim + l * nextJ + m * nextK;
00381 
00382   if ( this->m_IgnoreEdge )
00383     this->m_IgnoreEdge = 2 * this->m_IgnoreEdge - 1;
00384 
00385   this->UnRegisterVolume();
00386 }
00387 
00388 void 
00389 SplineWarpXform::GetVolumeOfInfluence 
00390 ( const size_t idx, const Self::SpaceVectorType& fromVol, const Self::SpaceVectorType& toVol,
00391   Self::SpaceVectorType& fromVOI, Self::SpaceVectorType& toVOI, const int fastMode ) const
00392 {
00393   int relIdx = idx / 3;
00394 
00395   const int xyz[3] = { ( relIdx %  this->m_Dims[0] ), 
00396                        ( (relIdx /  this->m_Dims[0]) % this->m_Dims[1] ), 
00397                        ( (relIdx /  this->m_Dims[0]) / this->m_Dims[1] ) };
00398   
00399   Types::Coordinate xyzLow[3], xyzUp[3];
00400 
00401   if ( (fastMode==1) || (this->m_FastMode && (fastMode<0)) ) 
00402     {
00403     for ( int dim = 0; dim < 3; ++dim )
00404       {
00405       xyzLow[dim] = Spacing[dim] * std::max( 0, xyz[dim]-2 );
00406       xyzUp[dim] = Spacing[dim] * std::min( this->m_Dims[dim]-3, xyz[dim] );
00407       }
00408     } 
00409   else
00410     {
00411     for ( int dim = 0; dim < 3; ++dim )
00412       {
00413       xyzLow[dim] = Spacing[dim] * std::max( 0, xyz[dim]-3 );
00414       xyzUp[dim] = Spacing[dim] * std::min( this->m_Dims[dim]-2, xyz[dim]+1 );
00415       }
00416     }
00417   
00418   for ( int dim = 0; dim < 3; ++dim )
00419     {
00420     fromVOI[dim] = std::min( toVol[dim], std::max( xyzLow[dim], fromVol[dim]) );
00421     toVOI[dim] = std::max( fromVol[dim], std::min( xyzUp[dim], toVol[dim]) ); 
00422     }
00423 }
00424 
00425 void
00426 SplineWarpXform::RegisterVolumeAxis 
00427 ( const DataGrid::IndexType::ValueType dim, const Types::Coordinate delta, const Types::Coordinate origin, const int cpgDim, const Types::Coordinate invCpgSpacing,
00428   std::vector<int>& g, std::vector<Types::Coordinate>& spline, std::vector<Types::Coordinate>& dspline )
00429 {
00430   g.resize( dim+1 );
00431   spline.resize( 4*dim );
00432   dspline.resize( 4*dim );
00433 
00434   for ( int idx=0; idx<dim; ++idx ) 
00435     {
00436     const Types::Coordinate r = invCpgSpacing * (origin + delta * idx);
00437     g[idx] = std::min( static_cast<int>( r ), cpgDim-4 );
00438     const Types::Coordinate f = r - g[idx];
00439     for ( int k = 0; k < 4; ++k ) 
00440       {
00441       spline[4*idx+k] = CubicSpline::ApproxSpline( k, f );
00442       dspline[4*idx+k] = CubicSpline::DerivApproxSpline( k, f );
00443       }
00444     }
00445   
00446   g[dim] = -1;
00447 }
00448 
00449 void
00450 SplineWarpXform::RegisterVolumePoints
00451 ( const DataGrid::IndexType& volDims, const Self::SpaceVectorType& delta, const Self::SpaceVectorType& origin )
00452 {
00453   this->RegisterVolumeAxis( volDims[0], delta[0], origin[0], this->m_Dims[0], this->InverseSpacing[0], gX, splineX, dsplineX );
00454   this->RegisterVolumeAxis( volDims[1], delta[1], origin[1], this->m_Dims[1], this->InverseSpacing[1], gY, splineY, dsplineY );
00455   this->RegisterVolumeAxis( volDims[2], delta[2], origin[2], this->m_Dims[2], this->InverseSpacing[2], gZ, splineZ, dsplineZ );
00456 
00457   for ( int idx = 0; idx<volDims[0]; ++idx ) gX[idx] *= nextI;
00458   for ( int idx = 0; idx<volDims[1]; ++idx ) gY[idx] *= nextJ;
00459   for ( int idx = 0; idx<volDims[2]; ++idx ) gZ[idx] *= nextK;
00460 
00461   this->VolumeDims = volDims;
00462 }
00463 
00464 void SplineWarpXform::UnRegisterVolume()
00465 {
00466   gX.resize( 0 );
00467   gY.resize( 0 );
00468   gZ.resize( 0 );
00469 
00470   splineX.resize( 0 );
00471   splineY.resize( 0 );
00472   splineZ.resize( 0 );
00473 
00474   dsplineX.resize( 0 );
00475   dsplineY.resize( 0 );
00476   dsplineZ.resize( 0 );
00477 }
00478 
00479 SplineWarpXform::SpaceVectorType& 
00480 SplineWarpXform::GetDeformedControlPointPosition
00481 ( Self::SpaceVectorType& v, const int x, const int y, const int z) 
00482   const 
00483 {
00484   
00485   const Types::Coordinate* coeff = m_Parameters + 3 * ( (x-1) + this->m_Dims[0] * ((y-1) + this->m_Dims[1] * (z-1)) );  
00486   static const Types::Coordinate spline[3] = { 1.0/6, 4.0/6, 1.0/6 };
00487 
00488   for ( int dim = 0; dim<3; ++dim ) 
00489     {
00490     Types::Coordinate mm = 0;
00491     const Types::Coordinate *coeff_mm = coeff;
00492     
00493     for ( int m = 0; m < 3; ++m ) 
00494       {
00495       Types::Coordinate ll = 0;
00496       const Types::Coordinate *coeff_ll = coeff_mm;
00497       
00498       
00499       for ( int l = 0; l < 3; ++l ) 
00500         {
00501         Types::Coordinate kk = 0;
00502         const Types::Coordinate *coeff_kk = coeff_ll;
00503         
00504         
00505         for ( int k = 0; k < 3; ++k, coeff_kk+=3 ) 
00506           {
00507           kk += spline[k] * (*coeff_kk);
00508           }
00509         ll += spline[l] * kk;
00510         coeff_ll += nextJ;
00511         }       
00512       mm += spline[m] * ll;
00513       coeff_mm += nextK;
00514       }
00515     v[dim] = mm;
00516     ++coeff;
00517     }
00518   
00519   return v;
00520 }
00521 
00522 void
00523 SplineWarpXform
00524 ::GetTransformedGrid 
00525 ( Self::SpaceVectorType& v, const int idxX, const int idxY, const int idxZ ) const
00526 {
00527   const Types::Coordinate* coeff = this->m_Parameters + gX[idxX] + gY[idxY] + gZ[idxZ];
00528   const Types::Coordinate *spX = &splineX[idxX<<2], *spY = &splineY[idxY<<2], *spZ = &splineZ[idxZ<<2];
00529   
00530   for ( int dim = 0; dim<3; ++dim ) 
00531     {
00532     Types::Coordinate mm = 0;
00533     const Types::Coordinate *coeff_mm = coeff;
00534       for ( int m = 0; m < 4; ++m )
00535         {
00536         Types::Coordinate ll = 0;
00537         const Types::Coordinate *coeff_ll = coeff_mm;
00538         for ( int l = 0; l < 4; ++l ) 
00539           {
00540           Types::Coordinate kk = 0;
00541           const Types::Coordinate *coeff_kk = coeff_ll;
00542           for ( int k = 0; k < 4; ++k, coeff_kk+=3 ) 
00543             {
00544             kk += spX[k] * (*coeff_kk);
00545             }
00546           ll += spY[l] * kk;
00547           coeff_ll += nextJ;
00548           }     
00549         mm += spZ[m] * ll;
00550         coeff_mm += nextK;
00551         }
00552       v[ dim ] = mm;
00553       ++coeff;
00554     }
00555 }
00556 
00557 void 
00558 SplineWarpXform::GetTransformedGridRow
00559 ( const int numPoints, Self::SpaceVectorType *const vIn, const int idxX, const int idxY, const int idxZ ) 
00560   const
00561 {
00562   Self::SpaceVectorType *v = vIn;
00563   const Types::Coordinate* coeff = m_Parameters + gX[idxX] + gY[idxY] + gZ[idxZ];
00564   const Types::Coordinate *spX = &splineX[idxX<<2], *spY = &splineY[idxY<<2], *spZ = &splineZ[idxZ<<2];
00565   
00566   
00567   
00568   Types::Coordinate sml[16], *psml = sml;
00569   for ( int m = 0; m < 4; ++m )
00570     {
00571     for ( int l = 0; l < 4; ++l, ++psml )
00572       {
00573       *psml = spZ[m] * spY[l];
00574       }
00575     }
00576   
00577   
00578   const int numberOfCells = (gX[idxX + numPoints - 1] - gX[idxX]) / nextI + 4;
00579   
00580   
00581   
00582   Types::Coordinate phiComp;
00583 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00584   Types::Coordinate phiHat[3*numberOfCells]; 
00585 #else
00586   std::vector<Types::Coordinate> phiHat( 3*numberOfCells );
00587 #endif
00588 
00589   const int *gpo;
00590   int phiIdx = 0;
00591   for ( int cell = 0; cell < numberOfCells; ++cell, coeff += nextI ) 
00592     {
00593     gpo = &this->GridPointOffset[0];
00594     for ( int dim = 0; dim < 3; ++dim, ++phiIdx ) 
00595       {
00596       phiComp = coeff[ *gpo ] * sml[0];
00597       ++gpo;
00598       for ( int ml = 1; ml < 16; ++ml, ++gpo ) 
00599         {
00600         phiComp += coeff[ *gpo ] * sml[ml];
00601         }
00602       phiHat[phiIdx] = phiComp;
00603       }
00604     }
00605   
00606   
00607   int cellIdx = 0;
00608 
00609   
00610   int i = idxX;
00611   for ( const int lastPoint = idxX + numPoints; i < lastPoint; ) 
00612     {
00613     
00614     const Types::Coordinate* phiPtr = &phiHat[3*cellIdx];
00615     
00616     
00617     do 
00618       {
00619       Self::SpaceVectorType& vRef = *v;
00620       
00621       
00622       
00623       vRef[0] = spX[0] * phiPtr[0] + spX[1] * phiPtr[3] + spX[2] * phiPtr[6] + spX[3] * phiPtr[9];
00624       vRef[1] = spX[0] * phiPtr[1] + spX[1] * phiPtr[4] + spX[2] * phiPtr[7] + spX[3] * phiPtr[10];
00625       vRef[2] = spX[0] * phiPtr[2] + spX[1] * phiPtr[5] + spX[2] * phiPtr[8] + spX[3] * phiPtr[11];
00626       
00627       
00628       ++i;
00629       spX += 4;
00630       ++v;
00631       
00632       } 
00633     while ( ( gX[i-1] == gX[i] ) && ( i < lastPoint ) );
00634     
00635     
00636     
00637     ++cellIdx;
00638     }
00639 }
00640 
00641 Types::Coordinate
00642 SplineWarpXform
00643 ::GetGridEnergy() const
00644 {
00645   double energy = 0;
00646 
00647 #pragma omp parallel for reduction(+:energy)
00648   for ( int z = 1; z<this->m_Dims[2]-1; ++z )
00649     {
00650     for ( int y = 1; y<this->m_Dims[1]-1; ++y )
00651       {
00652       for ( int x = 1; x<this->m_Dims[0]-1; ++x ) 
00653         {
00654         const Types::Coordinate* coeff = this->m_Parameters + x * nextI + y * nextJ + z * nextK;
00655         energy += this->GetGridEnergy( coeff );
00656         }
00657       }
00658     }
00659   
00660   return energy / (( this->m_Dims[0] - 2 ) * ( this->m_Dims[1] - 2 ) * ( this->m_Dims[2] - 2 ));
00661 }
00662 
00663 Types::Coordinate
00664 SplineWarpXform
00665 ::GetGridEnergy( const Self::SpaceVectorType& v ) const
00666 {
00667   Types::Coordinate r[3], f[3];
00668   int grid[3];
00669   
00670   for ( int dim = 0; dim<3; ++dim ) 
00671     {
00672     r[dim] = InverseSpacing[dim] * v[dim];
00673     grid[dim] = std::min( static_cast<int>( r[dim] ), this->m_Dims[dim]-4 );
00674     f[dim] = std::max<Types::Coordinate>( 0, std::min<Types::Coordinate>( 1.0, r[dim] - grid[dim] ) );
00675     }
00676   
00677   const Types::Coordinate* coeff = this->m_Parameters + 3 * ( grid[0] + this->m_Dims[0] * (grid[1] + this->m_Dims[1] * grid[2]) );
00678 
00679   
00680   double J[3][3];
00681   memset( J, 0, sizeof( J ) );
00682 
00683   
00684   double K[3][3];
00685   memset( K, 0, sizeof( K ) );
00686 
00687   for ( int dim = 0; dim<3; ++dim ) 
00688     {
00689     const Types::Coordinate *coeff_mm = coeff;
00690     for ( int m = 0; m < 3; ++m ) 
00691       {
00692       Types::Coordinate llJ[3] = { 0, 0, 0 };
00693       Types::Coordinate llK[3] = { 0, 0, 0 };
00694       const Types::Coordinate *coeff_ll = coeff_mm;
00695       for ( int l = 0; l < 3; ++l ) 
00696         {
00697         Types::Coordinate kkJ[3] = { 0, 0, 0 };
00698         Types::Coordinate kkK[3] = { 0, 0, 0 };
00699         const Types::Coordinate *coeff_kk = coeff_ll;
00700         for ( int k = 0; k < 3; ++k, coeff_kk += nextI ) 
00701           {
00702           const Types::Coordinate tmp = CubicSpline::ApproxSpline( k, f[0] ) * (*coeff_kk);
00703           kkJ[0] += CubicSpline::SecondDerivApproxSpline( k, f[0] ) * (*coeff_kk);
00704           kkJ[1] += tmp;
00705           kkJ[2] += tmp;
00706           
00707           const Types::Coordinate tmp2 = CubicSpline::DerivApproxSpline( k, f[0] ) * (*coeff_kk);
00708           kkK[0] += tmp2;
00709           kkK[1] += CubicSpline::ApproxSpline( k, f[0] ) * (*coeff_kk);
00710           kkK[2] += tmp2;
00711           }
00712 
00713         const Types::Coordinate tmp = CubicSpline::ApproxSpline( l, f[1] );
00714         llJ[0] += tmp * kkJ[0];
00715         llJ[1] += CubicSpline::SecondDerivApproxSpline( l, f[1] ) * kkJ[1];
00716         llJ[2] += tmp * kkJ[2];
00717         
00718         const Types::Coordinate tmp2 = CubicSpline::DerivApproxSpline( l, f[1] );
00719         llK[0] += tmp2 * kkK[0];
00720         llK[1] += CubicSpline::DerivApproxSpline( l, f[1] ) * kkK[1];
00721         llK[2] += tmp2 * kkK[2];
00722         coeff_ll += nextJ;
00723         }
00724 
00725       const Types::Coordinate tmp = CubicSpline::ApproxSpline( m, f[2] );
00726       J[0][dim] += tmp * llJ[0];
00727       J[1][dim] += CubicSpline::ApproxSpline( m, f[2] ) * llJ[1];
00728       J[2][dim] += tmp * llJ[2];
00729       
00730       const Types::Coordinate tmp2 = CubicSpline::DerivApproxSpline( m, f[2] );
00731       K[0][dim] += CubicSpline::ApproxSpline( m, f[2] ) * llK[0];
00732       K[1][dim] += tmp2 * llK[1];
00733       K[2][dim] += tmp2 * llK[2];
00734       coeff_mm += nextK;
00735       }
00736     ++coeff;
00737     }
00738   
00739   const double energy = 
00740     
00741     MathUtil::Square( InverseSpacing[0] ) *
00742     ( J[0][0] * J[0][0] + J[0][1] * J[0][1] + J[0][2] * J[0][2] ) +
00743     MathUtil::Square( InverseSpacing[1] ) *
00744     ( J[1][0] * J[1][0] + J[1][1] * J[1][1] + J[1][2] * J[1][2] ) +
00745     MathUtil::Square( InverseSpacing[2] ) *
00746     ( J[2][0] * J[2][0] + J[2][1] * J[2][1] + J[2][2] * J[2][2] ) +
00747     
00748     2 * ( InverseSpacing[0] * InverseSpacing[1] *
00749           ( K[0][0] * K[0][0] + K[0][1] * K[0][1] + K[0][2] * K[0][2] ) +
00750           InverseSpacing[1] * InverseSpacing[2] *
00751           ( K[1][0] * K[1][0] + K[1][1] * K[1][1] + K[1][2] * K[1][2] ) +
00752           InverseSpacing[2] * InverseSpacing[0] *
00753           ( K[2][0] * K[2][0] + K[2][1] * K[2][1] + K[2][2] * K[2][2] )
00754           );
00755   
00756   return energy;
00757 }
00758 
00759 Types::Coordinate
00760 SplineWarpXform
00761 ::GetGridEnergy( const Types::Coordinate *cp ) const
00762 {
00763   const double   sp[3] = {  1.0/6, 2.0/3, 1.0/6 };
00764   const double  dsp[3] = { -1.0/2,     0, 1.0/2 };
00765   const double ddsp[3] = {      1,    -2,     1 };
00766 
00767   
00768   double J[3][3];
00769   memset( J, 0, sizeof( J ) );
00770 
00771   
00772   double K[3][3];
00773   memset( K, 0, sizeof( K ) );
00774 
00775   const Types::Coordinate* coeff = cp - nextI - nextJ - nextK;
00776   for ( int dim = 0; dim<3; ++dim ) 
00777     {
00778     const Types::Coordinate *coeff_mm = coeff;
00779     for ( int m = 0; m < 3; ++m ) 
00780       {
00781       Types::Coordinate llJ[3] = { 0, 0, 0 };
00782       Types::Coordinate llK[3] = { 0, 0, 0 };
00783       const Types::Coordinate *coeff_ll = coeff_mm;
00784       for ( int l = 0; l < 3; ++l ) 
00785         {
00786         Types::Coordinate kkJ[3] = { 0, 0, 0 };
00787         Types::Coordinate kkK[3] = { 0, 0, 0 };
00788         const Types::Coordinate *coeff_kk = coeff_ll;
00789         for ( int k = 0; k < 3; ++k, coeff_kk += nextI ) 
00790           {
00791           const Types::Coordinate tmp = sp[k] * (*coeff_kk);
00792           kkJ[0] += ddsp[k] * (*coeff_kk);
00793           kkJ[1] += tmp;
00794           kkJ[2] += tmp;
00795           
00796           const Types::Coordinate tmp2 = dsp[k] * (*coeff_kk);
00797           kkK[0] += tmp2;
00798           kkK[1] +=  sp[k] * (*coeff_kk);
00799           kkK[2] += tmp2;
00800           }
00801         llJ[0] +=   sp[l] * kkJ[0];
00802         llJ[1] += ddsp[l] * kkJ[1];
00803         llJ[2] +=   sp[l] * kkJ[2];
00804         
00805         llK[0] +=  dsp[l] * kkK[0];
00806         llK[1] +=  dsp[l] * kkK[1];
00807         llK[2] +=   sp[l] * kkK[2];
00808         coeff_ll += nextJ;
00809         }       
00810       J[0][dim] +=   sp[m] * llJ[0];
00811       J[1][dim] +=   sp[m] * llJ[1];
00812       J[2][dim] += ddsp[m] * llJ[2];
00813       
00814       K[0][dim] +=   sp[m] * llK[0];
00815       K[1][dim] +=  dsp[m] * llK[1];
00816       K[2][dim] +=  dsp[m] * llK[2];
00817       coeff_mm += nextK;
00818       }
00819     ++coeff;
00820     }
00821   
00822   const double energy = 
00823     
00824     MathUtil::Square( InverseSpacing[0] ) *
00825     ( J[0][0] * J[0][0] + J[0][1] * J[0][1] + J[0][2] * J[0][2] ) +
00826     MathUtil::Square( InverseSpacing[1] ) *
00827     ( J[1][0] * J[1][0] + J[1][1] * J[1][1] + J[1][2] * J[1][2] ) +
00828     MathUtil::Square( InverseSpacing[2] ) *
00829     ( J[2][0] * J[2][0] + J[2][1] * J[2][1] + J[2][2] * J[2][2] ) +
00830     
00831     2 * ( InverseSpacing[0] * InverseSpacing[1] *
00832           ( K[0][0] * K[0][0] + K[0][1] * K[0][1] + K[0][2] * K[0][2] ) +
00833           InverseSpacing[1] * InverseSpacing[2] *
00834           ( K[1][0] * K[1][0] + K[1][1] * K[1][1] + K[1][2] * K[1][2] ) +
00835           InverseSpacing[2] * InverseSpacing[0] *
00836           ( K[2][0] * K[2][0] + K[2][1] * K[2][1] + K[2][2] * K[2][2] )
00837           );
00838   
00839   return energy;
00840 }
00841 
00842 void 
00843 SplineWarpXform::GetGridEnergyDerivative
00844 ( double& lower, double& upper, const int param, const Types::Coordinate step )
00845   const
00846 {
00847   const int controlPointIdx = param / nextI;
00848   const unsigned short x =  ( controlPointIdx %  this->m_Dims[0] );
00849   const unsigned short y = ( (controlPointIdx /  this->m_Dims[0]) % this->m_Dims[1] );
00850   const unsigned short z = ( (controlPointIdx /  this->m_Dims[0]) / this->m_Dims[1] );
00851   
00852   const int thisDim = param % nextI;
00853   const Types::Coordinate* coeff = m_Parameters + param - thisDim;
00854   
00855   double ground = 0;
00856 
00857   const int iFrom = std::max<int>( -1, 1-x );
00858   const int jFrom = std::max<int>( -1, 1-y );
00859   const int kFrom = std::max<int>( -1, 1-z );
00860 
00861   const int iTo = std::min<int>( 1, this->m_Dims[0]-2-x );
00862   const int jTo = std::min<int>( 1, this->m_Dims[1]-2-y );
00863   const int kTo = std::min<int>( 1, this->m_Dims[2]-2-z );
00864 
00865   for ( int k = kFrom; k < kTo; ++k )
00866     for ( int j = jFrom; j < jTo; ++j )
00867       for ( int i = iFrom; i < iTo; ++i )
00868         {
00869         ground += this->GetGridEnergy( coeff + i*nextI + j*nextJ + k*nextK );
00870         }
00871 
00872   upper = -ground;
00873   lower = -ground;
00874   
00875   const Types::Coordinate oldCoeff = m_Parameters[param];
00876   m_Parameters[param] += step;
00877   for ( int k = kFrom; k < kTo; ++k )
00878     for ( int j = jFrom; j < jTo; ++j )
00879       for ( int i = iFrom; i < iTo; ++i )
00880         upper += this->GetGridEnergy( coeff + i*nextI + j*nextJ + k*nextK );
00881 
00882   m_Parameters[param] = oldCoeff - step;
00883   for ( int k = kFrom; k < kTo; ++k )
00884     for ( int j = jFrom; j < jTo; ++j )
00885       for ( int i = iFrom; i < iTo; ++i )
00886         lower += this->GetGridEnergy( coeff + i*nextI + j*nextJ + k*nextK );
00887 
00888   m_Parameters[param] = oldCoeff;
00889 
00890   upper /= NumberOfControlPoints;
00891   lower /= NumberOfControlPoints;
00892 }
00893 
00894 Types::Coordinate
00895 SplineWarpXform::GetInverseConsistencyError
00896 ( const WarpXform* inverse, const UniformVolume* volume,
00897   const DataGrid::RegionType* voi )
00898   const 
00899 {
00900   Self::SpaceVectorType v, vv;
00901   Types::Coordinate result = 0.0;
00902   int count = 0;
00903 
00904   DataGrid::RegionType myVoi;
00905   const DataGrid::RegionType *pVoi = &myVoi;
00906   if ( voi ) 
00907     {
00908     pVoi = voi;
00909     } 
00910   else
00911     {
00912     myVoi = volume->GetWholeImageRegion();
00913     }
00914 
00915   const int dX = 1 + static_cast<int>( this->Spacing[0] / 2 * volume->m_Delta[AXIS_X] );
00916   const int dY = 1 + static_cast<int>( this->Spacing[1] / 2 * volume->m_Delta[AXIS_Y] );
00917   const int dZ = 1 + static_cast<int>( this->Spacing[2] / 2 * volume->m_Delta[AXIS_Z] );
00918 
00919   const int startX = pVoi->From()[0] - (pVoi->From()[0] % dX);
00920   const int startY = pVoi->From()[1] - (pVoi->From()[1] % dY);
00921   const int startZ = pVoi->From()[2] - (pVoi->From()[2] % dZ);
00922 
00923   const size_t length = pVoi->To()[0] - startX;
00924 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00925   Self::SpaceVectorType vecArray[length];
00926 #else
00927   std::vector<Self::SpaceVectorType> vecArray( length );
00928 #endif
00929 
00930   for ( int z = startZ; z < pVoi->To()[2]; z += dZ ) 
00931     {
00932     for ( int y = startY; y < pVoi->To()[1]; y += dY ) 
00933       {
00934       Self::SpaceVectorType* pVec = &vecArray[0];
00935       this->GetTransformedGridRow( length, pVec, startX, y, z );
00936 
00937       for ( int x = startX; x < pVoi->To()[0]; x += dX, pVec += dX ) 
00938         {
00939         if ( inverse->InDomain( *pVec ) ) 
00940           {
00941           inverse->ApplyInPlace( *pVec );
00942           v = volume->GetGridLocation( x, y, z );
00943           v -= *pVec;
00944           result += v.RootSumOfSquares();
00945           ++count;
00946           }
00947         }
00948       }
00949     }
00950   
00951   return count ? result / count : 0.0;
00952 }
00953 
00954 Types::Coordinate* 
00955 SplineWarpXform::GetPureDeformation( const bool includeScale ) const
00956 {
00957   const size_t numberOfParameters = this->m_NumberOfParameters;
00958   Types::Coordinate* points = Memory::AllocateArray<Types::Coordinate>(  numberOfParameters  );
00959   memcpy( points, this->m_Parameters, sizeof( *points ) * numberOfParameters );
00960   
00961   AffineXform::SmartPtr xform( this->GetInitialAffineXform()->MakeInverse() );
00962 
00963   if ( includeScale ) 
00964     {
00965     xform->SetScales( 1.0, 1.0, 1.0 );
00966     }
00967 
00968   Types::Coordinate* ptr = points;
00969   Self::SpaceVectorType u;
00970   for ( size_t pointIdx = 0; pointIdx < numberOfParameters / 3; ++pointIdx, ptr += 3 ) 
00971     {
00972     Self::SpaceVectorType v( ptr );
00973     
00974     
00975     xform->ApplyInPlace( v );
00976     
00977     
00978     for ( unsigned int dim = 0; dim < 3; ++dim ) 
00979       ptr[dim] = v[dim];
00980     }
00981   
00982   return points;
00983 }
00984 
00985 }