cmtkJointHistogram.h

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: 2752 $
00026 //
00027 //  $LastChangedDate: 2011-01-17 11:33:31 -0800 (Mon, 17 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
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   /* Return the index of the bin with the maximum value for one row.
00490    *\param j Index of the row.
00491    *\return The index of the bin with the maximum value in row j.
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   /* Return the index of the bin with the maximum value for one column.
00513    *\param j Index of the column.
00514    *\return The index of the bin with the maximum value in column j.
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 } // namespace cmtk
00597 
00598 #endif // #ifndef __cmtkJointHistogram_h_included_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines