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 <System/cmtkThreadPool.h>
00037
00038 #include <Base/cmtkRegionIndexIterator.h>
00039
00040 #include <vector>
00041
00042 namespace
00043 cmtk
00044 {
00045
00048
00049 CoordinateMatrix3x3
00050 SplineWarpXform::GetJacobian( const Self::SpaceVectorType& v ) const
00051 {
00052 CoordinateMatrix3x3 J;
00053 this->GetJacobian( v, J );
00054 return J;
00055 }
00056
00057 void
00058 SplineWarpXform::GetJacobianRow
00059 ( CoordinateMatrix3x3 *const array, const int x, const int y, const int z, const size_t numberOfPoints )
00060 const
00061 {
00062 const Types::Coordinate *spX = &splineX[x<<2], *spY = &splineY[y<<2], *spZ = &splineZ[z<<2];
00063 const Types::Coordinate *dspX = &dsplineX[x<<2], *dspY = &dsplineY[y<<2], *dspZ = &dsplineZ[z<<2];
00064 const Types::Coordinate *coeff = this->m_Parameters + gX[x] + gY[y] + gZ[z];
00065
00066
00067
00068 Types::Coordinate smlX[16], smlY[16], smlZ[16];
00069 for ( int i = 0, m = 0; m < 4; ++m )
00070 {
00071 for ( int l = 0; l < 4; ++l, ++i )
00072 {
00073 smlX[i] = spZ[m] * spY[l];
00074 smlY[i] = spZ[m] * dspY[l];
00075 smlZ[i] = dspZ[m] * spY[l];
00076 }
00077 }
00078
00079
00080 const int numberOfCells = (gX[x + numberOfPoints - 1] - gX[x]) / nextI + 4;
00081
00082
00083
00084 Types::Coordinate phiCompX, phiCompY, phiCompZ;
00085
00086 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00087 Types::Coordinate phiHatX[3*numberOfCells];
00088 Types::Coordinate phiHatY[3*numberOfCells];
00089 Types::Coordinate phiHatZ[3*numberOfCells];
00090 #else
00091 std::vector<Types::Coordinate> phiHatX(3*numberOfCells);
00092 std::vector<Types::Coordinate> phiHatY(3*numberOfCells);
00093 std::vector<Types::Coordinate> phiHatZ(3*numberOfCells);
00094 #endif
00095
00096 const int *gpo;
00097 int phiIdx = 0;
00098 for ( int cell = 0; cell < numberOfCells; ++cell, coeff += nextI )
00099 {
00100 gpo = &GridPointOffset[0];
00101 for ( int dim = 0; dim < 3; ++dim, ++phiIdx )
00102 {
00103 phiCompX = phiCompY = phiCompZ = 0;
00104 for ( int ml = 0; ml < 16; ++ml, ++gpo )
00105 {
00106 phiCompX += coeff[ *gpo ] * smlX[ml];
00107 phiCompY += coeff[ *gpo ] * smlY[ml];
00108 phiCompZ += coeff[ *gpo ] * smlZ[ml];
00109 }
00110 phiHatX[phiIdx] = phiCompX;
00111 phiHatY[phiIdx] = phiCompY;
00112 phiHatZ[phiIdx] = phiCompZ;
00113 }
00114 }
00115
00116
00117 int cellIdx = 0;
00118
00119 CoordinateMatrix3x3 J;
00120
00121 int i = x;
00122 for ( const int lastPoint = x + numberOfPoints; i < lastPoint; )
00123 {
00124
00125 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00126 const Types::Coordinate* phiPtrX = phiHatX + 3*cellIdx;
00127 const Types::Coordinate* phiPtrY = phiHatY + 3*cellIdx;
00128 const Types::Coordinate* phiPtrZ = phiHatZ + 3*cellIdx;
00129 #else
00130 const Types::Coordinate* phiPtrX = &phiHatX[3*cellIdx];
00131 const Types::Coordinate* phiPtrY = &phiHatY[3*cellIdx];
00132 const Types::Coordinate* phiPtrZ = &phiHatZ[3*cellIdx];
00133 #endif
00134
00135
00136 do
00137 {
00138
00139
00140
00141 J[0][0] = this->InverseSpacing[0] * ( dspX[0] * phiPtrX[0] + dspX[1] * phiPtrX[3] + dspX[2] * phiPtrX[6] + dspX[3] * phiPtrX[9] );
00142 J[0][1] = this->InverseSpacing[0] * ( dspX[0] * phiPtrX[1] + dspX[1] * phiPtrX[4] + dspX[2] * phiPtrX[7] + dspX[3] * phiPtrX[10] );
00143 J[0][2] = this->InverseSpacing[0] * ( dspX[0] * phiPtrX[2] + dspX[1] * phiPtrX[5] + dspX[2] * phiPtrX[8] + dspX[3] * phiPtrX[11] );
00144
00145 J[1][0] = this->InverseSpacing[1] * ( spX[0] * phiPtrY[0] + spX[1] * phiPtrY[3] + spX[2] * phiPtrY[6] + spX[3] * phiPtrY[9] );
00146 J[1][1] = this->InverseSpacing[1] * ( spX[0] * phiPtrY[1] + spX[1] * phiPtrY[4] + spX[2] * phiPtrY[7] + spX[3] * phiPtrY[10] );
00147 J[1][2] = this->InverseSpacing[1] * ( spX[0] * phiPtrY[2] + spX[1] * phiPtrY[5] + spX[2] * phiPtrY[8] + spX[3] * phiPtrY[11] );
00148
00149 J[2][0] = this->InverseSpacing[2] * ( spX[0] * phiPtrZ[0] + spX[1] * phiPtrZ[3] + spX[2] * phiPtrZ[6] + spX[3] * phiPtrZ[9] );
00150 J[2][1] = this->InverseSpacing[2] * ( spX[0] * phiPtrZ[1] + spX[1] * phiPtrZ[4] + spX[2] * phiPtrZ[7] + spX[3] * phiPtrZ[10] );
00151 J[2][2] = this->InverseSpacing[2] * ( spX[0] * phiPtrZ[2] + spX[1] * phiPtrZ[5] + spX[2] * phiPtrZ[8] + spX[3] * phiPtrZ[11] );
00152
00153 array[i-x].Set( &J[0][0] );
00154
00155
00156 ++i;
00157 spX += 4;
00158 dspX += 4;
00159
00160 } while ( ( gX[i-1] == gX[i] ) && ( i < lastPoint ) );
00161
00162
00163
00164 ++cellIdx;
00165 }
00166 }
00167
00168 void
00169 SplineWarpXform::GetJacobianAtControlPoint
00170 ( const Types::Coordinate* cp, CoordinateMatrix3x3& J ) const
00171 {
00172 J.Fill( 0.0 );
00173
00174 const double sp[3] = { 1.0/6, 2.0/3, 1.0/6 };
00175 const double dsp[3] = { -1.0/2, 0, 1.0/2 };
00176
00177 const Types::Coordinate* coeff = cp - nextI - nextJ - nextK;
00178 for ( int dim = 0; dim<3; ++dim ) {
00179 const Types::Coordinate *coeff_mm = coeff;
00180 for ( int m = 0; m < 3; ++m ) {
00181 Types::Coordinate ll[3] = { 0, 0, 0 };
00182 const Types::Coordinate *coeff_ll = coeff_mm;
00183 for ( int l = 0; l < 3; ++l ) {
00184 Types::Coordinate kk[3] = { 0, 0, 0 };
00185 const Types::Coordinate *coeff_kk = coeff_ll;
00186 for ( int k = 0; k < 3; ++k, coeff_kk += nextI ) {
00187 kk[0] += dsp[k] * (*coeff_kk);
00188 kk[1] += sp[k] * (*coeff_kk);
00189 kk[2] += sp[k] * (*coeff_kk);
00190 }
00191 ll[0] += sp[l] * kk[0];
00192 ll[1] += dsp[l] * kk[1];
00193 ll[2] += sp[l] * kk[2];
00194 coeff_ll += nextJ;
00195 }
00196 J[0][dim] += sp[m] * ll[0];
00197 J[1][dim] += sp[m] * ll[1];
00198 J[2][dim] += dsp[m] * ll[2];
00199 coeff_mm += nextK;
00200 }
00201 ++coeff;
00202 }
00203 for ( int i = 0; i<3; ++i )
00204 {
00205 for ( int j = 0; j<3; ++j )
00206 J[i][j] *= this->InverseSpacing[i];
00207 }
00208 }
00209
00210 void
00211 SplineWarpXform::GetJacobian
00212 ( const Self::SpaceVectorType& v, CoordinateMatrix3x3& J ) const
00213 {
00214 Types::Coordinate r[3], f[3];
00215 int grid[3];
00216
00217 for ( int dim = 0; dim<3; ++dim )
00218 {
00219 r[dim] = this->InverseSpacing[dim] * v[dim];
00220 grid[dim] = std::min( static_cast<int>( r[dim] ), this->m_Dims[dim]-4 );
00221 f[dim] = std::max<Types::Coordinate>( 0, std::min<Types::Coordinate>( 1.0, r[dim] - grid[dim] ) );
00222 }
00223
00224 const Types::Coordinate* coeff = this->m_Parameters + 3 * ( grid[0] + this->m_Dims[0] * (grid[1] + this->m_Dims[1] * grid[2]) );
00225
00226
00227
00228 for ( int dim = 0; dim<3; ++dim, ++coeff )
00229 {
00230 const Types::Coordinate *coeff_mm = coeff;
00231 for ( int m = 0; m < 4; ++m, coeff_mm += nextK )
00232 {
00233 Types::Coordinate ll[3] = { 0, 0, 0 };
00234 const Types::Coordinate *coeff_ll = coeff_mm;
00235 for ( int l = 0; l < 4; ++l, coeff_ll += nextJ )
00236 {
00237 Types::Coordinate kk[3] = { 0, 0, 0 };
00238 const Types::Coordinate *coeff_kk = coeff_ll;
00239
00240 for ( int k = 0; k < 4; ++k, coeff_kk+=3 )
00241 {
00242
00243 kk[0] += CubicSpline::DerivApproxSpline( k, f[0] ) * (*coeff_kk);
00244
00245 const Types::Coordinate tmp = CubicSpline::ApproxSpline( k, f[0] ) * (*coeff_kk);
00246 kk[1] += tmp;
00247
00248 kk[2] += tmp;
00249 }
00250
00251
00252 const Types::Coordinate tmp = CubicSpline::ApproxSpline( l, f[1] );
00253 ll[0] += tmp * kk[0];
00254
00255 ll[1] += CubicSpline::DerivApproxSpline( l, f[1] ) * kk[1];
00256
00257 ll[2] += tmp * kk[2];
00258 }
00259
00260
00261 const Types::Coordinate tmp = CubicSpline::ApproxSpline( m, f[2] );
00262 J[dim][0] += tmp * ll[0];
00263
00264 J[dim][1] += tmp * ll[1];
00265
00266 J[dim][2] += CubicSpline::DerivApproxSpline( m, f[2] ) * ll[2];
00267 }
00268 }
00269
00270
00271 for ( int i = 0; i<3; ++i )
00272 {
00273 for ( int j = 0; j<3; ++j )
00274 J[i][j] *= this->InverseSpacing[i];
00275 }
00276 }
00277
00278 Types::Coordinate
00279 SplineWarpXform::GetJacobianDeterminant
00280 ( const int x, const int y, const int z ) const
00281 {
00282 const Types::Coordinate *spX = &splineX[x<<2], *spY = &splineY[y<<2], *spZ = &splineZ[z<<2];
00283 const Types::Coordinate *dspX = &dsplineX[x<<2], *dspY = &dsplineY[y<<2], *dspZ = &dsplineZ[z<<2];
00284 const Types::Coordinate *coeff = this->m_Parameters + gX[x] + gY[y] + gZ[z];
00285
00286 double J[3][3];
00287 memset( J, 0, sizeof( J ) );
00288 for ( int dim = 0; dim<3; ++dim )
00289 {
00290 const Types::Coordinate *coeff_mm = coeff;
00291 for ( int m = 0; m < 4; ++m )
00292 {
00293 Types::Coordinate ll[3] = { 0, 0, 0 };
00294 const Types::Coordinate *coeff_ll = coeff_mm;
00295 for ( int l = 0; l < 4; ++l )
00296 {
00297 Types::Coordinate kk[3] = { 0, 0, 0 };
00298 const Types::Coordinate *coeff_kk = coeff_ll;
00299 for ( int k = 0; k < 4; ++k, coeff_kk+=3 )
00300 {
00301 kk[0] += dspX[k] * (*coeff_kk);
00302 kk[1] += spX[k];
00303 kk[2] += spX[k];
00304 }
00305 ll[0] += spY[l] * kk[0];
00306 ll[1] += dspY[l] * kk[1];
00307 ll[2] += spY[l] * kk[2];
00308 coeff_ll += nextJ;
00309 }
00310 J[0][dim] += spZ[m] * ll[0];
00311 J[1][dim] += spZ[m] * ll[1];
00312 J[2][dim] += dspZ[m] * ll[2];
00313 coeff_mm += nextK;
00314 }
00315 ++coeff;
00316 }
00317
00318 return InverseSpacing[0] * InverseSpacing[1] * InverseSpacing[2] *
00319 ( J[0][0] * (J[1][1]*J[2][2] - J[1][2]*J[2][1]) +
00320 J[0][1] * (J[1][2]*J[2][0] - J[1][0]*J[2][2]) +
00321 J[0][2] * (J[1][0]*J[2][1] - J[1][1]*J[2][0]) );
00322 }
00323
00324 Types::Coordinate
00325 SplineWarpXform::GetJacobianDeterminant
00326 ( const Self::SpaceVectorType& v ) const
00327 {
00328 Types::Coordinate r[3], f[3];
00329 int grid[3];
00330
00331 double J[3][3];
00332 memset( J, 0, sizeof( J ) );
00333
00334 for ( int dim = 0; dim<3; ++dim )
00335 {
00336 r[dim] = InverseSpacing[dim] * v[dim];
00337 grid[dim] = std::min( static_cast<int>( r[dim] ), this->m_Dims[dim]-4 );
00338 f[dim] = std::max<Types::Coordinate>( 0, std::min<Types::Coordinate>( 1.0, r[dim] - grid[dim] ) );
00339 }
00340
00341 const Types::Coordinate* coeff = this->m_Parameters + 3 * ( grid[0] + this->m_Dims[0] * (grid[1] + this->m_Dims[1] * grid[2]) );
00342
00343 for ( int dim = 0; dim<3; ++dim )
00344 {
00345 const Types::Coordinate *coeff_mm = coeff;
00346 for ( int m = 0; m < 4; ++m )
00347 {
00348 Types::Coordinate ll[3] = { 0, 0, 0 };
00349 const Types::Coordinate *coeff_ll = coeff_mm;
00350 for ( int l = 0; l < 4; ++l )
00351 {
00352 Types::Coordinate kk[3] = { 0, 0, 0 };
00353 const Types::Coordinate *coeff_kk = coeff_ll;
00354 for ( int k = 0; k < 4; ++k, coeff_kk+=3 )
00355 {
00356 kk[0] += CubicSpline::DerivApproxSpline( k, f[0] ) * (*coeff_kk);
00357 const Types::Coordinate tmp = CubicSpline::ApproxSpline( k, f[0] ) * (*coeff_kk);
00358 kk[1] += tmp;
00359 kk[2] += tmp;
00360 }
00361 const Types::Coordinate tmp = CubicSpline::ApproxSpline( l, f[1] );
00362 ll[0] += tmp * kk[0];
00363 ll[1] += CubicSpline::DerivApproxSpline( l, f[1] ) * kk[1];
00364 ll[2] += tmp * kk[2];
00365 coeff_ll += nextJ;
00366 }
00367 const Types::Coordinate tmp = CubicSpline::ApproxSpline( m, f[2] );
00368 J[0][dim] += tmp * ll[0];
00369 J[1][dim] += tmp * ll[1];
00370 J[2][dim] += CubicSpline::DerivApproxSpline( m, f[2] ) * ll[2];
00371 coeff_mm += nextK;
00372 }
00373 ++coeff;
00374 }
00375
00376 return InverseSpacing[0] * InverseSpacing[1] * InverseSpacing[2] *
00377 ( J[0][0] * (J[1][1]*J[2][2] - J[1][2]*J[2][1]) +
00378 J[0][1] * (J[1][2]*J[2][0] - J[1][0]*J[2][2]) +
00379 J[0][2] * (J[1][0]*J[2][1] - J[1][1]*J[2][0]) );
00380 }
00381
00382 void
00383 SplineWarpXform::GetJacobianDeterminantRow
00384 ( double *const values, const int x, const int y, const int z,
00385 const size_t numberOfPoints )
00386 const
00387 {
00388 const Types::Coordinate *spX = &splineX[x<<2], *spY = &splineY[y<<2], *spZ = &splineZ[z<<2];
00389 const Types::Coordinate *dspX = &dsplineX[x<<2], *dspY = &dsplineY[y<<2], *dspZ = &dsplineZ[z<<2];
00390 const Types::Coordinate *coeff = this->m_Parameters + gX[x] + gY[y] + gZ[z];
00391
00392 const Types::Coordinate globalInverseSpacing = InverseSpacing[0] * InverseSpacing[1] * InverseSpacing[2];
00393
00394
00395
00396 Types::Coordinate smlX[16], smlY[16], smlZ[16];
00397 for ( int i = 0, m = 0; m < 4; ++m )
00398 {
00399 for ( int l = 0; l < 4; ++l, ++i )
00400 {
00401 smlX[i] = spZ[m] * spY[l];
00402 smlY[i] = spZ[m] * dspY[l];
00403 smlZ[i] = dspZ[m] * spY[l];
00404 }
00405 }
00406
00407
00408 const int numberOfCells = (gX[x + numberOfPoints - 1] - gX[x]) / nextI + 4;
00409
00410
00411
00412 Types::Coordinate phiCompX, phiCompY, phiCompZ;
00413
00414 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00415 Types::Coordinate phiHatX[3*numberOfCells];
00416 Types::Coordinate phiHatY[3*numberOfCells];
00417 Types::Coordinate phiHatZ[3*numberOfCells];
00418 #else
00419 std::vector<Types::Coordinate> phiHatX(3*numberOfCells);
00420 std::vector<Types::Coordinate> phiHatY(3*numberOfCells);
00421 std::vector<Types::Coordinate> phiHatZ(3*numberOfCells);
00422 #endif
00423
00424 const int *gpo;
00425 int phiIdx = 0;
00426 for ( int cell = 0; cell < numberOfCells; ++cell, coeff += nextI )
00427 {
00428 gpo = &GridPointOffset[0];
00429 for ( int dim = 0; dim < 3; ++dim, ++phiIdx )
00430 {
00431 phiCompX = phiCompY = phiCompZ = 0;
00432 for ( int ml = 0; ml < 16; ++ml, ++gpo )
00433 {
00434 phiCompX += coeff[ *gpo ] * smlX[ml];
00435 phiCompY += coeff[ *gpo ] * smlY[ml];
00436 phiCompZ += coeff[ *gpo ] * smlZ[ml];
00437 }
00438 phiHatX[phiIdx] = phiCompX;
00439 phiHatY[phiIdx] = phiCompY;
00440 phiHatZ[phiIdx] = phiCompZ;
00441 }
00442 }
00443
00444
00445 int cellIdx = 0;
00446
00447 Types::Coordinate JXX, JXY, JXZ, JYX, JYY, JYZ, JZX, JZY, JZZ;
00448
00449 int i = x;
00450 for ( const int lastPoint = x + numberOfPoints; i < lastPoint; )
00451 {
00452
00453 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00454 const Types::Coordinate* phiPtrX = phiHatX + 3*cellIdx;
00455 const Types::Coordinate* phiPtrY = phiHatY + 3*cellIdx;
00456 const Types::Coordinate* phiPtrZ = phiHatZ + 3*cellIdx;
00457 #else
00458 const Types::Coordinate* phiPtrX = &phiHatX[3*cellIdx];
00459 const Types::Coordinate* phiPtrY = &phiHatY[3*cellIdx];
00460 const Types::Coordinate* phiPtrZ = &phiHatZ[3*cellIdx];
00461 #endif
00462
00463
00464 do
00465 {
00466
00467
00468
00469 JXX = dspX[0] * phiPtrX[0] + dspX[1] * phiPtrX[3] + dspX[2] * phiPtrX[6] + dspX[3] * phiPtrX[9];
00470 JXY = dspX[0] * phiPtrX[1] + dspX[1] * phiPtrX[4] + dspX[2] * phiPtrX[7] + dspX[3] * phiPtrX[10];
00471 JXZ = dspX[0] * phiPtrX[2] + dspX[1] * phiPtrX[5] + dspX[2] * phiPtrX[8] + dspX[3] * phiPtrX[11];
00472
00473 JYX = spX[0] * phiPtrY[0] + spX[1] * phiPtrY[3] + spX[2] * phiPtrY[6] + spX[3] * phiPtrY[9];
00474 JYY = spX[0] * phiPtrY[1] + spX[1] * phiPtrY[4] + spX[2] * phiPtrY[7] + spX[3] * phiPtrY[10];
00475 JYZ = spX[0] * phiPtrY[2] + spX[1] * phiPtrY[5] + spX[2] * phiPtrY[8] + spX[3] * phiPtrY[11];
00476
00477 JZX = spX[0] * phiPtrZ[0] + spX[1] * phiPtrZ[3] + spX[2] * phiPtrZ[6] + spX[3] * phiPtrZ[9];
00478 JZY = spX[0] * phiPtrZ[1] + spX[1] * phiPtrZ[4] + spX[2] * phiPtrZ[7] + spX[3] * phiPtrZ[10];
00479 JZZ = spX[0] * phiPtrZ[2] + spX[1] * phiPtrZ[5] + spX[2] * phiPtrZ[8] + spX[3] * phiPtrZ[11];
00480
00481 values[i-x] = globalInverseSpacing *
00482 ( JXX * (JYY*JZZ - JYZ*JZY) + JXY * (JYZ*JZX - JYX*JZZ) + JXZ * (JYX*JZY - JYY*JZX) );
00483
00484
00485 ++i;
00486 spX += 4;
00487 dspX += 4;
00488
00489 } while ( ( gX[i-1] == gX[i] ) && ( i < lastPoint ) );
00490
00491
00492
00493 ++cellIdx;
00494 }
00495 }
00496
00497 Types::Coordinate
00498 SplineWarpXform::JacobianDeterminant ( const Types::Coordinate *cp ) const
00499 {
00500 CoordinateMatrix3x3 J;
00501 this->GetJacobianAtControlPoint( cp, J );
00502
00503 return InverseSpacing[0] * InverseSpacing[1] * InverseSpacing[2] *
00504 ( J[0][0] * (J[1][1]*J[2][2] - J[1][2]*J[2][1]) +
00505 J[0][1] * (J[1][2]*J[2][0] - J[1][0]*J[2][2]) +
00506 J[0][2] * (J[1][0]*J[2][1] - J[1][1]*J[2][0]) );
00507 }
00508
00509 void
00510 SplineWarpXform
00511 ::GetJacobianConstraintThread( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t, const size_t )
00512 {
00513 Self::JacobianConstraintThreadInfo *info = static_cast<Self::JacobianConstraintThreadInfo*>( args );
00514
00515 const SplineWarpXform *me = info->thisObject;
00516
00517 const int pixelsPerRow = me->VolumeDims[0];
00518 std::vector<double> valuesJ( pixelsPerRow );
00519
00520 const int rowCount = ( me->VolumeDims[1] * me->VolumeDims[2] );
00521 const int rowFrom = ( rowCount / taskCnt ) * taskIdx;
00522 const int rowTo = ( taskIdx == (taskCnt-1) ) ? rowCount : ( rowCount/taskCnt ) * (taskIdx+1);
00523 int rowsToDo = rowTo - rowFrom;
00524
00525 int yFrom = rowFrom % me->VolumeDims[1];
00526 int zFrom = rowFrom / me->VolumeDims[2];
00527
00528 double constraint = 0;
00529 for ( int z = zFrom; (z < me->VolumeDims[2]) && rowsToDo; ++z )
00530 {
00531 for ( int y = yFrom; (y < me->VolumeDims[1]) && rowsToDo; yFrom = 0, ++y, --rowsToDo )
00532 {
00533 me->GetJacobianDeterminantRow( &(valuesJ[0]), 0, y, z, pixelsPerRow );
00534 for ( int x = 0; x < pixelsPerRow; ++x )
00535 {
00536 constraint += fabs( log ( valuesJ[x] / me->GlobalScaling ) );
00537 }
00538 }
00539 }
00540
00541
00542
00543 info->Constraint = constraint;
00544 }
00545
00546 void
00547 SplineWarpXform
00548 ::GetJacobianFoldingConstraintThread( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t, const size_t )
00549 {
00550 Self::JacobianConstraintThreadInfo *info = static_cast<Self::JacobianConstraintThreadInfo*>( args );
00551
00552 const SplineWarpXform *me = info->thisObject;
00553
00554 const int pixelsPerRow = me->VolumeDims[0];
00555 std::vector<double> valuesJ( pixelsPerRow );
00556
00557 const int rowCount = ( me->VolumeDims[1] * me->VolumeDims[2] );
00558 const int rowFrom = ( rowCount / taskCnt ) * taskIdx;
00559 const int rowTo = ( taskIdx == (taskCnt-1) ) ? rowCount : ( rowCount/taskCnt ) * (taskIdx+1);
00560 int rowsToDo = rowTo - rowFrom;
00561
00562 int yFrom = rowFrom % me->VolumeDims[1];
00563 int zFrom = rowFrom / me->VolumeDims[2];
00564
00565 double constraint = 0;
00566 for ( int z = zFrom; (z < me->VolumeDims[2]) && rowsToDo; ++z )
00567 {
00568 for ( int y = yFrom; (y < me->VolumeDims[1]) && rowsToDo; yFrom = 0, ++y, --rowsToDo )
00569 {
00570 me->GetJacobianDeterminantRow( &(valuesJ[0]), 0, y, z, pixelsPerRow );
00571 for ( int x = 0; x < pixelsPerRow; ++x )
00572 {
00573 constraint += fabs( me->GlobalScaling / valuesJ[x] + valuesJ[x] / me->GlobalScaling - 2 );
00574 }
00575 }
00576 }
00577
00578
00579
00580 info->Constraint = constraint;
00581 }
00582
00583 Types::Coordinate
00584 SplineWarpXform::GetJacobianConstraint () const
00585 {
00586 ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00587 const size_t numberOfThreads = threadPool.GetNumberOfThreads();
00588 const size_t numberOfTasks = std::min<size_t>( 4 * numberOfThreads - 3, this->m_Dims[2] );
00589
00590
00591 std::vector<Self::JacobianConstraintThreadInfo> constraintTaskInfo( numberOfTasks );
00592 for ( size_t taskIdx = 0; taskIdx < numberOfTasks; ++taskIdx )
00593 {
00594 constraintTaskInfo[taskIdx].thisObject = this;
00595 }
00596
00597 threadPool.Run( Self::GetJacobianConstraintThread, constraintTaskInfo );
00598
00599 double constraint = 0;
00600 for ( size_t taskIdx = 0; taskIdx < numberOfTasks; ++taskIdx )
00601 {
00602 constraint += constraintTaskInfo[taskIdx].Constraint;
00603 }
00604
00605
00606
00607 return constraint / ( VolumeDims[0] * VolumeDims[1] * VolumeDims[2] );
00608 }
00609
00610 Types::Coordinate
00611 SplineWarpXform::GetJacobianFoldingConstraint () const
00612 {
00613 ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00614 const size_t numberOfThreads = threadPool.GetNumberOfThreads();
00615 const size_t numberOfTasks = std::min<size_t>( 4 * numberOfThreads - 3, this->m_Dims[2] );
00616
00617
00618 std::vector<Self::JacobianConstraintThreadInfo> constraintTaskInfo( numberOfTasks );
00619 for ( size_t taskIdx = 0; taskIdx < numberOfTasks; ++taskIdx )
00620 {
00621 constraintTaskInfo[taskIdx].thisObject = this;
00622 }
00623
00624 threadPool.Run( Self::GetJacobianFoldingConstraintThread, constraintTaskInfo );
00625
00626 double constraint = 0;
00627 for ( size_t taskIdx = 0; taskIdx < numberOfTasks; ++taskIdx )
00628 {
00629 constraint += constraintTaskInfo[taskIdx].Constraint;
00630 }
00631
00632
00633
00634 return constraint / ( VolumeDims[0] * VolumeDims[1] * VolumeDims[2] );
00635 }
00636
00637 Types::Coordinate
00638 SplineWarpXform::GetJacobianConstraintSparse () const
00639 {
00640 double Constraint = 0;
00641
00642 const Types::Coordinate* coeff = this->m_Parameters + nextI + nextJ + nextK;
00643 for ( int z = 1; z<this->m_Dims[2]-1; ++z, coeff+=2*nextJ )
00644 for ( int y = 1; y<this->m_Dims[1]-1; ++y, coeff+=2*nextI )
00645 for ( int x = 1; x<this->m_Dims[0]-1; ++x, coeff+=nextI )
00646 Constraint += fabs( log ( this->GetJacobianDeterminant( Self::SpaceVectorType( coeff ) ) / GlobalScaling ) );
00647
00648
00649
00650 return (double)(Constraint / this->NumberOfControlPoints);
00651 }
00652
00653 void
00654 SplineWarpXform::GetJacobianConstraintDerivative
00655 ( double& lower, double& upper, const int param, const DataGrid::RegionType& voi, const Types::Coordinate step ) const
00656 {
00657 const int pixelsPerRow = voi.To()[0] - voi.From()[0];
00658 std::vector<double> valuesJ( pixelsPerRow );
00659
00660 double ground = 0;
00661
00662 for ( int k = voi.From()[2]; k < voi.To()[2]; ++k )
00663 for ( int j = voi.From()[1]; j < voi.To()[1]; ++j )
00664 {
00665 this->GetJacobianDeterminantRow( &(valuesJ[0]), voi.From()[0], j, k, pixelsPerRow );
00666 for ( int i = 0; i < pixelsPerRow; ++i )
00667 ground += fabs( log( valuesJ[i] / GlobalScaling ) );
00668 }
00669
00670 upper = -ground;
00671 lower = -ground;
00672
00673 const Types::Coordinate oldCoeff = this->m_Parameters[param];
00674 this->m_Parameters[param] += step;
00675 for ( int k = voi.From()[2]; k < voi.To()[2]; ++k )
00676 for ( int j = voi.From()[1]; j < voi.To()[1]; ++j )
00677 {
00678 this->GetJacobianDeterminantRow( &(valuesJ[0]), voi.From()[0], j, k, pixelsPerRow );
00679 for ( int i = 0; i < pixelsPerRow; ++i )
00680 {
00681 upper += fabs( log( valuesJ[i] / GlobalScaling ) );
00682 }
00683 }
00684
00685 this->m_Parameters[param] = oldCoeff - step;
00686 for ( int k = voi.From()[2]; k < voi.To()[2]; ++k )
00687 for ( int j = voi.From()[1]; j < voi.To()[1]; ++j )
00688 {
00689 this->GetJacobianDeterminantRow( &(valuesJ[0]), voi.From()[0], j, k, pixelsPerRow );
00690 for ( int i = 0; i < pixelsPerRow; ++i )
00691 {
00692 lower += fabs( log( valuesJ[i] / GlobalScaling ) );
00693 }
00694 }
00695 this->m_Parameters[param] = oldCoeff;
00696
00697 const double invVolume = 1.0 / voi.Size();
00698 upper *= invVolume;
00699 lower *= invVolume;
00700 }
00701
00702 void
00703 SplineWarpXform::GetJacobianFoldingConstraintDerivative
00704 ( double& lower, double& upper, const int param, const DataGrid::RegionType& voi, const Types::Coordinate step ) const
00705 {
00706 const int pixelsPerRow = voi.To()[0] - voi.From()[0];
00707 std::vector<double> valuesJ( pixelsPerRow );
00708
00709 double ground = 0;
00710
00711 for ( int k = voi.From()[2]; k < voi.To()[2]; ++k )
00712 for ( int j = voi.From()[1]; j < voi.To()[1]; ++j )
00713 {
00714 this->GetJacobianDeterminantRow( &(valuesJ[0]), voi.From()[0], j, k, pixelsPerRow );
00715 for ( int i = 0; i < pixelsPerRow; ++i )
00716 ground += fabs( this->GlobalScaling / valuesJ[i] + valuesJ[i] / this->GlobalScaling - 2 );
00717 }
00718
00719 upper = -ground;
00720 lower = -ground;
00721
00722 const Types::Coordinate oldCoeff = this->m_Parameters[param];
00723 this->m_Parameters[param] += step;
00724 for ( int k = voi.From()[2]; k < voi.To()[2]; ++k )
00725 for ( int j = voi.From()[1]; j < voi.To()[1]; ++j )
00726 {
00727 this->GetJacobianDeterminantRow( &(valuesJ[0]), voi.From()[0], j, k, pixelsPerRow );
00728 for ( int i = 0; i < pixelsPerRow; ++i )
00729 {
00730 upper += fabs( this->GlobalScaling / valuesJ[i] + valuesJ[i] / this->GlobalScaling - 2 );
00731
00732 }
00733 }
00734
00735 this->m_Parameters[param] = oldCoeff - step;
00736 for ( int k = voi.From()[2]; k < voi.To()[2]; ++k )
00737 for ( int j = voi.From()[1]; j < voi.To()[1]; ++j )
00738 {
00739 this->GetJacobianDeterminantRow( &(valuesJ[0]), voi.From()[0], j, k, pixelsPerRow );
00740 for ( int i = 0; i < pixelsPerRow; ++i )
00741 {
00742 lower += fabs( this->GlobalScaling / valuesJ[i] + valuesJ[i] / this->GlobalScaling - 2 );
00743 }
00744 }
00745 this->m_Parameters[param] = oldCoeff;
00746
00747 const double invVolume = 1.0 / voi.Size();
00748 upper *= invVolume;
00749 lower *= invVolume;
00750 }
00751
00752 void
00753 SplineWarpXform::GetJacobianConstraintDerivative
00754 ( double& lower, double& upper, const int param, const Types::Coordinate step )
00755 const
00756 {
00757 const int controlPointIdx = param / nextI;
00758 const unsigned short x = ( controlPointIdx % this->m_Dims[0] );
00759 const unsigned short y = ( (controlPointIdx / this->m_Dims[0]) % this->m_Dims[1] );
00760 const unsigned short z = ( (controlPointIdx / this->m_Dims[0]) / this->m_Dims[1] );
00761
00762 const int thisDim = param % nextI;
00763 const Types::Coordinate* coeff = this->m_Parameters + param - thisDim;
00764
00765 double ground = 0;
00766
00767 const int iFrom = std::max( -1, 1-x );
00768 const int jFrom = std::max( -1, 1-y );
00769 const int kFrom = std::max( -1, 1-z );
00770
00771 const int iTo = std::min( 1, this->m_Dims[0]-2-x );
00772 const int jTo = std::min( 1, this->m_Dims[1]-2-y );
00773 const int kTo = std::min( 1, this->m_Dims[2]-2-z );
00774
00775 for ( int k = kFrom; k < kTo; ++k )
00776 for ( int j = jFrom; j < jTo; ++j )
00777 for ( int i = iFrom; i < iTo; ++i )
00778 ground += fabs( log( this->GetJacobianDeterminant( Self::SpaceVectorType( coeff + i*nextI + j*nextJ + k*nextK ) ) / GlobalScaling ) );
00779
00780 upper = -ground;
00781 lower = -ground;
00782
00783 const Types::Coordinate oldCoeff = this->m_Parameters[param];
00784 this->m_Parameters[param] += step;
00785 for ( int k = kFrom; k < kTo; ++k )
00786 for ( int j = jFrom; j < jTo; ++j )
00787 for ( int i = iFrom; i < iTo; ++i )
00788 upper += fabs( log( this->GetJacobianDeterminant( Self::SpaceVectorType( coeff + i*nextI + j*nextJ + k*nextK ) ) / GlobalScaling ) );
00789
00790 this->m_Parameters[param] = oldCoeff - step;
00791 for ( int k = kFrom; k < kTo; ++k )
00792 for ( int j = jFrom; j < jTo; ++j )
00793 for ( int i = iFrom; i < iTo; ++i )
00794 lower += fabs( log( this->GetJacobianDeterminant( Self::SpaceVectorType( coeff + i*nextI + j*nextJ + k*nextK ) ) / GlobalScaling ) );
00795 this->m_Parameters[param] = oldCoeff;
00796
00797 upper /= this->NumberOfControlPoints;
00798 lower /= this->NumberOfControlPoints;
00799 }
00800
00801 void
00802 SplineWarpXform::RelaxToUnfold()
00803 {
00804 std::vector<byte> cpList( this->NumberOfControlPoints );
00805 std::vector<double> jacobiansRow( this->VolumeDims[0] );
00806
00807 bool isFolded = true;
00808 while ( isFolded )
00809 {
00810
00811 isFolded = false;
00812 std::fill( cpList.begin(), cpList.end(), 0 );
00813
00814 for ( int k = 0; k < this->VolumeDims[2]; ++k )
00815 {
00816 for ( int j = 0; j < this->VolumeDims[1]; ++j )
00817 {
00818 this->GetJacobianDeterminantRow( &(jacobiansRow[0]), 0, j, k, this->VolumeDims[0] );
00819 for ( int i = 0; i < this->VolumeDims[0]; ++i )
00820 {
00821 if ( jacobiansRow[i] <= 0 )
00822 {
00823 isFolded = true;
00824 cpList[ (this->gX[i] + this->gY[j] + this->gZ[k])/3 ] = 1;
00825 }
00826 }
00827 }
00828 }
00829
00830 if ( isFolded )
00831 {
00832
00833 for ( int k = 0; k < this->m_Dims[2]; ++k )
00834 {
00835 for ( int j = 0; j < this->m_Dims[1]; ++j )
00836 {
00837 for ( int i = 0; i < this->m_Dims[0]; ++i )
00838 {
00839 if ( cpList[ (i * this->nextI + j * this->nextJ + k * this->nextK)/3 ] == 1 )
00840 {
00841 for ( int kk = std::max( 0, k-3 ); kk < std::min( k+4, this->m_Dims[2] ); ++kk )
00842 {
00843 for ( int jj = std::max( 0, j-3 ); jj < std::min( j+4, this->m_Dims[1] ); ++jj )
00844 {
00845 for ( int ii = std::max( 0, i-3 ); ii < std::min( i+4, this->m_Dims[0] ); ++ii )
00846 {
00847 const size_t cpIdx = (ii * this->nextI + jj * this->nextJ + kk * this->nextK)/3;
00848 if ( cpList[ cpIdx ] != 1 )
00849 {
00850 cpList[ cpIdx ] = 2;
00851 }
00852 }
00853 }
00854 }
00855 }
00856 }
00857 }
00858 }
00859
00860
00861 std::vector<Types::Coordinate> pureDeformation( 3 * this->NumberOfControlPoints );
00862
00863 size_t param = 0;
00864 for ( int k = 0; k < this->m_Dims[2]; ++k )
00865 {
00866 for ( int j = 0; j < this->m_Dims[1]; ++j )
00867 {
00868 for ( int i = 0; i < this->m_Dims[0]; ++i, param+=3 )
00869 {
00870 Self::SpaceVectorType cp( this->m_Parameters+param );
00871 this->m_InitialAffineXform->GetInverse()->ApplyInPlace( cp );
00872
00873 Self::SpaceVectorType cp0;
00874 this->GetOriginalControlPointPosition( cp0, i, j, k );
00875
00876 cp -= cp0;
00877 for ( int dim = 0; dim < 3; ++dim )
00878 pureDeformation[param+dim] = cp[dim];
00879 }
00880 }
00881 }
00882
00883
00884 std::vector<Types::Coordinate> smoothed( this->NumberOfControlPoints );
00885 for ( int dim = 0; dim < 3; ++dim )
00886 {
00887
00888 size_t cp = 0;
00889 for ( int k = 0; k < this->m_Dims[2]; ++k )
00890 {
00891 for ( int j = 0; j < this->m_Dims[1]; ++j )
00892 {
00893 for ( int i = 0; i < this->m_Dims[0]; ++i, ++cp )
00894 {
00895 if ( cpList[cp] )
00896 {
00897
00898 Types::Coordinate weight = 0;
00899 FixedVector<3,Types::Coordinate> delta;
00900 for ( int kk = std::max( 0, k-3 ); kk < std::min( k+4, this->m_Dims[2] ); ++kk )
00901 {
00902 delta[2] = k-kk;
00903 for ( int jj = std::max( 0, j-3 ); jj < std::min( j+4, this->m_Dims[1] ); ++jj )
00904 {
00905 delta[1] = j-jj;
00906 for ( int ii = std::max( 0, i-3 ); ii < std::min( i+4, this->m_Dims[0] ); ++ii )
00907 {
00908 delta[0] = i-ii;
00909
00910 const Types::Coordinate w = exp( -delta.SumOfSquares() );
00911 smoothed[cp] = w * pureDeformation[ dim + ii*this->nextI + jj*this->nextJ + kk*this->nextK ];
00912 weight += w;
00913 }
00914 }
00915 }
00916 if ( weight > 0 )
00917 smoothed[cp] /= weight;
00918 }
00919 else
00920 {
00921
00922 smoothed[cp] = pureDeformation[dim+cp*3];
00923 }
00924 }
00925 }
00926 }
00927
00928
00929 for ( size_t cp = 0; cp < this->NumberOfControlPoints; ++cp )
00930 {
00931 pureDeformation[dim+cp*3] = smoothed[cp];
00932 }
00933 }
00934
00935
00936 param = 0;
00937 for ( int k = 0; k < this->m_Dims[2]; ++k )
00938 {
00939 for ( int j = 0; j < this->m_Dims[1]; ++j )
00940 {
00941 for ( int i = 0; i < this->m_Dims[0]; ++i, param+=3 )
00942 {
00943 Self::SpaceVectorType cp0;
00944 this->GetOriginalControlPointPosition( cp0, i, j, k );
00945
00946 Self::SpaceVectorType cp( &(pureDeformation[0])+param );
00947 cp += cp0;
00948
00949 this->m_InitialAffineXform->ApplyInPlace( cp );
00950
00951 for ( int dim = 0; dim < 3; ++dim )
00952 this->m_Parameters[param+dim] = cp[dim];
00953 }
00954 }
00955 }
00956 }
00957 }
00958 }
00959
00960 }