cmtkScalarImageSimilarity.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 2004-2010 SRI International
00004 /
00005 //  Copyright 1997-2009 Torsten Rohlfing
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: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkScalarImageSimilarity.h"
00034 
00035 #include <Base/cmtkHistogram.h>
00036 
00037 #include <vector>
00038 
00039 namespace
00040 cmtk
00041 {
00042 
00045 
00046 ScalarImageSimilarity::ReturnType 
00047 ScalarImageSimilarity::GetMutualInformation
00048 ( const ScalarImage* image0, const ScalarImage* image1,
00049   ScalarImageSimilarityMemory *const memory )
00050 {
00051   if ( ! CheckImageDimensions( image0, image1 ) ) 
00052     return MathUtil::GetFloatNaN();
00053 
00054   const TypedArray *data0 = image0->GetPixelData();
00055   const TypedArray *data1 = image1->GetPixelData();
00056 
00057   return TypedArraySimilarity::GetMutualInformation( data0, data1, memory );
00058 }
00059 
00060 ScalarImageSimilarity::ReturnType 
00061 ScalarImageSimilarity::GetNormalizedMutualInformation
00062 ( const ScalarImage* image0, const ScalarImage* image1, ScalarImageSimilarityMemory *const )
00063 {
00064   if ( ! CheckImageDimensions( image0, image1 ) ) 
00065     return MathUtil::GetFloatNaN();
00066 
00067   const TypedArray *data0 = image0->GetPixelData();
00068   const TypedArray *data1 = image1->GetPixelData();
00069 
00070   return TypedArraySimilarity::GetNormalizedMutualInformation( data0, data1 );
00071 }
00072 
00073 ScalarImageSimilarity::ReturnType 
00074 ScalarImageSimilarity::GetMinusMeanSquaredDifference
00075 ( const ScalarImage* image0, const ScalarImage* image1 )
00076 {
00077   if ( ! CheckImageDimensions( image0, image1 ) ) 
00078     return MathUtil::GetFloatNaN();
00079 
00080   const TypedArray *data0 = image0->GetPixelData();
00081   const TypedArray *data1 = image1->GetPixelData();
00082 
00083   return TypedArraySimilarity::GetMinusMeanSquaredDifference( data0, data1 );
00084 }
00085 
00086 ScalarImageSimilarity::ReturnType 
00087 ScalarImageSimilarity::GetCrossCorrelation
00088 ( const ScalarImage* image0, const ScalarImage* image1 )
00089 {
00090   if ( ! CheckImageDimensions( image0, image1 ) ) 
00091     return MathUtil::GetFloatNaN();
00092 
00093   const TypedArray *data0 = image0->GetPixelData();
00094   const TypedArray *data1 = image1->GetPixelData();
00095 
00096   return TypedArraySimilarity::GetCrossCorrelation( data0, data1 );
00097 }
00098 
00099 ScalarImageSimilarity::ReturnType 
00100 ScalarImageSimilarity::GetGradientCorrelation
00101 ( const ScalarImage* image0, const ScalarImage* image1 )
00102 {
00103   if ( ! CheckImageDimensions( image0, image1 ) ) 
00104     return MathUtil::GetFloatNaN();
00105 
00106   TypedArray::SmartPtr gradientX0( image0->GetSobelFiltered( CMTK_SCALARIMAGE_HORIZONTAL ) );
00107   TypedArray::SmartPtr gradientX1( image1->GetSobelFiltered( CMTK_SCALARIMAGE_HORIZONTAL ) );
00108 
00109   TypedArray::SmartPtr gradientY0( image0->GetSobelFiltered( CMTK_SCALARIMAGE_VERTICAL ) );
00110   TypedArray::SmartPtr gradientY1( image1->GetSobelFiltered( CMTK_SCALARIMAGE_VERTICAL ) );
00111 
00112   return TypedArraySimilarity::GetCrossCorrelation( gradientX0, gradientX1 ) + TypedArraySimilarity::GetCrossCorrelation( gradientY0, gradientY1 );
00113 }
00114 
00115 ScalarImageSimilarity::ReturnType 
00116 ScalarImageSimilarity::GetGradientDifference
00117 ( const ScalarImage* image0, const ScalarImage* image1, const ScalarImageSimilarity::ReturnType Ax, const ScalarImageSimilarity::ReturnType Ay )
00118 {
00119   if ( ! CheckImageDimensions( image0, image1 ) ) 
00120     return MathUtil::GetFloatNaN();
00121 
00122   TypedArray::SmartPtr gradientX0( image0->GetSobelFiltered( CMTK_SCALARIMAGE_HORIZONTAL ) );
00123   TypedArray::SmartPtr gradientX1( image1->GetSobelFiltered( CMTK_SCALARIMAGE_HORIZONTAL ) );
00124 
00125   TypedArray::SmartPtr gradientY0( image0->GetSobelFiltered( CMTK_SCALARIMAGE_VERTICAL ) );
00126   TypedArray::SmartPtr gradientY1( image1->GetSobelFiltered( CMTK_SCALARIMAGE_VERTICAL ) );
00127 
00128   // absAx and absAy are the relative coefficients Ax and Ay multiplied with
00129   // the first gradient image's variances as described by Penney et al.
00130   Types::DataItem mean, var;
00131   gradientX0->GetStatistics( mean, var );
00132   ScalarImageSimilarity::ReturnType absAx = Ax * var;
00133   gradientY0->GetStatistics( mean, var );
00134   ScalarImageSimilarity::ReturnType absAy = Ay * var;
00135 
00136   Types::DataItem scaleFactor = 0;
00137   TypedArray::SmartPtr diffX( TypedArraySimilarity::GetDifferenceArray( gradientX0, gradientX1, scaleFactor ) );
00138   TypedArray::SmartPtr diffY( TypedArraySimilarity::GetDifferenceArray( gradientY0, gradientY1, scaleFactor ) );
00139   ScalarImageSimilarity::ReturnType resultX = 0, resultY = 0;
00140   
00141   unsigned int numberOfPixels = image0->GetNumberOfPixels();
00142   for ( unsigned int offset = 0; offset < numberOfPixels; ++offset ) 
00143     {
00144     Types::DataItem value;
00145     diffX->Get( value, offset );
00146     resultX += 1.0 / ( absAx + MathUtil::Square( value ) );
00147     diffY->Get( value, offset );
00148     resultY += 1.0 / ( absAy + MathUtil::Square( value ) );
00149     }
00150   
00151   return absAx * resultX + absAy * resultY;
00152 }
00153 
00154 ScalarImageSimilarity::ReturnType 
00155 ScalarImageSimilarity::GetPatternIntensity
00156 ( const ScalarImage* image0, const ScalarImage* image1, const ScalarImageSimilarity::ReturnType sigma, const int radius )
00157 {
00158   if ( ! CheckImageDimensions( image0, image1 ) ) 
00159     return MathUtil::GetFloatNaN();
00160 
00161   ScalarImageSimilarity::ReturnType PI = 0;
00162 
00163   const int r2 = MathUtil::Square( radius );
00164   const ScalarImageSimilarity::ReturnType sigma2 = MathUtil::Square( sigma );
00165 
00166   // precompute desired offsets
00167   static std::vector<int> rows; 
00168   static std::vector<int> cols;
00169 
00170   static int lastRadius = 0;
00171   
00172   if ( radius != lastRadius )
00173     {
00174     lastRadius = radius;
00175 
00176     rows.clear();
00177     cols.clear();
00178 
00179     for ( int jj = -radius; jj <= (int)radius; ++jj ) 
00180       {
00181       for ( int ii = -radius; ii <= (int)radius; ++ii ) 
00182         {
00183         // are we inside circle?
00184         if ( ( MathUtil::Square(ii) + MathUtil::Square(jj) ) <= r2 ) 
00185           {
00186           rows.push_back(jj);
00187           cols.push_back(ii);
00188           }
00189         }
00190       }
00191     }
00192   
00193   // compute difference image
00194   Types::DataItem scaleFactor = 0;
00195   TypedArray::SmartPtr diff( TypedArraySimilarity::GetDifferenceArray( image0->GetPixelData(), image1->GetPixelData(), scaleFactor ) );
00196   
00197   // first, loop over all pixels in the images.
00198   const int dimsX = image0->GetDims()[AXIS_X];
00199   const int dimsY = image0->GetDims()[AXIS_Y];
00200 
00201   size_t offset = 0;
00202   for ( int j = 0; j < dimsY; ++j ) 
00203     {
00204     for ( int i = 0; i < dimsX; ++i, ++offset ) 
00205       {
00206       // get difference pixel in center of VOI around current pixel
00207       Types::DataItem centerValue;
00208       if ( diff->Get( centerValue, offset ) )
00209         {
00210         
00211         // loop over all pixels in square that encloses circular VOI
00212         for ( size_t rc=0; rc<rows.size(); rc++ ) 
00213           {
00214           const int jj = rows[rc];
00215           const int ii = cols[rc];
00216           
00217           Types::DataItem VOIvalue;
00218           // this is a hack really, since we're reading 2-D indexed data from
00219           // a linear typed array. Because we generated this array as the
00220           // subtraction of two 2-D images, however, this should work fine.
00221           // doing it this way saves us the implementation of another,
00222           // image-based rather than array-based subtraction function.
00223           if ( (i+ii)>=0 && (i+ii)<dimsX && (j+jj)>=0 && (j+jj)<dimsY )
00224             {
00225             diff->Get( VOIvalue, offset + ii + dimsX * jj );
00226             
00227             // then update Pattern Intensity sum
00228             PI += 1.0 / ( sigma2 + MathUtil::Square( centerValue - VOIvalue ) );
00229             }
00230           }
00231         }
00232       }
00233     }
00234   
00235   // normalize with sigma^2 that is common for all addends.
00236   PI *= sigma2;
00237   
00238   return PI;
00239 }
00240 
00241 ScalarImageSimilarity::ReturnType 
00242 ScalarImageSimilarity::GetDifferenceImageEntropy
00243 ( const ScalarImage* image0, const ScalarImage* image1 )
00244 {
00245   Types::DataItem dummy;
00246   return GetDifferenceImageEntropy( image0, image1, dummy );
00247 }
00248 
00249 ScalarImageSimilarity::ReturnType 
00250 ScalarImageSimilarity::GetDifferenceImageEntropy
00251 ( const ScalarImage* image0, const ScalarImage* image1, Types::DataItem &scaleFactor )
00252 {
00253   if ( ! CheckImageDimensions( image0, image1 ) ) 
00254     return MathUtil::GetFloatNaN();
00255 
00256   const TypedArray *data0 = image0->GetPixelData();
00257   const TypedArray *data1 = image1->GetPixelData();
00258 
00259   return TypedArraySimilarity::GetDifferenceArrayEntropy( data0, data1, scaleFactor );
00260 }
00261 
00262 ScalarImageSimilarity::ReturnType 
00263 ScalarImageSimilarity::GetCorrelationRatio
00264 ( const ScalarImage* image0, const ScalarImage* image1 )
00265 {
00266   if ( ! CheckImageDimensions( image0, image1 ) ) 
00267     return MathUtil::GetFloatNaN();
00268   
00269   const TypedArray *data0 = image0->GetPixelData();
00270   const TypedArray *data1 = image1->GetPixelData();
00271 
00272   return TypedArraySimilarity::GetCorrelationRatio( data0, data1 );
00273 }
00274 
00275 bool 
00276 ScalarImageSimilarity::CheckImageDimensions
00277 ( const ScalarImage* image0, const ScalarImage* image1 )
00278 {
00279   if ( !image0 || !image1 ) return false;
00280 
00281   if ( !image0->GetPixelData() || !image1->GetPixelData() ) return false;
00282 
00283   return ( ( image0->GetDims()[0] == image1->GetDims()[0] ) && ( image0->GetDims()[1] == image1->GetDims()[1] ) );
00284 }
00285 
00286 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines