Loading...
Searching...
No Matches
Histogram.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31#ifndef HISTOGRAM_H_
32#define HISTOGRAM_H_
33
34//
35#include <drain/Log.h>
36#include <drain/TypeUtils.h>
37#include <typeinfo>
38#include <cmath>
39
40#include <vector>
41#include <iostream>
42#include <stdexcept>
43
44#include "ValueScaling.h"
45
46
47
48namespace drain
49{
50
51// // // using namespace std;
52
53//std::cerr;
54
56
60class Histogram : protected std::vector<unsigned long> {
61public:
62
63 typedef unsigned long count_t;
64 typedef std::vector<count_t> vect_t;
65
66 Histogram(size_t size=256);
67
68 Histogram(const Histogram & histogram);
69
70 virtual ~Histogram(){};
71
72 ValueScaling scaling;
73
75 void setSize(size_t s);
76
77 static
78 std::size_t recommendSizeByType(const std::type_info & type, std::size_t defaultValue = 256);
79
80 inline
81 int getSize() const { return size(); };
82
83 inline
84 int autoSize(const std::type_info & type){
85 if (empty()){
86 resize(recommendSizeByType(type, 256));
87 }
88 return size();
89 };
90
92 inline
93 void clearBins(){
94 std::fill(begin(), end(), 0);
95 }
96
98
104 template <class T>
105 void compute(const T & src, const std::type_info & type = typeid(double), const UniTuple<double,2> & scaling = {1.0, 0.0});
106
108 //void clearBins();
109
110
112 void setSampleCount(long int n){
113 //sampleCount = n;
114 sampleCount = n;
115 sampleCountMedian = static_cast<size_t>(weight * static_cast<double>(n));
116 }
117
118 size_t getSampleCount() const {
119 return sampleCount;
120 }
121
122
124 void setRange(double dataMin, double dataMax);
125
127 inline
128 void setRange(const Range<double> & range){
129 setRange(range.min, range.max);
130 }
131
132 inline
133 void deriveScaling(const ValueScaling & s, const Type & type){
134 setRange(s.fwd(0.0), s.fwd(1 << (8*drain::Type::call<drain::sizeGetter>(type))));
135 }
136
137 inline
138 void setScale(const ValueScaling & scaling){
139 drain::Logger mout(__FILE__, __FUNCTION__);
140 mout.discouraged("use setRange instead (scaling=", scaling, ")");
141 mout.advice("range perhaps: [", this->scaling.getPhysicalRange());
142 this->scaling.assignSequence(scaling);
143 //int s = 1 << (8*drain::Type::call<drain::sizeGetter>(type));
144 }
145
147 /*
148 inline
149 void setScale(const ValueScaling & scaling){
150 //scaling.setRange(0.0, bins-1.0, dataMin, dataMax);
151 };
152 */
153
154 inline
155 int getInMin() const { return 0; };
156
158 inline
159 int getUpperBoundIn() const { return size(); };
160
161
162 inline
163 int getOutMin() const { return scaling.fwd(0); };
164
166 inline
167 int getUpperBoundOut() const { return scaling.fwd(size()); };
168
169
170
172
175 inline
176 void setMedianPosition(double pos){
177 weight = pos;
178 sampleCountMedian = static_cast<size_t>(weight * static_cast<double>(sampleCount));
179 };
180
181 /*
182 template <class T>
183 inline
184 bool withinLimits(T i) const {
185 return ((i >= inMin) && (i <= inMax)); // check if ok inMax is too much
186 }
187 */
188
189 template <class T>
190 inline
191 void increment(T i){
192 /*
193 size_t i2 = scaling.inv(i);
194 if (i2 >= this->size()){
195 std::cerr << "fail: " << i << "\t => \t" << i2 << '\t';
196 return;
197 }*/
198 ++(*this)[scaling.inv(i)];
199 ++sampleCount; // TODO: slow?
200 }
201
202 template <class T>
203 inline
204 void increment(T i, int count){
205 /*
206 size_t i2 = scaling.inv(i);
207 if (i2 >= this->size()){
208 std::cerr << "fail: " << i << "\t => \t" << i2 << '\t';
209 return;
210 }
211 */
212 (*this)[scaling.inv(i)] += count;
213 //(*this)[((i-inMin)*bins)/inSpan] += count;
214 sampleCount += count;
215 }
216
217 template <class T>
218 inline
219 void incrementRaw(T i){
220 /*
221 if (i >= this->size()){
222 std::cerr << "failRaw: " << i << '\t';
223 return;
224 }*/
225 ++(*this)[i];
226 ++sampleCount; // TODO: slow?
227 }
228
229 template <class T>
230 inline
231 void incrementRaw(T i, int count){
232 if (i > this->size()){
233 std::cerr << "failRaw: " << i << '\t';
234 return;
235 }
236 (*this)[i] += count;
237 sampleCount += count;
238 }
239
240 template <class T>
241 inline
242 void decrement(T i){
243 --(*this)[scaling.inv(i)]; // [((i-inMin)*bins)/inSpan];
244 --sampleCount;
245 }
246
247 template <class T>
248 inline
249 void decrement(T i, int count){
250 (*this)[scaling.inv(i)] -= count; //[((i-inMin)*bins)/inSpan] -= count;
251 sampleCount -= count;
252 }
253
254 template <class T>
255 inline
256 void decrementRaw(T i){
257 --(*this)[i];
258 --sampleCount;
259 }
260
261 template <class T>
262 inline
263 void decrementRaw(T i, int count){
264 (*this)[i] -= count;
265 sampleCount -= count;
266 }
267
268
269 template <class T>
270 inline
271 T scaleOut(size_type i) const {
272 //return static_cast<T>(outMin + (i*outSpan)/bins);
273 return static_cast<T>(scaling.fwd(i));
274 }
275
276
277
278
280
282 // @param p applies to weighted median; for standard median, p = 0.5.
283 template <class T>
284 inline
285 T getMax() const {
286 for (size_type i = size()-1; i > 0; --i)
287 if ((*this)[i] > 0)
288 return scaleOut<T>(i);
289 // cerr << "Warning: Histogram empty.\n";
290 return getUpperBoundOut(); //static_cast<T>(outMax);
291 }
292
293
294 template <class T>
295 inline
296 T getMin() const {
297 for (size_type i = 0; i < size(); ++i)
298 if ((*this)[i] > 0)
299 return scaleOut<T>(i);
300 //cerr << "Warning: Histogram empty.\n";
301 return getUpperBoundOut(); //static_cast<T>(outMax);
302 }
303
305
308 template <class T>
309 //inline
310 T getSum() const {
311 double sum = 0;
312 //std::cout << __FUNCTION__ << ':' << sum << std::endl;
313 for (size_type i = 0; i < size(); i++){
314 sum += ((*this)[i] * scaleOut<T>(i)); // count * nominal (should be scaled to middle)
315 //if ((*this)[i])
316 // std::cout << i << '\t' << (*this)[i] << '\t' << scaleOut<T>(i) << '\t' << sum << '\n';
317 }
318 return sum;
319 }
320
321
323 template <class T>
324 inline
325 T getMean() const {
326 //return scaleOut(getSum()/sampleCount);
327 if (sampleCount > 0)
328 return getSum<T>()/sampleCount;
329 else
330 return 0;
331 }
332
333
334 template <class T>
335 inline
336 T getMedian() const {
337 size_type sum = 0;
338 //const
339 //size_type limit = static_cast<size_t>(weight*sampleCount);
340
341 for (size_type i = 0; i < size(); ++i){
342 sum += (*this)[i];
343 if (sum >= sampleCountMedian){ // limit){
344 //if (sum >= limit){
345 return scaleOut<T>(i);
346 }
347 }
348 //return (245*sum)/sampleCount;
349
350 //return ::rand(); //static_cast<T>(outMax);
351 return getUpperBoundOut(); //static_cast<T>(outMax);
352 }
353
354
355 template <class T>
356 inline
357 T getWeightedMedian(float p) const {
358 size_type _sum;
359 if ((p < 0.0) || (p>1.0)){
360 throw std::runtime_error("Histogram<T>::getMedian: median point <0 or >1.0 .");
361 }
362 const size_t limit = sampleCountMedian; // static_cast<size_t>(p * sampleCount);
363 _sum = 0;
364 for (size_type i = 0; i < size(); i++){
365 _sum += (*this)[i];
366 if (_sum >= limit){
367 return static_cast<T>(i);
368 }
369 }
370 return static_cast<T>(size());
371 }
372
373
375 // NOTE: could be pipelined.
376 template <class T>
377 inline
378 T getVariance() const {
379 int n;
380 long sum;
381 long sum2;
382 T f;
383 T sumT;
384
385 sum = 0;
386 sum2 = 0;
387 for (size_type i = 0; i < size(); i++){
388 f = scaleOut<T>(i);
389 n = (*this)[i];
390 sum += n * f;
391 sum2 += n * (f*f);
392 }
393 sumT = static_cast<T>(sum)/sampleCount;
394 return static_cast<T>(sum2)/sampleCount - sumT*sumT;
395 }
396
397
398 template <class T>
399 inline
400 T getStdDeviation() const {
401 return static_cast<T>(sqrt(getVariance<double>()));
402 }
403
404
405
406
407
408
409 inline
410 const vect_t getVector() const {
411 return *this;
412 };
413
414 std::ostream & toStream(std::ostream & ostr) const;
415
416 void dump(std::ostream & ostr = std::cout);
417
418 std::string delimiter;
419
420 inline
421 double getValue(){
422 return (this->*statisticPtr)();
423 }
424
426
430 inline
431 double getValue(char c){
432 return (this->*getStatisticPtr(c))();
433 }
434
435
436 inline
437 void setValueFunc(char c){
438 statisticPtr = getStatisticPtr(c);
439 }
440
441
442protected:
443
444 void initialize();
445
446 typedef double (Histogram::*stat_ptr_t)() const;
447
448 double (Histogram::*statisticPtr)() const;
449
450 stat_ptr_t getStatisticPtr(char c);
451
452
453 //double (Histogram::*)getPtr const;
454
455private:
457 // size_t bins;
458
460 //size_type sampleCount;
461
463 size_type sampleCount = 0;
464
465 // Half of sampleCount.
466 size_type sampleCountMedian = 0;
467
468 // weight for weighted median;
469 float weight = 0.5;
470
472 static inline
473 bool isSmallInt(const std::type_info & type){
474 return (type == typeid(unsigned char)) || (type == typeid(unsigned short int));
475 }
476
478
481 static inline
482 short getBitShift(unsigned int value){
483 short i = 0;
484 while ((value = (value>>1)) > 0){
485 ++i;
486 }
487 return i;
488 }
489
490
491};
492
493
494template <class T>
495void Histogram::compute(const T & dst, const std::type_info & type, const UniTuple<double,2> & scaling){
496
497 drain::Logger mout(__FILE__, __FUNCTION__);
498
499 const int size = autoSize(type);
500
501 if (size <= 0){
502 mout.error(size, " bins, something went wrong");
503 return;
504 }
505
506 if (size > 0x10000){
507 mout.error(size, " bins exceeds Histogram size limit: ", 0x10000);
508 return;
509 }
510
511
512 initialize();
513
514 ValueScaling inputScaling(scaling);
515
516 const bool SAME_SCALING = (inputScaling == this->scaling);
517
518 mout.attention("scalings: ", this->scaling, ", ", inputScaling, " same? ", SAME_SCALING);
519 if (inputScaling == this->scaling){
520
521 }
522
523 mout.info("Physical range of the histogram: ", this->scaling.getPhysicalRange());
524
525 if (isSmallInt(type)){
526 const unsigned short histBits = getBitShift(size);
527 if (size == (1<<histBits)){ //
528 const signed short dataBits = (8*drain::Type::call<drain::sizeGetter>(type));
529 const short int bitShift = dataBits - histBits;
530
531 mout.note("Small int (", dataBits, "b) data, histogram[", size,"] ", histBits, " b, computing with bit shift ", bitShift);
532 // setRange(inputScaling.fwd(0), inputScaling.fwd(size -1));
533 mout.info("Physical range of the histogram: ", this->scaling.getPhysicalRange());
534 // mout.warn("Histogram size ", size, "=2^N, using bitShift=", bitShift, ", computing raw values.");
535 for (typename T::const_iterator it = dst.begin(); it != dst.end(); ++it){
536 this->incrementRaw(static_cast<unsigned short int>(*it) >> bitShift);
537 }
538 }
539 else {
540 mout.advice("Consider histogram size of 2^N, e.g.", (1<<histBits));
541 }
542 return;
543 }
544 else {
545 mout.warn("Type not unsigned short or uchar: ", drain::TypeName<T>::str());
546 mout.warn("Handling as int ");
547 for (typename T::const_iterator it = dst.begin(); it != dst.end(); ++it){
548 this->incrementRaw(static_cast<int>(*it));
549 }
550 return;
551 }
552
553 //mout.warn("Data range: ", range, ", mapped (physical) Range: ", rangeOut);
554 //mout.warn("Size ", s, " != 2^N (slow mode)");
555 //mout.advice("Consider histogram size of 2^N, e.g.", (1<<histBits));
556 mout.error("Skipping...");
557
558
559}
560
561inline
562std::ostream & operator<<(std::ostream &ostr,const Histogram &h){
563 return h.toStream(ostr);
564}
565
566}
567
568//std::ostream & operator<<(std::ostream &ostr,const drain::Histogram &h);
569
570//template <class T>
571
572
573#endif /*HISTOGRAM_H_*/
574
575// Drain
Class for computing a histogram and some statistics: average, min, max, mean, std....
Definition Histogram.h:60
void clearBins()
Does not change the size of the histogram.
Definition Histogram.h:93
double getValue(char c)
Return requested statistic.
Definition Histogram.h:431
void setRange(double dataMin, double dataMax)
Set range of original (physical) values to be mapped on the limited number of bins....
Definition Histogram.cpp:76
void setMedianPosition(double pos)
Set location of the median, if not in the middle (50%).
Definition Histogram.h:176
int getUpperBoundIn() const
Returns the upperLimit (exclusive)
Definition Histogram.h:159
int getInMin() const
Set range of original (physical) values to be mapped on the limited number of bins....
Definition Histogram.h:155
T getSum() const
Sum of the samples.
Definition Histogram.h:310
T getMean() const
Unscaled mean.
Definition Histogram.h:325
void setSampleCount(long int n)
Does not change the size of the histogram.
Definition Histogram.h:112
int getUpperBoundOut() const
Returns the upperLimit (exclusive)
Definition Histogram.h:167
void compute(const T &src, const std::type_info &type=typeid(double), const UniTuple< double, 2 > &scaling={1.0, 0.0})
Collect distribution.
Definition Histogram.h:495
T getVariance() const
Computes variance of the values inside the window.
Definition Histogram.h:378
T getMax() const
Statistics.
Definition Histogram.h:285
void setRange(const Range< double > &range)
Set range of original (physical) values to be mapped on the limited number of bins....
Definition Histogram.h:128
void setSize(size_t s)
Sets the number of bins; the resolution of the histogram.
Definition Histogram.cpp:62
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:431
Logger & note(const TT &... args)
For top-level information.
Definition Log.h:490
Logger & attention(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition Log.h:477
Logger & error(const TT &... args)
Echoes.
Definition Log.h:417
Definition Range.h:52
Utilities related to std::type_info.
Definition Type.h:48
Tuple of N elements of type T.
Definition UniTuple.h:65
Linear scaling and physical range for image intensities.
Definition ValueScaling.h:63
double fwd(double x) const
Forward scaling: given encoded value x, returns corresponding value (possibly physically meaningful).
Definition ValueScaling.h:294
Definition DataSelector.cpp:1277
Default implementation.
Definition TypeName.h:54