[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

vigra/histogram.hxx VIGRA

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 2011-2012 by Ullrich Koethe                  */
00004 /*                                                                      */
00005 /*    This file is part of the VIGRA computer vision library.           */
00006 /*    The VIGRA Website is                                              */
00007 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
00008 /*    Please direct questions, bug reports, and contributions to        */
00009 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00010 /*        vigra@informatik.uni-hamburg.de                               */
00011 /*                                                                      */
00012 /*    Permission is hereby granted, free of charge, to any person       */
00013 /*    obtaining a copy of this software and associated documentation    */
00014 /*    files (the "Software"), to deal in the Software without           */
00015 /*    restriction, including without limitation the rights to use,      */
00016 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00017 /*    sell copies of the Software, and to permit persons to whom the    */
00018 /*    Software is furnished to do so, subject to the following          */
00019 /*    conditions:                                                       */
00020 /*                                                                      */
00021 /*    The above copyright notice and this permission notice shall be    */
00022 /*    included in all copies or substantial portions of the             */
00023 /*    Software.                                                         */
00024 /*                                                                      */
00025 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00026 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00027 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00028 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00029 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00030 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00031 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00032 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
00033 /*                                                                      */
00034 /************************************************************************/
00035 
00036 #ifndef VIGRA_HISTOGRAM_HXX
00037 #define VIGRA_HISTOGRAM_HXX
00038 
00039 #include "config.hxx"
00040 #include "array_vector.hxx"
00041 #include <algorithm>
00042 
00043 namespace vigra {
00044 
00045 /** \brief Set histogram options.
00046 
00047     HistogramOptions objects are used to pass histogram options to other objects. This \ref acc_hist_options "example" shows how it is is used to pass histogram options to an accumulator chain.
00048 */
00049 class HistogramOptions
00050 {
00051   public:
00052 
00053     /** \brief Lower bound for linear range mapping from values to indices. */
00054     double minimum;
00055 
00056     /** \brief Upper bound for linear range mapping from values to indices. */
00057     double maximum;
00058 
00059     /** \brief Total number of bins in the histogram. */
00060     int binCount;
00061 
00062     /** \brief If true, range mapping bounds are defined by minimum and maximum of the data. */
00063     bool local_auto_init;
00064     
00065     /** Initialize members with default values:
00066 
00067     - minimum, maximum = 0.0
00068     - binCount = 64
00069     - local_auto_init = false
00070     */
00071     HistogramOptions()
00072     : minimum(0.0), maximum(0.0),
00073       binCount(64),
00074       local_auto_init(false)
00075     {}
00076     
00077     /** Set minimum = mi and maximum = ma. Requirement: mi < ma.
00078     */
00079     HistogramOptions & setMinMax(double mi, double ma)
00080     {
00081         vigra_precondition(mi < ma,
00082             "HistogramOptions::setMinMax(): min < max required.");
00083         minimum = mi;
00084         maximum = ma;
00085         return *this;
00086     }
00087 
00088     /** Set binCount = c. Requirement: c > 0.
00089     */
00090     HistogramOptions & setBinCount(int c)
00091     {
00092         vigra_precondition(c > 0,
00093             "HistogramOptions::setBinCount(): binCount > 0 required.");
00094         binCount = c;
00095         return *this;
00096     }
00097 
00098     /** Set local_auto_init = true. Requirement: setMinMax() must not have been called before. */
00099     HistogramOptions & regionAutoInit()
00100     {
00101         vigra_precondition(!validMinMax(),
00102             "HistogramOptions::regionAutoInit(): you must not call setMinMax() when auto initialization is desired.");
00103         local_auto_init = true;
00104         return *this;
00105     }
00106 
00107     /** Set local_auto_init = false. Requirement: setMinMax() must not have been called before. */
00108     HistogramOptions & globalAutoInit()
00109     {
00110         vigra_precondition(!validMinMax(),
00111             "HistogramOptions::globalAutoInit(): you must not call setMinMax() when auto initialization is desired.");
00112         local_auto_init = false;
00113         return *this;
00114     }
00115     
00116     /** Return minimum < maximum.
00117     */
00118     bool validMinMax() const
00119     {
00120         return minimum < maximum;
00121     }
00122 };
00123 
00124 template <class DataType, class BinType>
00125 class HistogramView
00126 {
00127     BinType * bins_;
00128     int size_, stride_;
00129     DataType offset_;
00130     double scale_, scaleInverse_;
00131     
00132   public:
00133     HistogramView(DataType const & min, DataType const & max, int binCount, 
00134                   BinType * bins = 0, int stride = 1)
00135     : bins_(bins),
00136       size_(binCount),
00137       stride_(stride),
00138       offset_(min),
00139       scale_(double(binCount) / (max - min)),
00140       scaleInverse_(1.0 / scale_)
00141     {}
00142     
00143     HistogramView & setData(BinType * bins , int stride = 1)
00144     {
00145         bins_ = bins;
00146         stride_ = stride;
00147         return *this;
00148     }
00149     
00150     HistogramView & reset()
00151     {
00152         if(hasData())
00153             for(int k=0; k<size_; ++k)
00154                 *(bins_ +k*stride_) = BinType();
00155         return *this;
00156     }
00157     
00158     void getBinCenters(ArrayVector<DataType> * centers) const
00159     {
00160         double invScale = 1.0 / scale_;
00161         for(int k=0; k < size_; ++k)
00162         {
00163             (*centers)[k] = mapItemInverse(k + 0.5) ;
00164         }
00165     }
00166     
00167     int size() const
00168     {
00169         return size_;
00170     }
00171     
00172     bool hasData() const
00173     {
00174         return bins_ != 0;
00175     }
00176     
00177     BinType const & operator[](int k) const
00178     {
00179         return *(bins_ + k*stride_);
00180     }
00181 
00182     double mapItem(DataType const & d) const
00183     {
00184         return scale_ * (d - offset_);
00185     }
00186     
00187     DataType mapItemInverse(double d) const
00188     {
00189         return DataType(d * scaleInverse_ + offset_);
00190     }
00191     
00192     void add(DataType const & d, BinType weight = NumericTraits<BinType>::one())
00193     {
00194         get(int(mapItem(d))) += weight;
00195     }
00196 
00197   protected:
00198 
00199     BinType & get(int index)
00200     {
00201         if(index < 0)
00202             index = 0;
00203         if(index >= size_)
00204             index = size_ - 1;
00205         return *(bins_ + index*stride_);
00206     }
00207 };
00208 
00209 template <class T>
00210 class TrapezoidKernel
00211 {
00212   public:
00213     typedef T value_type;
00214     
00215     T operator[](double f) const
00216     {
00217         if(f < -0.5)
00218             return 0.5*(f + 1.5);
00219         if(f > 0.5)
00220             return 0.5*(1.5 - f);
00221         return 0.5;
00222     }
00223     
00224     double radius() const
00225     {
00226         return 1.5;
00227     }
00228     
00229     T findMaximum(double l, double c, double r) const
00230     {
00231         double curv = -2.0*c + r + l;
00232         if(curv == 0.0)
00233             return T(-0.5);
00234         double extr = 0.5*(l-r) / curv;
00235         if(curv < 0.0)
00236         {
00237             return extr < -0.5
00238                        ? T(-0.5)
00239                        : extr > 0.5
00240                               ? T(0.5)
00241                               : T(extr);
00242         }
00243         else
00244         {
00245             return extr < 0.0
00246                        ? T(0.5)
00247                        : T(-0.5);
00248         }
00249     }
00250     
00251     bool findMode(double l, double c, double r, double * m) const
00252     {
00253         double curv = -2.0*c + r + l;
00254         if(curv >= 0.0)
00255             return false;
00256         *m = 0.5*(l-r) / curv;
00257         if(*m < -0.5 || *m > 0.5)
00258             return false;
00259         return true;
00260     }
00261 };
00262 
00263 template <class DataType, class KernelType>
00264 class KernelHistogramView
00265 : public HistogramView<DataType, typename KernelType::value_type>
00266 {
00267     KernelType kernel_;
00268     int radius_;
00269     
00270   public:
00271   
00272     typedef typename KernelType::value_type BinType;
00273     typedef HistogramView<DataType, BinType> BaseType;
00274 
00275     KernelHistogramView(DataType const & min, DataType const & max, int binCount, 
00276                         BinType * bins = 0, int stride = 1)
00277     : BaseType(min, max, binCount, bins, stride),
00278       radius_(kernel_.radius()-0.5) // FIXME: this needs generalization
00279     {}
00280     
00281     void add(DataType const & d, BinType weight = NumericTraits<BinType>::one())
00282     {
00283         double mapped = this->mapItem(d);
00284         double f = mapped - std::floor(mapped) - kernel_.radius();
00285         int center = int(mapped);
00286         
00287         for(int k=center+radius_; k>=center-radius_; --k, f += 1.0)
00288         {   
00289             this->get(k) += weight*kernel_[f];
00290         }
00291     }
00292     
00293     DataType findMode() const
00294     {
00295         double mmax = 0, vmax = 0, m;
00296         
00297         for(int k=0; k<this->size(); ++k)
00298         {
00299             double l = k > 0
00300                          ? (*this)[k-1]
00301                          : 0.0;
00302             double c = (*this)[k];
00303             double r = k < this->size() - 1
00304                          ? (*this)[k+1]
00305                          : 0.0;
00306             if(kernel_.findMode(l, c, r, &m))
00307             {
00308                 double v = l*kernel_[m+1.0] + c*kernel_[m] + r*kernel_[m-1.0];
00309                 if(vmax < v)
00310                 {
00311                     mmax = m + k + 0.5;
00312                     vmax = v;
00313                 }
00314             }
00315         }
00316         return this->mapItemInverse(mmax);
00317     }
00318     
00319     template <class Array>
00320     void findModes(Array * modes)
00321     {
00322         double m;
00323         for(int k=0; k<this->size(); ++k)
00324         {
00325             double l = k > 0
00326                          ? (*this)[k-1]
00327                          : 0.0;
00328             double c = (*this)[k];
00329             double r = k < this->size() - 1
00330                          ? (*this)[k+1]
00331                          : 0.0;
00332             if(kernel_.findMode(l, c, r, &m))
00333             {
00334                 double v = l*kernel_[m+1.0] + c*kernel_[m] + r*kernel_[m-1.0];
00335                 modes->push_back(std::make_pair(this->mapItemInverse(m + k + 0.5), v));
00336             }
00337         }
00338     }
00339 };
00340 
00341 template <class DataType, class BinType>
00342 class Histogram
00343 : public HistogramView<DataType, BinType>
00344 {
00345   public:
00346     typedef HistogramView<DataType, BinType> BaseType;
00347     ArrayVector<BinType> data_;
00348     
00349   public:
00350     Histogram(DataType const & min, DataType const & max, int binCount, 
00351                   BinType * bins = 0, int stride = 1)
00352     : BaseType(min, max, binCount),
00353       data_(binCount)
00354     {
00355         this->setData(&data_[0]);
00356     }
00357     
00358     Histogram const & reset()
00359     {
00360         this->setData(&data_[0]);
00361         BaseType::reset();
00362         return *this;
00363     }
00364  };
00365 
00366 } // namespace vigra
00367 
00368 #endif // VIGRA_HISTOGRAM_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.9.0 (Tue Nov 6 2012)