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 }