Go to the documentation of this file.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 #ifndef __cmtkJointHistogram_h_included_
00034 #define __cmtkJointHistogram_h_included_
00035
00036 #include <cmtkconfig.h>
00037
00038 #include <Base/cmtkJointHistogramBase.h>
00039 #include <Base/cmtkUniformVolume.h>
00040 #include <Base/cmtkTypedArray.h>
00041 #include <Base/cmtkMathUtil.h>
00042 #include <Base/cmtkTypes.h>
00043 #include <Base/cmtkHistogram.h>
00044
00045 #include <System/cmtkSmartPtr.h>
00046
00047 #include <vector>
00048 #include <algorithm>
00049
00050 namespace
00051 cmtk
00052 {
00053
00056
00061 template<class T>
00062 class JointHistogram :
00064 public JointHistogramBase
00065 {
00066 protected:
00068 size_t NumBinsX;
00069
00071 Types::DataItem BinWidthX;
00072
00074 Types::DataItem BinOffsetX;
00075
00077 size_t NumBinsY;
00078
00080 Types::DataItem BinWidthY;
00081
00083 Types::DataItem BinOffsetY;
00084
00086 std::vector<T> JointBins;
00087
00089 size_t m_TotalNumberOfBins;
00090
00091 public:
00093 typedef JointHistogram<T> Self;
00094
00096 typedef SmartPointer<Self> SmartPtr;
00097
00100 JointHistogram ()
00101 {
00102 this->m_TotalNumberOfBins = NumBinsX = NumBinsY = 0;
00103 BinWidthX = BinWidthY = 1.0;
00104 BinOffsetX = BinOffsetY = 0.0;
00105 }
00106
00109 JointHistogram( const size_t numBinsX, const size_t numBinsY, const bool reset = true )
00110 {
00111 this->m_TotalNumberOfBins = NumBinsX = NumBinsY = 0;
00112 BinWidthX = BinWidthY = 1.0;
00113 BinOffsetX = BinOffsetY = 0.0;
00114 this->Resize( numBinsX, numBinsY, reset );
00115 }
00116
00120 Self* Clone () const
00121 {
00122 return new Self( *this );
00123 }
00124
00126 void Resize( const size_t numberOfBinsX, const size_t numberOfBinsY, const bool reset = true )
00127 {
00128 this->NumBinsX = numberOfBinsX;
00129 this->NumBinsY = numberOfBinsY;
00130 this->m_TotalNumberOfBins = this->NumBinsX * this->NumBinsY;
00131
00132 this->JointBins.resize( this->m_TotalNumberOfBins );
00133
00134 if ( reset )
00135 this->Reset();
00136 }
00137
00139 size_t GetNumBinsX() const
00140 {
00141 return this->NumBinsX;
00142 }
00143
00145 size_t GetNumBinsY() const
00146 {
00147 return this->NumBinsY;
00148 }
00149
00152 void SetRangeX( const Types::DataItemRange& range )
00153 {
00154 this->BinOffsetX = range.m_LowerBound;
00155 this->BinWidthX = range.Width() / ( this->NumBinsX - 1 );
00156 }
00157
00160 void SetRangeY( const Types::DataItemRange& range )
00161 {
00162 this->BinOffsetY = range.m_LowerBound;
00163 this->BinWidthY = range.Width() / ( this->NumBinsY - 1 );
00164 }
00165
00168 void SetRangeCenteredX( const Types::DataItemRange& range )
00169 {
00170 this->BinWidthX = range.Width() / (this->NumBinsX - 1);
00171 this->BinOffsetX = - this->BinWidthX / 2;
00172 }
00173
00176 void SetRangeCenteredY( const Types::DataItemRange& range )
00177 {
00178 this->BinWidthY = range.Width() / (this->NumBinsY - 1);
00179 this->BinOffsetY = - this->BinWidthY / 2;
00180 }
00181
00184 const Types::DataItemRange GetRangeX() const
00185 {
00186 return Types::DataItemRange( this->BinOffsetX, this->BinOffsetX + this->BinWidthX * ( this->NumBinsX - 1) );
00187 }
00188
00191 const Types::DataItemRange GetRangeY() const
00192 {
00193 return Types::DataItemRange( this->BinOffsetY, this->BinOffsetY + this->BinWidthY * ( this->NumBinsY - 1) );
00194 }
00195
00202 void Reset ()
00203 {
00204 std::fill( this->JointBins.begin(), this->JointBins.end(), 0 );
00205 }
00206
00211 size_t ValueToBinX ( const Types::DataItem value ) const
00212 {
00213 const size_t binIndex = static_cast<size_t>( (value - BinOffsetX) / BinWidthX );
00214 return std::max<size_t>( 0, std::min<size_t>( NumBinsX-1, binIndex ) );
00215 }
00216
00221 size_t ValueToBinY ( const Types::DataItem value ) const
00222 {
00223 const size_t binIndex = static_cast<int>( (value - BinOffsetY) / BinWidthY );
00224 return std::max<size_t>( 0, std::min<size_t>( NumBinsY-1, binIndex ) );
00225 }
00226
00231 Types::DataItem BinToValueX ( const size_t bin ) const
00232 {
00233 return BinOffsetX + (bin+0.5) * BinWidthX;
00234 }
00235
00240 Types::DataItem BinToValueY ( const size_t bin ) const
00241 {
00242 return BinOffsetY + (bin+0.5) * BinWidthY;
00243 }
00244
00252 T ProjectToX ( const size_t indexX ) const
00253 {
00254 T project = 0;
00255 for ( size_t j=0; j < NumBinsY; ++j )
00256 project += this->JointBins[indexX + j * NumBinsX];
00257
00258 return project;
00259 }
00260
00268 T ProjectToY ( const size_t indexY ) const
00269 {
00270 T project = 0;
00271 size_t offset = indexY * NumBinsX;
00272 for ( size_t i = 0; i < NumBinsX; ++i )
00273 project += this->JointBins[i + offset];
00274
00275 return project;
00276 }
00277
00279 Histogram<T>* GetMarginalX() const;
00280
00282 Histogram<T>* GetMarginalY() const;
00283
00286 T GetBin( const size_t indexX, const size_t indexY ) const
00287 {
00288 return this->JointBins[ indexX + NumBinsX * indexY ];
00289 }
00290
00293 T SampleCount () const
00294 {
00295 T sampleCount = 0;
00296
00297 for ( size_t idx = 0; idx < this->m_TotalNumberOfBins; ++idx )
00298 {
00299 sampleCount += this->JointBins[idx];
00300 }
00301
00302 return sampleCount;
00303 }
00304
00307 T GetMaximumBinValue () const
00308 {
00309 T maximum = 0;
00310
00311 size_t idx = 0;
00312 for ( size_t i=0; i<NumBinsY; ++i )
00313 {
00314 for ( size_t j=0; j<NumBinsX; ++j, ++idx )
00315 maximum = std::max( maximum, this->JointBins[idx] );
00316 }
00317
00318 return maximum;
00319 }
00320
00329 void GetMarginalEntropies ( double& HX, double& HY ) const;
00330
00336 double GetJointEntropy() const;
00337
00344 void Increment ( const size_t sampleX, const size_t sampleY )
00345 {
00346 ++this->JointBins[sampleX+sampleY*NumBinsX];
00347 }
00348
00356 void Increment
00357 ( const size_t sampleX, const size_t sampleY, const T weight )
00358 {
00359 this->JointBins[ sampleX + sampleY * NumBinsX ] += weight;
00360 }
00361
00370 void Decrement ( const size_t sampleX, const size_t sampleY )
00371 {
00372 --this->JointBins[sampleX+sampleY*NumBinsX];
00373 }
00374
00375 void Decrement
00376 ( const size_t sampleX, const size_t sampleY, const Types::DataItem weight )
00377 {
00378 this->JointBins[ sampleX + sampleY * NumBinsX ] -= static_cast<T>( weight );
00379 }
00380
00390 void AddJointHistogram ( const Self& other )
00391 {
00392 for ( size_t idx = 0; idx < this->m_TotalNumberOfBins; ++idx )
00393 this->JointBins[idx] += other.JointBins[idx];
00394 }
00395
00407 void AddHistogramRow( const Histogram<T>& other, const size_t sampleY, const float weight = 1 )
00408 {
00409 size_t idx = this->NumBinsX * sampleY;
00410 for ( size_t i = 0; i<NumBinsX; ++i, ++idx )
00411 {
00412 this->JointBins[idx] += static_cast<T>( weight * other[i] );
00413 }
00414 }
00415
00427 void AddHistogramColumn( const size_t sampleX, const Histogram<T>& other, const float weight = 1 )
00428 {
00429 size_t idx = sampleX;
00430 for ( size_t j = 0; j<NumBinsY; ++j, idx += NumBinsX )
00431 this->JointBins[idx] += static_cast<T>( weight * other[j] );
00432 }
00433
00443 void RemoveJointHistogram ( const Self& other )
00444 {
00445 for ( size_t idx = 0; idx < this->m_TotalNumberOfBins; ++idx )
00446 {
00447 this->JointBins[idx] -= other.JointBins[idx];
00448 }
00449 }
00450
00456 void NormalizeOverX( const double normalizeTo = 1.0 )
00457 {
00458 for ( size_t j = 0; j < NumBinsY; ++j )
00459 {
00460 const T project = this->ProjectToY( j );
00461 if ( project > 0 )
00462 {
00463 const double factor = normalizeTo / project;
00464 for ( size_t i = 0; i < NumBinsX; ++i )
00465 this->JointBins[ i + NumBinsX * j ] = static_cast<T>( this->JointBins[ i + NumBinsX * j ] * factor );
00466 }
00467 }
00468 }
00469
00475 void NormalizeOverY( const double normalizeTo = 1.0 )
00476 {
00477 for ( size_t i = 0; i < NumBinsX; ++i )
00478 {
00479 const T project = this->ProjectToX( i );
00480 if ( project > 0 )
00481 {
00482 const double factor = normalizeTo / project;
00483 for ( size_t j = 0; j < NumBinsY; ++j )
00484 this->JointBins[ i + NumBinsX * j ] = static_cast<T>( this->JointBins[ i + NumBinsX * j ] * factor );
00485 }
00486 }
00487 }
00488
00489
00490
00491
00492
00493 size_t GetMaximumBinIndexOverX( const size_t j ) const
00494 {
00495 size_t offset = j * NumBinsX;
00496
00497 size_t maxIndex = 0;
00498 T maxValue = this->JointBins[ offset ];
00499
00500 for ( size_t i = 1; i < NumBinsX; ++i )
00501 {
00502 offset++;
00503 if ( this->JointBins[ offset ] > maxValue )
00504 {
00505 maxValue = this->JointBins[ offset ];
00506 maxIndex = i;
00507 }
00508 }
00509 return maxIndex;
00510 }
00511
00512
00513
00514
00515
00516 size_t GetMaximumBinIndexOverY( const size_t i ) const
00517 {
00518 size_t offset = i;
00519
00520 size_t maxIndex = 0;
00521 T maxValue = this->JointBins[ offset ];
00522
00523 for ( size_t j = 1; j < NumBinsY; ++j )
00524 {
00525 offset += NumBinsX;
00526 if ( this->JointBins[ offset ] > maxValue )
00527 {
00528 maxValue = this->JointBins[ offset ];
00529 maxIndex = j;
00530 }
00531 }
00532 return maxIndex;
00533 }
00534
00541 double GetMutualInformation( const bool normalized = false ) const
00542 {
00543 double hX, hY, hXY;
00544 this->GetMarginalEntropies( hX, hY );
00545 hXY = this->GetJointEntropy();
00546 if ( hXY > 0 )
00547 if ( normalized )
00548 return (hX + hY) / hXY;
00549 else
00550 return (hX + hY) - hXY;
00551 else
00552 return 0;
00553 }
00554
00556 double GetCorrelationRatio() const
00557 {
00558 T sampleCount = this->SampleCount();
00559 if ( ! sampleCount ) return 0;
00560
00561 double sigSquare = 0, m = 0;
00562 for ( size_t j = 0; j < NumBinsY; ++j )
00563 {
00564 sigSquare += ( MathUtil::Square(j) * ProjectToY(j) );
00565 m += (j * ProjectToY(j));
00566 }
00567
00568 double invSampleCount = 1.0 / sampleCount;
00569
00570 m *= invSampleCount;
00571 (sigSquare *= invSampleCount) -= MathUtil::Square(m);
00572
00573 double eta = 0;
00574 for ( size_t i = 0; i < NumBinsX; ++i )
00575 {
00576 if ( ProjectToX(i) > 0 )
00577 {
00578 double sigSquare_i = 0, m_i = 0;
00579 for ( size_t j = 0; j < NumBinsY; ++j )
00580 {
00581 sigSquare_i += (MathUtil::Square(j) * this->JointBins[ i + j * NumBinsX ]);
00582 m_i += (j * this->JointBins[ i + j * NumBinsX ]);
00583 }
00584 m_i *= (1.0 / ProjectToX(i) );
00585 (sigSquare_i *= (1.0 / ProjectToX(i))) -= MathUtil::Square(m_i);
00586 eta += (sigSquare_i * ProjectToX(i));
00587 }
00588 }
00589
00590 return eta / (sigSquare * sampleCount);
00591 }
00592 };
00593
00595
00596 }
00597
00598 #endif // #ifndef __cmtkJointHistogram_h_included_