vigra - vigra/histogram.hxx Source File

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

vigra/histogram.hxx |

    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)