cmtkDeblurringVolumeReconstruction.txx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2011 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2731 $
00026 //
00027 //  $LastChangedDate: 2011-01-13 16:22:47 -0800 (Thu, 13 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include <algorithm>
00034 
00035 #include <Base/cmtkHistogramBase.h>
00036 
00037 template<class TPSF>
00038 void
00039 DeblurringVolumeReconstruction<TPSF>
00040 ::Blur( const ap::real_1d_array& reconstructedPixelArray )
00041 {
00042   this->m_InterpolatedPassImages.clear();
00043   
00044   const UniformVolume* correctedImage = this->m_CorrectedImage;
00045   const DataGrid::IndexType& correctedImageDims = correctedImage->GetDims();
00046 
00047   for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00048     {
00049     const UniformVolume* passImage = this->m_OriginalPassImages[pass];
00050     UniformVolume::SmartPtr result( passImage->CloneGrid() );
00051     result->CreateDataArray( TYPE_FLOAT, true/*setToZero*/ );
00052     
00053     const DataGrid::IndexType& passImageDims = passImage->GetDims();
00054     const int passImageDimsX = passImageDims[0], passImageDimsY = passImageDims[1], passImageDimsZ = passImageDims[2];
00055     const size_t passImageDimsXY = passImageDimsX*passImageDimsY;
00056     const size_t passImageDimsXYZ = passImageDimsXY*passImageDimsZ;
00057 
00058     const TPSF* passImagePSF = this->m_PassImagePSF[pass];
00059     const AffineXform* correctedToPassXform = AffineXform::SmartPtr::DynamicCastFrom( this->m_TransformationsToPassImages[pass] );
00060     const AffineXform* passToCorrectedXform = AffineXform::SmartPtr::DynamicCastFrom( this->m_TransformationsToPassImages[pass] )->GetInverse();
00061 
00062 #pragma omp parallel for
00063     for ( size_t offset = 0; offset < passImageDimsXYZ; ++offset )
00064       {
00065       const int curPassVox[3] = { (offset % passImageDimsXY) % passImageDimsX, (offset % passImageDimsXY) / passImageDimsX, (offset / passImageDimsXY) };
00066       
00067       Types::DataItem blurredData = 0;
00068       Types::DataItem totalWeight = 0;
00069       
00070       /* Get a bounding box for the transformed neighborhood (pass- to corrected-image)
00071            */
00072       const UniformVolume::CoordinateVectorType curPassVec3D = passImage->GetGridLocation( curPassVox[0], curPassVox[1], curPassVox[2] );
00073       int corrBoundingBox[6];
00074       this->GetBoundingBoxOfXformedPassNeighborhood( corrBoundingBox, correctedImage, curPassVec3D, passImagePSF, passToCorrectedXform, correctedImageDims );
00075       
00076       /* Iterate through the bounding box of the blur-weights matrix,
00077            * assembling the weighted sum of the neighbors, and the sum of weights
00078            */
00079       Types::DataItem data;
00080       for (int k = corrBoundingBox[2]; k <= corrBoundingBox[5]; ++k)
00081         {
00082         for (int j = corrBoundingBox[1]; j <= corrBoundingBox[4]; ++j)
00083           {
00084           for (int i = corrBoundingBox[0]; i <= corrBoundingBox[3]; ++i)
00085             {
00086             UniformVolume::CoordinateVectorType curNeighbVec3D;
00087             Types::Coordinate from[3], to[3];
00088             curNeighbVec3D = correctedImage->GetGridLocation( i, j, k );
00089             correctedToPassXform->ApplyInPlace( curNeighbVec3D );
00090             
00091             int neighborPassVox[3];
00092             if ( passImage->FindVoxel( curNeighbVec3D, neighborPassVox, from, to ) )
00093               {
00094               Types::Coordinate weightIJK = 1;
00095               for ( int dim = 0; dim < 3; ++dim )
00096                 {
00097                 const Types::Coordinate displacement = curNeighbVec3D[dim] - curPassVec3D[dim];
00098                 weightIJK *= passImagePSF->GetWeight( dim, displacement );
00099                 }
00100               
00101               totalWeight += weightIJK;
00102               data = reconstructedPixelArray( 1+correctedImage->GetOffsetFromIndex( i, j, k ) );                 
00103               blurredData += data * weightIJK;
00104               }
00105             }
00106           }
00107         }
00108       /* Assign the blurred value to the result
00109            */
00110       if ( totalWeight == 0 )
00111         result->GetData()->SetPaddingAt( offset );
00112       else
00113         result->SetDataAt( blurredData / totalWeight, offset );
00114       }
00115     this->m_InterpolatedPassImages.push_back( result );
00116     }
00117 }
00118 
00119 template <class TPSF>
00120 void
00121 DeblurringVolumeReconstruction<TPSF>
00122 ::ComputeErrorGradientImage( ap::real_1d_array& g )
00123 {
00124   const UniformVolume* correctedImage = this->m_CorrectedImage;
00125   const size_t numberOfPixels = correctedImage->GetNumberOfPixels();
00126   for ( size_t i = 1; i <= numberOfPixels; ++i )
00127     g(i) = 0;
00128 
00129   const DataGrid::IndexType& correctedImageDims = correctedImage->GetDims();
00130   const int correctedImageDimsX = correctedImageDims[0], correctedImageDimsY = correctedImageDims[1];
00131   const int correctedImageDimsXY = correctedImageDimsX*correctedImageDimsY;
00132 
00133   for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00134     {
00135     const Types::Coordinate passImageWeight = this->m_PassWeights[pass];      
00136     if ( passImageWeight > 0 )
00137       {
00138       const UniformVolume* differencePassImage = this->m_DifferencePassImages[pass];
00139       const UniformVolume* blurredPassImage = this->m_InterpolatedPassImages[pass];
00140       
00141       const TPSF* passImagePSF = this->m_PassImagePSF[pass];
00142       const AffineXform* transformationToPassImage = AffineXform::SmartPtr::DynamicCastFrom( this->m_TransformationsToPassImages[pass] );
00143       
00144 #pragma omp parallel for
00145       for ( size_t offset = 0; offset < numberOfPixels; ++offset )
00146         {
00147         const int corrCenterVox[3] = { (offset % correctedImageDimsXY) % correctedImageDimsX, (offset % correctedImageDimsXY) / correctedImageDimsX, (offset / correctedImageDimsXY) };
00148 
00149         UniformVolume::CoordinateVectorType curCenterVec3D = correctedImage->GetGridLocation( corrCenterVox[0], corrCenterVox[1], corrCenterVox[2] );
00150         transformationToPassImage->ApplyInPlace( curCenterVec3D );
00151 
00152         /* compute neighborhood in blurred (pass) image from which blurred pixels 
00153            * are affected by current corrected image pixel
00154            */
00155         int passRegionCorners[2][3];
00156         for ( int dim = 0; dim < 3; ++dim )
00157           {
00158           passRegionCorners[0][dim] = blurredPassImage->GetCoordIndex( dim, curCenterVec3D[dim] - passImagePSF->GetTruncationRadius( dim ) );
00159           passRegionCorners[1][dim] = blurredPassImage->GetCoordIndex( dim, curCenterVec3D[dim] + passImagePSF->GetTruncationRadius( dim ) );
00160           }
00161         
00162         /* Iterate through the neighborhood in the blurred (pass) image,
00163            * assembling a value for the gradient at this offset of the corrected
00164            * image
00165            */
00166         Types::DataItem gradientData = 0;
00167         for (int k = passRegionCorners[0][2]; k <= passRegionCorners[1][2]; ++k)
00168           {
00169           for (int j = passRegionCorners[0][1]; j <= passRegionCorners[1][1]; ++j)
00170             {
00171             for (int i = passRegionCorners[0][0]; i <= passRegionCorners[1][0]; ++i)
00172               {
00173               Types::DataItem differenceData;
00174               // if differenceData==0, we can skip this, too
00175               if ( differencePassImage->GetDataAt( differenceData, i, j, k ) && (differenceData !=0) ) 
00176                 {
00177                 Types::DataItem weight = 0;
00178                 
00179                 const UniformVolume::CoordinateVectorType passNeighbVec3D = blurredPassImage->GetGridLocation( i, j, k );
00180                 
00181                 weight = passImageWeight;
00182                 for ( int dim = 0; dim < 3; ++dim )
00183                   {
00184                   const Types::Coordinate displacement = curCenterVec3D[dim] - passNeighbVec3D[dim];
00185                   weight *= passImagePSF->GetWeight( dim, displacement );
00186                   }
00187                 
00188                 gradientData += weight * differenceData;
00189                 }
00190               }
00191             }
00192           }
00193         
00194         if ( this->m_FourthOrderError )
00195           g(offset+1) += 4 * (gradientData*gradientData*gradientData) / numberOfPixels;
00196         else
00197           g(offset+1) += 2 * gradientData / numberOfPixels;
00198         }
00199       }
00200     }
00201 }
00202 
00203 template<class TPSF>
00204 void
00205 DeblurringVolumeReconstruction<TPSF>
00206 ::GetBoundingBoxOfXformedPassNeighborhood
00207 ( int* correctedImageBoundingBox, const UniformVolume* correctedImage, const Vector3D& currentPassVoxel, const TPSF* psf,
00208   const AffineXform* passToCorrectedXform, const DataGrid::IndexType& correctedImageDims ) const
00209 {
00210   /* Compute the blurring neighborhood in the pass image 
00211    */
00212   Types::Coordinate corners[2][3];
00213   for ( int dim = 0; dim < 3; ++dim )
00214     {
00215     const Types::Coordinate radius = psf->GetTruncationRadius( dim );
00216     corners[0][dim] = currentPassVoxel[dim] - radius;
00217     corners[1][dim] = currentPassVoxel[dim] + radius;
00218     }
00219 
00220   /* Make corner vectors out of that 2-D array and put them in a 1-D array,
00221    * transforming each to the space of the corrected image.
00222    */
00223   Vector3D corners3D[8];
00224   int neighborIdx = 0;
00225   for ( int a = 0; a < 2 ; ++a )
00226     {
00227     for ( int b = 0; b < 2 ; ++b )
00228       {
00229       for ( int c = 0; c < 2; ++c, ++neighborIdx )
00230         {
00231         corners3D[neighborIdx][0] = corners[a][0];
00232         corners3D[neighborIdx][1] = corners[b][1];
00233         corners3D[neighborIdx][2] = corners[c][2];
00234         passToCorrectedXform->ApplyInPlace( corners3D[neighborIdx] );
00235         }
00236       }
00237     }
00238 
00239   /* Compute the bounding box of that transformed region 
00240    */
00241   Vector3D bboxMin = corners3D[0];
00242   Vector3D bboxMax = corners3D[0];
00243   for ( int m = 1; m < 8; ++m )
00244     {
00245     for ( int o = 0; o < 3; ++o )
00246       {
00247       if ( corners3D[m][o] < bboxMin[o] )
00248         {
00249         bboxMin[o] = corners3D[m][o];
00250         }
00251       else
00252         if ( corners3D[m][o] > bboxMax[o] )
00253           {
00254           bboxMax[o] = corners3D[m][o];
00255           }
00256       }
00257     }
00258 
00259   /* Put the voxel indices corresponding to the corners of that bounding box 
00260    * into correctedImageBoundingBox
00261    */
00262   correctedImage->GetVoxelIndexNoBounds( bboxMin, correctedImageBoundingBox+0 );
00263   correctedImage->GetVoxelIndexNoBounds( bboxMax, correctedImageBoundingBox+3 );
00264 
00265   /* Clip bounding box (now correctedImageBoundingBox) against corrected image boundaries 
00266    */
00267   for ( int dim = 0; dim < 3; ++dim )
00268     {
00269     correctedImageBoundingBox[dim] = std::max( correctedImageBoundingBox[dim], 0 );
00270     // increment upper indexes by one to compensate for floating point truncation in pixel index lookup.
00271     correctedImageBoundingBox[dim+3] = std::min( correctedImageBoundingBox[dim+3]+1, correctedImageDims[dim]-1 );
00272     }
00273 }
00274 
00275 template<class TPSF>
00276 void
00277 DeblurringVolumeReconstruction<TPSF>
00278 ::FunctionAndGradient
00279 ::Evaluate( const ap::real_1d_array& x, ap::real_value_type& f, ap::real_1d_array& g )
00280 {
00281   this->m_Function->Blur( x );
00282   this->m_Function->ComputeApproximationError();
00283   this->m_Function->ComputeErrorGradientImage( g );
00284   
00285   const ap::real_value_type msd = f = this->m_Function->GetMeanSquaredError();
00286 
00287   ap::real_value_type lnorm = 0;
00288   if ( this->m_Function->m_ConstraintWeightLNorm > 0 )
00289     {
00290     f += this->m_Function->m_ConstraintWeightLNorm * (lnorm = this->m_Function->ComputeCorrectedImageLaplacianNorm( x ));
00291     this->m_Function->AddLaplacianGradientImage( g, x, this->m_Function->m_ConstraintWeightLNorm );
00292     }
00293 
00294   if ( this->m_Function->GetMaximumError() <= this->m_Function->m_LowestMaxError )
00295     {
00296     this->m_Function->m_LowestMaxError = this->m_Function->GetMaximumError();
00297     const int numberOfPixels = this->m_Function->m_CorrectedImage->GetNumberOfPixels();
00298     for ( int i = 1; i <= numberOfPixels; ++i )
00299       this->m_Function->m_CorrectedImage->SetDataAt( x(i), i-1 );
00300     this->m_Function->m_LowestMaxErrorImage = UniformVolume::SmartPtr( this->m_Function->m_CorrectedImage->Clone( true /*copyData*/ ) );
00301     }
00302   
00303   std::cerr << "f " << f << " MSD " << msd
00304             << " MAX " << this->m_Function->GetMaximumError() 
00305             << " KLD " << this->m_Function->GetOriginalToCorrectedImageKLD( x )
00306             << " LNORM " << lnorm << std::endl;
00307 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines