[ 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) |
html generated using doxygen and Python
|