cmtkTypedArraySimilarity.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: 2464 $
00026 //
00027 //  $LastChangedDate: 2010-10-19 09:54:33 -0700 (Tue, 19 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torsten_at_home $
00030 //
00031 */
00032 
00033 #include "cmtkTypedArraySimilarity.h"
00034 
00035 #include <Base/cmtkHistogram.h>
00036 #include <Base/cmtkMathUtil.h>
00037 
00038 namespace
00039 cmtk
00040 {
00041 
00044 
00045 TypedArraySimilarity::ReturnType 
00046 TypedArraySimilarity::GetMutualInformation
00047 ( const TypedArray* array0, const TypedArray* array1,
00048   TypedArraySimilarityMemory *const memory )
00049 {
00050   if ( ! CheckArrayDimensions( array0, array1 ) ) 
00051     return MathUtil::GetFloatNaN();
00052 
00053   size_t dataSize = array0->GetDataSize();
00054 
00055   JointHistogram<unsigned int>::SmartPtr histogram;
00056   if ( memory ) 
00057     {
00058     histogram = JointHistogram<unsigned int>::SmartPtr( memory->CreateHistogram( array0, array1 ) );
00059     }
00060   else
00061     {
00062     size_t numBins = std::max<unsigned>( std::min<unsigned>( static_cast<unsigned>( sqrt( (float)dataSize ) ), 128 ), 8 );
00063     
00064     histogram = JointHistogram<unsigned int>::SmartPtr( new JointHistogram<unsigned int>( numBins, numBins ) );
00065     
00066     histogram->SetRangeX( array0->GetRange() );
00067     histogram->SetRangeY( array1->GetRange() );
00068     }
00069 
00070   Types::DataItem value0, value1;
00071   for ( unsigned int idx = 0; idx < dataSize; ++idx ) 
00072     {
00073     if ( array0->Get( value0, idx ) && array1->Get( value1, idx ) ) 
00074       {
00075       histogram->Increment( histogram->ValueToBinX( value0 ), histogram->ValueToBinY( value1 ) );
00076       }
00077     }
00078   
00079   return static_cast<TypedArraySimilarity::ReturnType>( histogram->GetMutualInformation( false ) );
00080 }
00081 
00082 TypedArraySimilarity::ReturnType 
00083 TypedArraySimilarity::GetCorrelationRatio
00084  ( const TypedArray* array0, const TypedArray* array1 )
00085 {
00086   // check if both images have same number of pixels.
00087   if ( ! CheckArrayDimensions( array0, array1 ) ) return MathUtil::GetFloatNaN();
00088 
00089   // determine reference image value range.
00090   const Types::DataItemRange range = array0->GetRange();
00091 
00092   // get pixel count and determine histogram size.
00093   const unsigned int dataSize = array0->GetDataSize();
00094   unsigned int numBins = std::max<unsigned>( std::min<unsigned>( static_cast<unsigned>( sqrt( (float)dataSize ) ), 128 ), 8 );
00095 
00096   // make sure number of classes doesn't exceed number of distinct values for
00097   // discrete data types.
00098   if ( (array0->GetType() != TYPE_FLOAT) && (array0->GetType() != TYPE_DOUBLE) ) 
00099     {
00100     numBins = std::min( numBins, static_cast<unsigned int>(range.Width()+1) );
00101     }
00102   
00103   // create histogram to count floating pixels in each reference class
00104   Histogram<unsigned int> histogram( numBins );
00105 
00106   // set value range for histogram to range of reference image.
00107   histogram.SetRange( range );
00108 
00109   // initialize arrays that hold the sums of all floating values and their
00110   // squares, separated by histogram classes of the reference image.
00111   double* sumJ = Memory::AllocateArray<double>( numBins );
00112   memset( sumJ, 0, numBins * sizeof( sumJ[0] ) );
00113   double* sumSquareJ = Memory::AllocateArray<double>( numBins );
00114   memset( sumSquareJ, 0, numBins * sizeof( sumSquareJ[0] ) );
00115 
00116   // sort all image intensities into data structures.
00117   Types::DataItem value0, value1;
00118   for ( unsigned int idx = 0; idx < dataSize; ++idx ) 
00119     {
00120     // for all valid voxel pairs
00121     if ( array0->Get( value0, idx ) && array1->Get( value1, idx ) ) 
00122       {
00123       // what's the reference histogram bin?
00124       unsigned int bin = histogram.ValueToBin( value0 );
00125       // count this sample
00126       histogram.Increment( bin );
00127       // add floating value to sum of values for this class
00128       sumJ[bin] += value1;
00129       // add squared floating value to sum of squared values for this class
00130       sumSquareJ[bin] += MathUtil::Square( value1 );
00131       }
00132     }
00133   
00134   double invSampleCount = 1.0 / histogram.SampleCount();
00135   // initialize variable for the weighted sum of the sigma^2 values over all
00136   // reference intensity classes.
00137   double sumSigmaSquare = 0;
00138   // run over all bins, i.e., reference classes
00139   for ( unsigned int j = 0; j < numBins; ++j ) 
00140     {
00141     // are there any values in the current class?
00142     if ( histogram[j] ) 
00143       {
00144       // compute mean floating value for this reference class
00145       double mu = sumJ[j] / histogram[j];
00146       // compute variance of floating values for this reference class
00147       double sigmaSq = ( mu*mu*histogram[j] - 2.0*mu*sumJ[j] + sumSquareJ[j] ) / histogram[j]; 
00148       // update sum over all classes with weighted sigma^2 for this class.
00149       sumSigmaSquare += (invSampleCount * histogram[j]) * sigmaSq;
00150       }
00151     }
00152   
00153   // get variance of complete floating image for normalization
00154   Types::DataItem sigmaSqJ, muJ;
00155   array1->GetStatistics( muJ, sigmaSqJ );
00156 
00157   Memory::DeleteArray( sumJ );
00158   Memory::DeleteArray( sumSquareJ );
00159 
00160   // return (supposedly) correlation ratio
00161   return 1.0 - (1.0 /  sigmaSqJ ) * sumSigmaSquare;
00162 }
00163 
00164 TypedArraySimilarity::ReturnType 
00165 TypedArraySimilarity::GetNormalizedMutualInformation
00166 ( const TypedArray* array0, const TypedArray* array1,
00167   TypedArraySimilarityMemory *const memory )
00168 {
00169   if ( ! CheckArrayDimensions( array0, array1 ) ) return MathUtil::GetFloatNaN();
00170 
00171   size_t dataSize = array0->GetDataSize();
00172 
00173   JointHistogram<unsigned int>::SmartPtr histogram;
00174   if ( memory ) 
00175     histogram = JointHistogram<unsigned int>::SmartPtr( memory->CreateHistogram( array0, array1 ) );
00176   else 
00177     {
00178     size_t numBins = std::max<unsigned>( std::min<unsigned>( static_cast<unsigned>( sqrt( (float)dataSize ) ), 128 ), 8 );
00179     
00180     histogram = JointHistogram<unsigned int>::SmartPtr( new JointHistogram<unsigned int>( numBins, numBins ) );
00181     histogram->SetRangeX( array0->GetRange() );
00182     histogram->SetRangeY( array1->GetRange() );
00183     }
00184   
00185   Types::DataItem value0, value1;
00186   for ( unsigned int idx = 0; idx < dataSize; ++idx ) 
00187     {
00188     if ( array0->Get( value0, idx ) && array1->Get( value1, idx ) ) 
00189       {
00190       histogram->Increment( histogram->ValueToBinX( value0 ), histogram->ValueToBinY( value1 ) );
00191       }
00192     }
00193   
00194   return static_cast<TypedArraySimilarity::ReturnType>( histogram->GetMutualInformation( true ) );
00195 }
00196 
00197 TypedArraySimilarity::ReturnType 
00198 TypedArraySimilarity::GetMinusMeanSquaredDifference
00199 ( const TypedArray* array0, const TypedArray* array1 )
00200 {
00201   if ( ! CheckArrayDimensions( array0, array1 ) ) return MathUtil::GetFloatNaN();
00202 
00203   unsigned int countPixels = 0;
00204   Types::DataItem pixel0, pixel1;
00205   Types::DataItem sumOfSquares = 0;
00206 
00207   unsigned int numberOfPixels = array0->GetDataSize();
00208   for ( unsigned int idx = 0; idx < numberOfPixels; ++idx ) 
00209     {
00210     if ( array0->Get( pixel0, idx ) && array1->Get( pixel1, idx ) ) 
00211       {
00212       sumOfSquares += MathUtil::Square( pixel0 - pixel1 );
00213       ++countPixels;
00214       }
00215     }
00216   
00217   if ( !countPixels )
00218     return MathUtil::GetFloatNaN();
00219   else
00220     return static_cast<TypedArraySimilarity::ReturnType>( -(sumOfSquares / (float)countPixels) );
00221 }
00222 
00223 TypedArraySimilarity::ReturnType
00224 TypedArraySimilarity::GetPeakSignalToNoiseRatio
00225 ( const TypedArray* data, const TypedArray* signal )
00226 {
00227   return -10.0 * log( -GetMinusMeanSquaredDifference( data, signal ) / signal->GetRange().Width() ) / log( 10.0 );
00228 }
00229 
00230 TypedArraySimilarity::ReturnType 
00231 TypedArraySimilarity::GetCrossCorrelation
00232 ( const TypedArray* array0, const TypedArray* array1 )
00233 {
00234   if ( ! CheckArrayDimensions( array0, array1 ) ) 
00235     return MathUtil::GetFloatNaN();
00236 
00237   Types::DataItem pixel0, pixel1;
00238   Types::DataItem sumOfProducts = 0, sumOfSquares0 = 0, sumOfSquares1 = 0;
00239 
00240   Types::DataItem mean0, mean1, dummy;
00241   array0->GetStatistics( mean0, dummy );
00242   array1->GetStatistics( mean1, dummy );
00243 
00244   unsigned int numberOfPixels = array0->GetDataSize();
00245   for ( unsigned int idx = 0; idx < numberOfPixels; ++idx ) 
00246     {
00247     if ( array0->Get( pixel0, idx ) && array1->Get( pixel1, idx ) ) 
00248       {
00249       sumOfProducts += (pixel0 - mean0) * (pixel1 - mean1);
00250       sumOfSquares0 += MathUtil::Square( pixel0 - mean0 );
00251       sumOfSquares1 += MathUtil::Square( pixel1 - mean1 );
00252       }
00253     }
00254   
00255   return sumOfProducts / ( sqrt( sumOfSquares0 ) * sqrt( sumOfSquares1 ) );
00256 }
00257 
00258 TypedArray::SmartPtr
00259 TypedArraySimilarity::GetDifferenceArray
00260 ( const TypedArray* array0, const TypedArray* array1, Types::DataItem &scaleFactor )
00261 {
00262   const size_t numberOfPixels = array0->GetDataSize();
00263   
00264   TypedArray::SmartPtr differenceArray = TypedArray::Create( GetSignedDataType( array0->GetType() ), numberOfPixels );
00265   
00266   Types::DataItem value0, value1;
00267   Types::DataItem ATA = 0.0, ATB = 0.0;
00268   for ( size_t i=0; i<numberOfPixels; i++) 
00269     {
00270     array0->Get( value0, i );
00271     ATA += (value0 * value0);
00272     
00273     array1->Get( value1, i );
00274     ATB += (value0 * value1);
00275     }
00276 
00277   // invert to get scale convention correct ( array0 = s*array1 )
00278   scaleFactor = ATA/ATB;
00279 
00280   Types::DataItem pixel0, pixel1;
00281   for ( size_t idx = 0; idx < numberOfPixels; ++idx ) 
00282     {
00283     if ( array0->Get( pixel0, idx ) && array1->Get( pixel1, idx ) ) 
00284       {
00285       differenceArray->Set( pixel0 - scaleFactor * pixel1, idx );
00286       }    
00287     }
00288   
00289   return differenceArray;
00290 }
00291 
00292 TypedArraySimilarity::ReturnType 
00293 TypedArraySimilarity::GetDifferenceArrayEntropy
00294 ( const TypedArray* array0, const TypedArray* array1,
00295   Types::DataItem &scaleFactor )
00296 {
00297   TypedArray::SmartPtr differenceArray( GetDifferenceArray( array0, array1, scaleFactor ) );
00298 
00299   return differenceArray->GetEntropy();
00300 }
00301 
00302 bool 
00303 TypedArraySimilarity::CheckArrayDimensions
00304 ( const TypedArray* array0, const TypedArray* array1 )
00305 {
00306   if ( !array0 || !array1 ) return false;
00307 
00308   return ( array0->GetDataSize() == array1->GetDataSize() );
00309 }
00310 
00311 
00312 TypedArraySimilarity::ReturnType
00313 TypedArraySimilarity::GetOptimalScale
00314 ( const TypedArray* array0, const TypedArray* array1 )
00315 {
00316   unsigned int dataSize = array0->GetDataSize();
00317   Types::DataItem value0, value1;
00318 
00319   TypedArraySimilarity::ReturnType ATA = 0.0;
00320   TypedArraySimilarity::ReturnType ATb = 0.0;
00321 
00322   for (unsigned int i=0; i<dataSize; i++) 
00323     {
00324     array0->Get( value0, i );
00325     ATA += (TypedArraySimilarity::ReturnType) (value0 * value0);
00326     
00327     array1->Get( value1, i );
00328     ATb += (TypedArraySimilarity::ReturnType) (value0 * value1);
00329     }
00330   
00331   return ATb/ATA;
00332 }
00333 
00334 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines