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 "cmtkVolumeInjectionReconstruction.h"
00034
00035 #include <Base/cmtkHistogramBase.h>
00036 #include <Base/cmtkTypedArrayNoiseEstimatorNaiveGaussian.h>
00037 #include <IO/cmtkVolumeIO.h>
00038 #include <System/cmtkProgress.h>
00039
00040 #include <algorithm>
00041
00042 namespace
00043 cmtk
00044 {
00045
00048
00049 VolumeInjectionReconstruction
00050 ::VolumeInjectionReconstruction( const UniformVolume* originalImage, const int interleaveFactor, const int interleaveAxis )
00051 : m_NumberOfPasses( interleaveFactor ),
00052 m_PassWeights( interleaveFactor ),
00053 m_OriginalImageHistogram(),
00054 m_CorrectedImageHistogram()
00055 {
00056 this->m_OriginalImageHistogram = Histogram<double>::SmartPtr( new Histogram<double>( Self::NumberOfHistogramBins ) );
00057 this->m_CorrectedImageHistogram = Histogram<double>::SmartPtr( new Histogram<double>( Self::NumberOfHistogramBins ) );
00058
00059 const TypedArray* originalData = originalImage->GetData();
00060 this->SetupHistogramKernels( originalData );
00061
00062 this->m_CorrectedImage = UniformVolume::SmartPtr( originalImage->CloneGrid() );
00063 this->m_CorrectedImage->CreateDataArray( TYPE_FLOAT );
00064
00065
00066 this->m_OriginalPassImages.clear();
00067 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00068 {
00069 UniformVolume::SmartPtr passImage( originalImage->GetInterleavedSubVolume( interleaveAxis, this->m_NumberOfPasses, pass ) );
00070 this->m_OriginalPassImages.push_back( passImage );
00071 }
00072
00073 std::fill( m_PassWeights.begin(), m_PassWeights.end(), 1.0 );
00074
00075 this->m_TransformationsToPassImages.clear();
00076 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00077 {
00078 this->m_TransformationsToPassImages.push_back( AffineXform::SmartPtr( new AffineXform ) );
00079 }
00080 }
00081
00082 VolumeInjectionReconstruction
00083 ::VolumeInjectionReconstruction( const UniformVolume* reconstructionGrid, std::vector<UniformVolume::SmartPtr>& images )
00084 : m_NumberOfPasses( images.size() ),
00085 m_PassWeights( images.size() ),
00086 m_OriginalImageHistogram( new Histogram<double>( Self::NumberOfHistogramBins ) ),
00087 m_CorrectedImageHistogram( new Histogram<double>( Self::NumberOfHistogramBins ) )
00088 {
00089 const TypedArray* originalData = reconstructionGrid->GetData();
00090 if ( !originalData )
00091 originalData = images[0]->GetData();
00092 this->SetupHistogramKernels( originalData );
00093
00094 this->m_CorrectedImage = UniformVolume::SmartPtr( reconstructionGrid->CloneGrid() );
00095 this->m_CorrectedImage->CreateDataArray( TYPE_FLOAT );
00096
00097 this->m_OriginalPassImages = images;
00098 std::fill( m_PassWeights.begin(), m_PassWeights.end(), 1.0 );
00099
00100 this->m_TransformationsToPassImages.clear();
00101 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00102 {
00103 this->m_TransformationsToPassImages.push_back( AffineXform::SmartPtr( new AffineXform ) );
00104 }
00105 }
00106
00107 int
00108 VolumeInjectionReconstruction
00109 ::GuessInterleaveAxis
00110 ( const UniformVolume* image, const int defaultAxis )
00111 {
00112 if ( (image->m_Dims[0] == image->m_Dims[1]) && (image->m_Dims[1] != image->m_Dims[2]) )
00113 return 2;
00114 if ( (image->m_Dims[0] == image->m_Dims[2]) && (image->m_Dims[1] != image->m_Dims[2]) )
00115 return 1;
00116 if ( (image->m_Dims[1] == image->m_Dims[2]) && (image->m_Dims[1] != image->m_Dims[0]) )
00117 return 0;
00118
00119 if ( (image->m_Delta[0] == image->m_Delta[1]) && (image->m_Delta[1] != image->m_Delta[2]) )
00120 return 2;
00121 if ( (image->m_Delta[0] == image->m_Delta[2]) && (image->m_Delta[1] != image->m_Delta[2]) )
00122 return 1;
00123 if ( (image->m_Delta[1] == image->m_Delta[2]) && (image->m_Delta[1] != image->m_Delta[0]) )
00124 return 0;
00125
00126 return defaultAxis;
00127 }
00128
00129 void
00130 VolumeInjectionReconstruction
00131 ::SetupHistogramKernels( const TypedArray* originalData )
00132 {
00133 this->m_OriginalImageRange = originalData->GetRange();
00134 this->m_CorrectedImageHistogram->SetRange( this->m_OriginalImageRange );
00135 this->m_OriginalImageHistogram->SetRange( this->m_OriginalImageRange );
00136 originalData->GetEntropy( *this->m_OriginalImageHistogram, true );
00137
00138 const HistogramType::BinType noiseSigma = TypedArrayNoiseEstimatorNaiveGaussian( originalData, Self::NumberOfHistogramBins ).GetNoiseLevelSigma();
00139 const HistogramType::BinType kernelSigma = Self::NumberOfHistogramBins * noiseSigma / this->m_OriginalImageRange.Width();
00140 size_t kernelRadius = static_cast<size_t>( 1 + 2 * kernelSigma );
00141
00142
00143
00144 size_t runLengthZeroes = 1;
00145 for ( size_t i = 0; i < Self::NumberOfHistogramBins; ++i )
00146 {
00147 if ( (*this->m_OriginalImageHistogram)[i] == 0 )
00148 {
00149 ++runLengthZeroes;
00150 kernelRadius = std::max( kernelRadius, runLengthZeroes );
00151 }
00152 else
00153 {
00154 runLengthZeroes = 0;
00155 }
00156 }
00157
00158
00159 this->m_OriginalImageIntensityNoiseKernel.resize( kernelRadius );
00160 if ( kernelRadius > 1 )
00161 {
00162 const HistogramType::BinType normFactor = 1.0/(sqrt(2*M_PI) * kernelSigma);
00163 for ( size_t i = 0; i < kernelRadius; ++i )
00164 {
00165 this->m_OriginalImageIntensityNoiseKernel[i] = static_cast<HistogramType::BinType>( normFactor * exp( -MathUtil::Square( 1.0 * i / kernelSigma ) / 2 ) );
00166 }
00167 }
00168 else
00169 {
00170 this->m_OriginalImageIntensityNoiseKernel[0] = static_cast<HistogramType::BinType>( 1 );
00171 }
00172
00173
00174 originalData->GetEntropy( *this->m_OriginalImageHistogram, &this->m_OriginalImageIntensityNoiseKernel[0], this->m_OriginalImageIntensityNoiseKernel.size() );
00175 }
00176
00177 void
00178 VolumeInjectionReconstruction
00179 ::ComputeTransformationsToPassImages( const int registrationMetric )
00180 {
00181 this->m_TransformationsToPassImages.clear();
00182
00183 UniformVolume::SmartPtr registerToImage = this->m_ReferenceImage ? this->m_ReferenceImage : this->m_OriginalPassImages[0];
00184 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00185 {
00186 if ( registerToImage == this->m_OriginalPassImages[pass] )
00187 {
00188
00189 this->m_TransformationsToPassImages.push_back( AffineXform::SmartPtr( new AffineXform ) );
00190 }
00191 else
00192 {
00193
00194 AffineRegistration ar;
00195 ar.SetVolume_1( registerToImage );
00196 ar.SetVolume_2( this->m_OriginalPassImages[pass] );
00197
00198 ar.AddNumberDOFs( 6 );
00199
00200 ar.SetInitialAlignCenters( false );
00201 ar.SetNoSwitch( true );
00202
00203 ar.SetMetric( registrationMetric );
00204 ar.SetExploration( 4 * this->m_CorrectedImage->GetMaxDelta() );
00205 ar.SetAccuracy( .1 * this->m_CorrectedImage->GetMinDelta() );
00206 ar.SetSampling( 2 * this->m_CorrectedImage->GetMaxDelta() );
00207
00208 ar.Register();
00209
00210 this->m_TransformationsToPassImages.push_back( ar.GetTransformation() );
00211 }
00212 }
00213 }
00214
00215 void
00216 VolumeInjectionReconstruction
00217 ::VolumeInjectionAnisotropic( const Types::Coordinate kernelSigmaFactor, const Types::Coordinate kernelRadiusFactor )
00218 {
00219 const Types::Coordinate minusOneOverTwoSigmaSquare = -1 / (2 * kernelSigmaFactor*kernelSigmaFactor);
00220
00221 UniformVolume::SmartPtr& correctedImage = this->m_CorrectedImage;
00222 TypedArray::SmartPtr correctedImageData = correctedImage->GetData();
00223 const size_t correctedImageNumPixels = correctedImage->GetNumberOfPixels();
00224 const Types::Coordinate correctedDelta[3] = { correctedImage->m_Delta[0], correctedImage->m_Delta[1], correctedImage->m_Delta[2] };
00225
00226 this->m_NeighorhoodMaxPixelValues.setbounds( 1, correctedImageNumPixels );
00227 this->m_NeighorhoodMinPixelValues.setbounds( 1, correctedImageNumPixels );
00228 for ( size_t i = 1; i <= correctedImageNumPixels; ++i )
00229 {
00230 this->m_NeighorhoodMaxPixelValues(i) = this->m_OriginalImageRange.m_LowerBound;
00231 this->m_NeighorhoodMinPixelValues(i) = this->m_OriginalImageRange.m_UpperBound;
00232 }
00233
00234 Progress::Begin( 0, correctedImageNumPixels, 1e5, "Anisotropic Volume Injection" );
00235
00236 #pragma omp parallel for schedule(dynamic)
00237 for ( size_t correctedPx = 0; correctedPx < correctedImageNumPixels; ++correctedPx )
00238 {
00239 if ( (correctedPx % ((size_t)1e5)) == 0 )
00240 Progress::SetProgress( correctedPx );
00241
00242 ap::real_value_type sum = 0;
00243 ap::real_value_type weight = 0;
00244
00245 const UniformVolume::CoordinateVectorType vCorrected = correctedImage->GetGridLocation( correctedPx );
00246
00247 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00248 {
00249 const ap::real_value_type passImageWeight = this->m_PassWeights[pass];
00250
00251 if ( passImageWeight > 0 )
00252 {
00253 const UniformVolume* passImage = this->m_OriginalPassImages[pass];
00254 const DataGrid::IndexType& passImageDims = passImage->GetDims();
00255 const Xform* passImageXform = this->m_TransformationsToPassImages[pass];
00256
00257 const UniformVolume::CoordinateVectorType vPass = passImageXform->Apply( vCorrected );
00258
00259 int passGridPosition[3];
00260 passImage->GetVoxelIndexNoBounds( vPass, passGridPosition );
00261
00262 int passGridFrom[3], passGridTo[3];
00263 for ( int n = 0; n < 3; ++n )
00264 {
00265 passGridFrom[n] = std::max( passGridPosition[n] - static_cast<int>( kernelRadiusFactor ), 0 );
00266 passGridTo[n] = std::min( passGridPosition[n] + static_cast<int>( kernelRadiusFactor ) + 1, passImageDims[n] );
00267 }
00268
00269 UniformVolume::CoordinateVectorType u, delta;
00270 for ( int k = passGridFrom[2]; k < passGridTo[2]; ++k )
00271 {
00272 u[2] = passImage->GetPlaneCoord( AXIS_Z, k );
00273 delta[2] = (u[2] - vPass[2]) / correctedDelta[2];
00274
00275 for ( int j = passGridFrom[1]; j < passGridTo[1]; ++j )
00276 {
00277 u[1] = passImage->GetPlaneCoord( AXIS_Y, j );
00278 delta[1] = (u[1] - vPass[1]) / correctedDelta[1];
00279
00280 for ( int i = passGridFrom[0]; i < passGridTo[0]; ++i )
00281 {
00282 u[0] = passImage->GetPlaneCoord( AXIS_X, i );
00283 delta[0] = (u[0] - vPass[0]) / correctedDelta[0];
00284
00285 Types::DataItem passImageData;
00286 if ( passImage->GetDataAt( passImageData, i, j, k ) )
00287 {
00288 const Types::Coordinate mahalanobis = delta.RootSumOfSquares();
00289 if ( mahalanobis <= kernelRadiusFactor )
00290 {
00291 const ap::real_value_type kernelWeightPixel = passImageWeight * exp( mahalanobis*mahalanobis * minusOneOverTwoSigmaSquare );
00292
00293 sum += passImageData * kernelWeightPixel;
00294 weight += kernelWeightPixel;
00295
00296 if ( passImageData < this->m_NeighorhoodMinPixelValues(correctedPx+1) )
00297 this->m_NeighorhoodMinPixelValues(correctedPx+1) = passImageData;
00298 if ( passImageData > this->m_NeighorhoodMaxPixelValues(correctedPx+1) )
00299 this->m_NeighorhoodMaxPixelValues(correctedPx+1) = passImageData;
00300 }
00301 }
00302 }
00303 }
00304 }
00305 }
00306 }
00307 if ( weight > 0 )
00308 correctedImageData->Set( static_cast<Types::DataItem>( sum / weight ), correctedPx );
00309 else
00310 correctedImageData->SetPaddingAt( correctedPx );
00311 }
00312
00313 Progress::Done();
00314 }
00315
00316 void
00317 VolumeInjectionReconstruction
00318 ::VolumeInjectionIsotropic( const Types::Coordinate kernelSigma, const Types::Coordinate kernelRadius )
00319 {
00320 const size_t correctedImageNumPixels = this->m_CorrectedImage->GetNumberOfPixels();
00321 const DataGrid::IndexType& splattedImageDims = this->m_CorrectedImage->GetDims();
00322
00323 this->m_CorrectedImage->GetData()->ClearArray();
00324
00325 this->m_NeighorhoodMaxPixelValues.setbounds( 1, correctedImageNumPixels );
00326 this->m_NeighorhoodMinPixelValues.setbounds( 1, correctedImageNumPixels );
00327 for ( size_t i = 1; i <= correctedImageNumPixels; ++i )
00328 {
00329 this->m_NeighorhoodMaxPixelValues(i) = this->m_OriginalImageRange.m_LowerBound;
00330 this->m_NeighorhoodMinPixelValues(i) = this->m_OriginalImageRange.m_UpperBound;
00331 }
00332
00333 const int kernelRadiusIndex[3] =
00334 {
00335 1 + static_cast<int>( kernelRadius / this->m_CorrectedImage->m_Delta[0] ),
00336 1 + static_cast<int>( kernelRadius / this->m_CorrectedImage->m_Delta[1] ),
00337 1 + static_cast<int>( kernelRadius / this->m_CorrectedImage->m_Delta[2] )
00338 };
00339
00340 const Types::Coordinate kernelRadiusSquare = kernelRadius * kernelRadius;
00341 const Types::Coordinate minusOneOverTwoSigmaSquare = -1 / (2 * kernelSigma*kernelSigma);
00342
00343 std::vector<ap::real_value_type> kernelWeights( correctedImageNumPixels );
00344 std::fill( kernelWeights.begin(), kernelWeights.end(), 0 );
00345
00346 std::vector<ap::real_value_type> splattedImage( correctedImageNumPixels );
00347 std::fill( splattedImage.begin(), splattedImage.end(), 0 );
00348
00349 Progress::Begin( 0, this->m_NumberOfPasses, 1, "Isotropic Volume Injection" );
00350
00351 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00352 {
00353 Progress::SetProgress( pass );
00354
00355 const ap::real_value_type passImageWeight = this->m_PassWeights[pass];
00356
00357 if ( passImageWeight > 0 )
00358 {
00359 const UniformVolume* passImage = this->m_OriginalPassImages[pass];
00360 AffineXform::SmartPtr affinePassImageXform = AffineXform::SmartPtr::DynamicCastFrom( this->m_TransformationsToPassImages[pass] );
00361 const AffineXform* passImageXformInverse = (affinePassImageXform) ? affinePassImageXform->GetInverse() : static_cast<const AffineXform*>( NULL );
00362
00363 const int passImageNumPixels = passImage->GetNumberOfPixels();
00364 for ( int offset = 0; offset < passImageNumPixels; ++offset )
00365 {
00366 Types::DataItem passImageData;
00367 if ( passImage->GetDataAt( passImageData, offset ) )
00368 {
00369 int x, y, z;
00370 passImage->GetIndexFromOffset( offset, x, y, z );
00371
00372 UniformVolume::CoordinateVectorType v = passImage->GetGridLocation( x, y, z );
00373 if ( passImageXformInverse )
00374 {
00375 passImageXformInverse->ApplyInPlace( v );
00376 }
00377 else
00378 {
00379 this->m_TransformationsToPassImages[pass]->ApplyInverseInPlace( v );
00380 }
00381
00382 int targetGridPosition[3];
00383 if ( this->m_CorrectedImage->FindVoxel( v, targetGridPosition ) )
00384 {
00385
00386 int targetGridFrom[3], targetGridTo[3];
00387 for ( int n = 0; n < 3; ++n )
00388 {
00389 targetGridFrom[n] = std::max( targetGridPosition[n] - kernelRadiusIndex[n], 0 );
00390 targetGridTo[n] = std::min( targetGridPosition[n] + kernelRadiusIndex[n] + 1, splattedImageDims[n] );
00391 }
00392
00393 UniformVolume::CoordinateVectorType u;
00394 for ( int k = targetGridFrom[2]; k < targetGridTo[2]; ++k )
00395 {
00396 u[2] = this->m_CorrectedImage->GetPlaneCoord( AXIS_Z, k );
00397
00398 for ( int j = targetGridFrom[1]; j < targetGridTo[1]; ++j )
00399 {
00400 u[1] = this->m_CorrectedImage->GetPlaneCoord( AXIS_Y, j );
00401
00402 size_t splattedImageOffset = this->m_CorrectedImage->GetOffsetFromIndex( targetGridFrom[0], j, k );
00403 for ( int i = targetGridFrom[0]; i < targetGridTo[0]; ++i, ++splattedImageOffset )
00404 {
00405 u[0] = this->m_CorrectedImage->GetPlaneCoord( AXIS_X, i );
00406
00407 const Types::Coordinate distanceSquare = ( u-v ).SumOfSquares();
00408 if ( distanceSquare <= kernelRadiusSquare )
00409 {
00410 const ap::real_value_type kernelWeightPixel = passImageWeight * exp( distanceSquare * minusOneOverTwoSigmaSquare );
00411
00412 splattedImage[splattedImageOffset] += passImageData * kernelWeightPixel;
00413 kernelWeights[splattedImageOffset] += kernelWeightPixel;
00414
00415 if ( passImageData < this->m_NeighorhoodMinPixelValues(splattedImageOffset+1) )
00416 this->m_NeighorhoodMinPixelValues(splattedImageOffset+1) = passImageData;
00417 if ( passImageData > this->m_NeighorhoodMaxPixelValues(splattedImageOffset+1) )
00418 this->m_NeighorhoodMaxPixelValues(splattedImageOffset+1) = passImageData;
00419 }
00420 }
00421 }
00422 }
00423 }
00424 }
00425 }
00426 }
00427 }
00428
00429 #pragma omp parallel for
00430 for ( size_t idx = 0; idx < correctedImageNumPixels; ++idx )
00431 {
00432 const Types::DataItem kernelWeightPixel = static_cast<Types::DataItem>( kernelWeights[idx] );
00433 if ( kernelWeightPixel > 0 )
00434 {
00435 this->m_CorrectedImage->SetDataAt( static_cast<Types::DataItem>( splattedImage[idx] / kernelWeightPixel ), idx );
00436 }
00437 }
00438
00439 Progress::Done();
00440 }
00441
00442 UniformVolume::SmartPtr&
00443 VolumeInjectionReconstruction
00444 ::GetCorrectedImage()
00445 {
00446 return this->m_CorrectedImage;
00447 }
00448
00449 void
00450 VolumeInjectionReconstruction
00451 ::SetReferenceImage( UniformVolume::SmartPtr& referenceImage )
00452 {
00453 this->m_ReferenceImage = referenceImage;
00454 }
00455
00456 ap::real_value_type
00457 VolumeInjectionReconstruction
00458 ::GetOriginalToCorrectedImageKLD( const ap::real_1d_array& x )
00459 {
00460 this->m_CorrectedImageHistogram->Reset();
00461 for ( int i = x.getlowbound(); i <= x.gethighbound(); ++i )
00462 this->m_CorrectedImageHistogram->AddWeightedSymmetricKernel
00463 ( this->m_CorrectedImageHistogram->ValueToBin( static_cast<Types::DataItem>( x(i) ) ), this->m_OriginalImageIntensityNoiseKernel.size(), &this->m_OriginalImageIntensityNoiseKernel[0] );
00464 const ap::real_value_type kld = this->m_CorrectedImageHistogram->GetKullbackLeiblerDivergence( *this->m_OriginalImageHistogram );
00465
00466 return kld;
00467 }
00468
00469 ap::real_value_type
00470 VolumeInjectionReconstruction
00471 ::ComputeCorrectedImageLaplacianNorm( const ap::real_1d_array& correctedImagePixels )
00472 {
00473 const UniformVolume* correctedImage = this->m_CorrectedImage;
00474 const size_t correctedImageNumPixels = correctedImage->GetNumberOfPixels();
00475 this->m_CorrectedImageLaplacians.resize( correctedImageNumPixels );
00476
00477 const DataGrid::IndexType& correctedImageDims = correctedImage->GetDims();
00478 const int nextI = 1;
00479 const int nextJ = nextI * correctedImageDims[0];
00480 const int nextK = nextJ * correctedImageDims[1];
00481
00482 ap::real_value_type lnorm = 0;
00483 #pragma omp parallel for reduction(+:lnorm)
00484 for ( size_t idx = 1; idx <= correctedImageNumPixels; ++idx )
00485 {
00486 int x, y, z;
00487 correctedImage->GetIndexFromOffset( idx-1, x, y, z );
00488
00489 const int xm = (x>0) ? idx-nextI : idx+nextI;
00490 const int ym = (y>0) ? idx-nextJ : idx+nextJ;
00491 const int zm = (z>0) ? idx-nextK : idx+nextK;
00492
00493 const int xp = (x+1 < correctedImageDims[0]) ? idx+nextI : idx-nextI;
00494 const int yp = (y+1 < correctedImageDims[1]) ? idx+nextJ : idx-nextJ;
00495 const int zp = (z+1 < correctedImageDims[2]) ? idx+nextK : idx-nextK;
00496
00497 const ap::real_value_type l =
00498 correctedImagePixels( xm ) + correctedImagePixels( xp ) +
00499 correctedImagePixels( ym ) + correctedImagePixels( yp ) +
00500 correctedImagePixels( zm ) + correctedImagePixels( zp ) -
00501 6 * correctedImagePixels( idx );
00502
00503 this->m_CorrectedImageLaplacians[idx-1] = l;
00504 lnorm += l*l;
00505 }
00506 return lnorm / correctedImageNumPixels;
00507 }
00508
00509 void
00510 VolumeInjectionReconstruction
00511 ::AddLaplacianGradientImage( ap::real_1d_array& g, const ap::real_1d_array&, const ap::real_value_type weight ) const
00512 {
00513 const UniformVolume* correctedImage = this->m_CorrectedImage;
00514 const size_t correctedImageNumPixels = correctedImage->GetNumberOfPixels();
00515 const DataGrid::IndexType& correctedImageDims = correctedImage->GetDims();
00516
00517 const int nextI = 1;
00518 const int nextJ = nextI * correctedImageDims[0];
00519 const int nextK = nextJ * correctedImageDims[1];
00520
00521 #pragma omp parallel for
00522 for ( size_t idx = 0; idx < correctedImageNumPixels; ++idx )
00523 {
00524 int x, y, z;
00525 correctedImage->GetIndexFromOffset( idx, x, y, z );
00526
00527 const int xm = (x>0) ? idx-nextI : idx+nextI;
00528 const int ym = (y>0) ? idx-nextJ : idx+nextJ;
00529 const int zm = (z>0) ? idx-nextK : idx+nextK;
00530
00531 const int xp = (x+1 < correctedImageDims[0]) ? idx+nextI : idx-nextI;
00532 const int yp = (y+1 < correctedImageDims[1]) ? idx+nextJ : idx-nextJ;
00533 const int zp = (z+1 < correctedImageDims[2]) ? idx+nextK : idx-nextK;
00534
00535 g(idx+1) += (2 * weight / correctedImageNumPixels) *
00536 ( this->m_CorrectedImageLaplacians[xm] + this->m_CorrectedImageLaplacians[xp] +
00537 this->m_CorrectedImageLaplacians[ym] + this->m_CorrectedImageLaplacians[yp] +
00538 this->m_CorrectedImageLaplacians[zm] + this->m_CorrectedImageLaplacians[zp] -
00539 6 * this->m_CorrectedImageLaplacians[idx] );
00540 }
00541 }
00542
00543 }