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 "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
00087 if ( ! CheckArrayDimensions( array0, array1 ) ) return MathUtil::GetFloatNaN();
00088
00089
00090 const Types::DataItemRange range = array0->GetRange();
00091
00092
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
00097
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
00104 Histogram<unsigned int> histogram( numBins );
00105
00106
00107 histogram.SetRange( range );
00108
00109
00110
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
00117 Types::DataItem value0, value1;
00118 for ( unsigned int idx = 0; idx < dataSize; ++idx )
00119 {
00120
00121 if ( array0->Get( value0, idx ) && array1->Get( value1, idx ) )
00122 {
00123
00124 unsigned int bin = histogram.ValueToBin( value0 );
00125
00126 histogram.Increment( bin );
00127
00128 sumJ[bin] += value1;
00129
00130 sumSquareJ[bin] += MathUtil::Square( value1 );
00131 }
00132 }
00133
00134 double invSampleCount = 1.0 / histogram.SampleCount();
00135
00136
00137 double sumSigmaSquare = 0;
00138
00139 for ( unsigned int j = 0; j < numBins; ++j )
00140 {
00141
00142 if ( histogram[j] )
00143 {
00144
00145 double mu = sumJ[j] / histogram[j];
00146
00147 double sigmaSq = ( mu*mu*histogram[j] - 2.0*mu*sumJ[j] + sumSquareJ[j] ) / histogram[j];
00148
00149 sumSigmaSquare += (invSampleCount * histogram[j]) * sigmaSq;
00150 }
00151 }
00152
00153
00154 Types::DataItem sigmaSqJ, muJ;
00155 array1->GetStatistics( muJ, sigmaSqJ );
00156
00157 Memory::DeleteArray( sumJ );
00158 Memory::DeleteArray( sumSquareJ );
00159
00160
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
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 }