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

histogram.hxx
1/************************************************************************/
2/* */
3/* Copyright 2011-2012 by Ullrich Koethe */
4/* */
5/* This file is part of the VIGRA computer vision library. */
6/* The VIGRA Website is */
7/* http://hci.iwr.uni-heidelberg.de/vigra/ */
8/* Please direct questions, bug reports, and contributions to */
9/* ullrich.koethe@iwr.uni-heidelberg.de or */
10/* vigra@informatik.uni-hamburg.de */
11/* */
12/* Permission is hereby granted, free of charge, to any person */
13/* obtaining a copy of this software and associated documentation */
14/* files (the "Software"), to deal in the Software without */
15/* restriction, including without limitation the rights to use, */
16/* copy, modify, merge, publish, distribute, sublicense, and/or */
17/* sell copies of the Software, and to permit persons to whom the */
18/* Software is furnished to do so, subject to the following */
19/* conditions: */
20/* */
21/* The above copyright notice and this permission notice shall be */
22/* included in all copies or substantial portions of the */
23/* Software. */
24/* */
25/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32/* OTHER DEALINGS IN THE SOFTWARE. */
33/* */
34/************************************************************************/
35
36#ifndef VIGRA_HISTOGRAM_HXX
37#define VIGRA_HISTOGRAM_HXX
38
39#include "config.hxx"
40#include "array_vector.hxx"
41#include <algorithm>
42
43namespace vigra {
44
45/** \brief Set histogram options.
46
47 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.
48*/
50{
51 public:
52
53 /** \brief Lower bound for linear range mapping from values to indices. */
54 double minimum;
55
56 /** \brief Upper bound for linear range mapping from values to indices. */
57 double maximum;
58
59 /** \brief Total number of bins in the histogram. */
61
62 /** \brief If true, range mapping bounds are defined by minimum and maximum of the data. */
64
65 /** Initialize members with default values:
66
67 - minimum, maximum = 0.0
68 - binCount = 64
69 - local_auto_init = false
70 */
72 : minimum(0.0), maximum(0.0),
73 binCount(64),
74 local_auto_init(false)
75 {}
76
77 /** Set minimum = mi and maximum = ma. Requirement: mi < ma.
78 */
79 HistogramOptions & setMinMax(double mi, double ma)
80 {
81 vigra_precondition(mi < ma,
82 "HistogramOptions::setMinMax(): min < max required.");
83 minimum = mi;
84 maximum = ma;
85 return *this;
86 }
87
88 /** Set binCount = c. Requirement: c > 0.
89 */
91 {
92 vigra_precondition(c > 0,
93 "HistogramOptions::setBinCount(): binCount > 0 required.");
94 binCount = c;
95 return *this;
96 }
97
98 /** Set local_auto_init = true. Requirement: setMinMax() must not have been called before. */
100 {
101 vigra_precondition(!validMinMax(),
102 "HistogramOptions::regionAutoInit(): you must not call setMinMax() when auto initialization is desired.");
103 local_auto_init = true;
104 return *this;
105 }
106
107 /** Set local_auto_init = false. Requirement: setMinMax() must not have been called before. */
109 {
110 vigra_precondition(!validMinMax(),
111 "HistogramOptions::globalAutoInit(): you must not call setMinMax() when auto initialization is desired.");
112 local_auto_init = false;
113 return *this;
114 }
115
116 /** Return minimum < maximum.
117 */
118 bool validMinMax() const
119 {
120 return minimum < maximum;
121 }
122};
123
124template <class DataType, class BinType>
125class HistogramView
126{
127 BinType * bins_;
128 int size_, stride_;
129 DataType offset_;
130 double scale_, scaleInverse_;
131
132 public:
133 HistogramView(DataType const & min, DataType const & max, int binCount,
134 BinType * bins = 0, int stride = 1)
135 : bins_(bins),
136 size_(binCount),
137 stride_(stride),
138 offset_(min),
139 scale_(double(binCount) / (max - min)),
140 scaleInverse_(1.0 / scale_)
141 {}
142
143 HistogramView & setData(BinType * bins , int stride = 1)
144 {
145 bins_ = bins;
146 stride_ = stride;
147 return *this;
148 }
149
150 HistogramView & reset()
151 {
152 if(hasData())
153 for(int k=0; k<size_; ++k)
154 *(bins_ +k*stride_) = BinType();
155 return *this;
156 }
157
158 void getBinCenters(ArrayVector<DataType> * centers) const
159 {
160 for(int k=0; k < size_; ++k)
161 {
162 (*centers)[k] = mapItemInverse(k + 0.5) ;
163 }
164 }
165
166 int size() const
167 {
168 return size_;
169 }
170
171 bool hasData() const
172 {
173 return bins_ != 0;
174 }
175
176 BinType const & operator[](int k) const
177 {
178 return *(bins_ + k*stride_);
179 }
180
181 double mapItem(DataType const & d) const
182 {
183 return scale_ * (d - offset_);
184 }
185
186 DataType mapItemInverse(double d) const
187 {
188 return DataType(d * scaleInverse_ + offset_);
189 }
190
191 void add(DataType const & d, BinType weight = NumericTraits<BinType>::one())
192 {
193 get(int(mapItem(d))) += weight;
194 }
195
196 protected:
197
198 BinType & get(int index)
199 {
200 if(index < 0)
201 index = 0;
202 if(index >= size_)
203 index = size_ - 1;
204 return *(bins_ + index*stride_);
205 }
206};
207
208template <class T>
209class TrapezoidKernel
210{
211 public:
212 typedef T value_type;
213
214 T operator[](double f) const
215 {
216 if(f < -0.5)
217 return 0.5*(f + 1.5);
218 if(f > 0.5)
219 return 0.5*(1.5 - f);
220 return 0.5;
221 }
222
223 double radius() const
224 {
225 return 1.5;
226 }
227
228 T findMaximum(double l, double c, double r) const
229 {
230 double curv = -2.0*c + r + l;
231 if(curv == 0.0)
232 return T(-0.5);
233 double extr = 0.5*(l-r) / curv;
234 if(curv < 0.0)
235 {
236 return extr < -0.5
237 ? T(-0.5)
238 : extr > 0.5
239 ? T(0.5)
240 : T(extr);
241 }
242 else
243 {
244 return extr < 0.0
245 ? T(0.5)
246 : T(-0.5);
247 }
248 }
249
250 bool findMode(double l, double c, double r, double * m) const
251 {
252 double curv = -2.0*c + r + l;
253 if(curv >= 0.0)
254 return false;
255 *m = 0.5*(l-r) / curv;
256 if(*m < -0.5 || *m > 0.5)
257 return false;
258 return true;
259 }
260};
261
262template <class DataType, class KernelType>
263class KernelHistogramView
264: public HistogramView<DataType, typename KernelType::value_type>
265{
266 KernelType kernel_;
267 int radius_;
268
269 public:
270
271 typedef typename KernelType::value_type BinType;
272 typedef HistogramView<DataType, BinType> BaseType;
273
274 KernelHistogramView(DataType const & min, DataType const & max, int binCount,
275 BinType * bins = 0, int stride = 1)
276 : BaseType(min, max, binCount, bins, stride),
277 radius_(kernel_.radius()-0.5) // FIXME: this needs generalization
278 {}
279
280 void add(DataType const & d, BinType weight = NumericTraits<BinType>::one())
281 {
282 double mapped = this->mapItem(d);
283 double f = mapped - std::floor(mapped) - kernel_.radius();
284 int center = int(mapped);
285
286 for(int k=center+radius_; k>=center-radius_; --k, f += 1.0)
287 {
288 this->get(k) += weight*kernel_[f];
289 }
290 }
291
292 DataType findMode() const
293 {
294 double mmax = 0, vmax = 0, m;
295
296 for(int k=0; k<this->size(); ++k)
297 {
298 double l = k > 0
299 ? (*this)[k-1]
300 : 0.0;
301 double c = (*this)[k];
302 double r = k < this->size() - 1
303 ? (*this)[k+1]
304 : 0.0;
305 if(kernel_.findMode(l, c, r, &m))
306 {
307 double v = l*kernel_[m+1.0] + c*kernel_[m] + r*kernel_[m-1.0];
308 if(vmax < v)
309 {
310 mmax = m + k + 0.5;
311 vmax = v;
312 }
313 }
314 }
315 return this->mapItemInverse(mmax);
316 }
317
318 template <class Array>
319 void findModes(Array * modes)
320 {
321 double m;
322 for(int k=0; k<this->size(); ++k)
323 {
324 double l = k > 0
325 ? (*this)[k-1]
326 : 0.0;
327 double c = (*this)[k];
328 double r = k < this->size() - 1
329 ? (*this)[k+1]
330 : 0.0;
331 if(kernel_.findMode(l, c, r, &m))
332 {
333 double v = l*kernel_[m+1.0] + c*kernel_[m] + r*kernel_[m-1.0];
334 modes->push_back(std::make_pair(this->mapItemInverse(m + k + 0.5), v));
335 }
336 }
337 }
338};
339
340template <class DataType, class BinType>
341class Histogram
342: public HistogramView<DataType, BinType>
343{
344 public:
345 typedef HistogramView<DataType, BinType> BaseType;
346 ArrayVector<BinType> data_;
347
348 public:
349 Histogram(DataType const & min, DataType const & max, int binCount,
350 BinType * /*bins*/ = 0, int /*stride*/ = 1)
351 : BaseType(min, max, binCount),
352 data_(binCount)
353 {
354 this->setData(&data_[0]);
355 }
356
357 Histogram const & reset()
358 {
359 this->setData(&data_[0]);
360 BaseType::reset();
361 return *this;
362 }
363 };
364
365} // namespace vigra
366
367#endif // VIGRA_HISTOGRAM_HXX
HistogramOptions & setMinMax(double mi, double ma)
Definition histogram.hxx:79
bool local_auto_init
If true, range mapping bounds are defined by minimum and maximum of the data.
Definition histogram.hxx:63
double maximum
Upper bound for linear range mapping from values to indices.
Definition histogram.hxx:57
int binCount
Total number of bins in the histogram.
Definition histogram.hxx:60
bool validMinMax() const
Definition histogram.hxx:118
double minimum
Lower bound for linear range mapping from values to indices.
Definition histogram.hxx:54
HistogramOptions & setBinCount(int c)
Definition histogram.hxx:90
HistogramOptions & globalAutoInit()
Definition histogram.hxx:108
HistogramOptions & regionAutoInit()
Definition histogram.hxx:99
HistogramOptions()
Definition histogram.hxx:71

© 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.12.1 (Thu Feb 27 2025)