Fawkes API Fawkes Development Version
histogram.cpp
1
2/***************************************************************************
3 * histogram.cpp - Implementation of the histogram
4 *
5 * Generated: Tue Jun 14 11:11:29 2005
6 * Copyright 2005-2009 Tim Niemueller [www.niemueller.de]
7 * 2008 Daniel Beck
8 *
9 ****************************************************************************/
10
11/* This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version. A runtime exception applies to
15 * this software (see LICENSE.GPL_WRE file mentioned below for details).
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
23 */
24
25#include <core/exceptions/software.h>
26#include <fvutils/statistical/histogram.h>
27#include <fvutils/statistical/histogram_block.h>
28#include <fvutils/statistical/histogram_file.h>
29
30#include <algorithm>
31#include <cstdlib>
32#include <cstring>
33#include <fstream>
34#include <iostream>
35#include <vector>
36
37using namespace std;
38using namespace fawkes;
39
40namespace firevision {
41
42/** @class Histogram <fvutils/statistical/histogram.h>
43 * Histogram.
44 * Histrogram with 2D or 3D coordinates for buckets.
45 */
46
47/** Constructor.
48 * @param width width of histogram plane
49 * @param height height of histogram plane
50 * @param depth depth of the histogram
51 * @param num_undos number of possible undos
52 */
53Histogram::Histogram(unsigned int width,
54 unsigned int height,
55 unsigned int depth,
56 unsigned int num_undos)
57{
58 if ((width == 0) || (height == 0) || (depth == 0)) {
59 throw Exception("Width or height or depth is zero.");
60 }
61
62 this->width = width;
63 this->height = height;
64 this->depth = depth;
65 this->undo_num = num_undos;
66 this->undo_current = 0;
67
68 if (depth == 1) {
69 dimension = 2;
70 } else {
71 dimension = 3;
72 }
73
74 histogram_block =
75 new HistogramBlock(FIREVISION_HISTOGRAM_TYPE_32, H_UNKNOWN, width, height, depth);
76 histogram = (unsigned int *)histogram_block->data_ptr();
77
78 histogram_size = (size_t)width * height * depth * sizeof(unsigned int);
79
80 undo_overlay = (unsigned int **)malloc(undo_num * sizeof(unsigned int *));
81 for (unsigned int i = 0; i < undo_num; ++i) {
82 undo_overlay[i] = (unsigned int *)malloc(histogram_size);
83 }
84
85 undo_num_vals = (unsigned int *)malloc(undo_num * sizeof(unsigned int));
86
87 reset();
88}
89
90/** Constructor.
91 * @param block construct a histogram from the given histogram block
92 */
94{
95 width = block->width();
96 height = block->height();
97 depth = block->depth();
98
99 if (depth == 1) {
100 dimension = 2;
101 } else {
102 dimension = 3;
103 }
104
105 undo_num = 1;
106 undo_current = 0;
107
108 histogram_block = block;
109 histogram = (unsigned int *)histogram_block->data_ptr();
110 histogram_size = (size_t)width * height * depth * sizeof(unsigned int);
111
112 undo_overlay = (unsigned int **)malloc(undo_num * sizeof(unsigned int *));
113 for (unsigned int i = 0; i < undo_num; ++i) {
114 undo_overlay[i] = (unsigned int *)malloc(histogram_size);
115 }
116
117 undo_num_vals = (unsigned int *)malloc(undo_num * sizeof(unsigned int));
118}
119
120/** Destructor. */
122{
123 delete histogram_block;
124 for (unsigned int i = 0; i < undo_num; ++i) {
125 free(undo_overlay[i]);
126 }
127 free(undo_overlay);
128 free(undo_num_vals);
129}
130
131/** Add point.
132 * @param p point
133 */
134void
136{
137 if (dimension != 2) {
138 throw Exception("Trying to add 2-dim data to 3-dim histogram");
139 }
140
141 if (p->x >= width || p->y >= height) {
142 throw OutOfBoundsException("Point lies outside of histogram range");
143 }
144
145 unsigned int index = p->y * width + p->x;
146 histogram[index] += 1;
147 undo_overlay[undo_current][index] += 1;
148 ++number_of_values;
149 undo_num_vals[undo_current] += 1;
150}
151
152/** Add point.
153 * @param p point
154 */
155void
157{
158 if (dimension != 2) {
159 throw Exception("Trying to add 2-dim data to 3-dim histogram");
160 }
161
162 if (p.x >= width || p.y >= height) {
163 throw OutOfBoundsException("Point lies outside of histogram range");
164 }
165
166 unsigned int index = p.y * width + p.x;
167 histogram[index] += 1;
168 undo_overlay[undo_current][index] += 1;
169 ++number_of_values;
170 undo_num_vals[undo_current] += 1;
171}
172
173/** Get histogram data buffer.
174 * @return histogram
175 */
176unsigned int *
178{
179 return histogram;
180}
181
182/** Obtain the histogram block of this histogram.
183 * @return pointer to the histogram block
184 */
187{
188 return histogram_block;
189}
190
191/** Obtain dimensions of the histogram.
192 * @param width reference to the variable where the width is stored
193 * @param height reference to the variable where the height is stored
194 * @param depth reference to the variable where the depth is stored
195 */
196void
197Histogram::get_dimensions(unsigned int &width, unsigned int &height, unsigned int &depth)
198{
199 width = this->width;
200 height = this->height;
201 depth = this->depth;
202}
203
204/** Get value from histogram.
205 * @param x x coordinate in histogram plane
206 * @param y y coordinate in histogram plane
207 * @return value
208 */
209unsigned int
210Histogram::get_value(unsigned int x, unsigned int y)
211{
212 return histogram_block->get_value(x, y);
213}
214
215/** Get value from histogram.
216 * @param x x coordinate in histogram plane
217 * @param y y coordinate in histogram plane
218 * @param z z coordinate in the histogram
219 * @return value
220 */
221unsigned int
222Histogram::get_value(unsigned int x, unsigned int y, unsigned int z)
223{
224 return histogram_block->get_value(x, y, z);
225}
226
227/** Set value in histogram.
228 * @param x x coordinate in histogram plane
229 * @param y y coordinate in histogram plane
230 * @param value value
231 */
232void
233Histogram::set_value(unsigned int x, unsigned int y, unsigned int value)
234{
235 unsigned int old_value = histogram_block->get_value(x, y);
236 histogram_block->set_value(x, y, value);
237 number_of_values += value - old_value;
238
239 unsigned int index = y * width + x;
240 if (value > old_value) {
241 // The value got incremented, add to overlay
242 undo_overlay[undo_current][index] += value - old_value;
243 } else {
244 if ((old_value - value) < undo_overlay[undo_current][index]) {
245 undo_overlay[undo_current][index] -= (old_value - value);
246 } else {
247 // We cannot handle values smaller than the original value, this is
248 // due to choosing unsigned int as datatype, right now this should suffice
249 undo_overlay[undo_current][index] = 0;
250 }
251 }
252}
253
254/** Set value in histogram.
255 * @param x x coordinate in histogram plane
256 * @param y y coordinate in histogram plane
257 * @param z z coordinate in the histogram
258 * @param value value
259 */
260void
261Histogram::set_value(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
262{
263 unsigned int old_value = histogram_block->get_value(x, y, z);
264 histogram_block->set_value(x, y, z, value);
265
266 number_of_values += value - old_value;
267 unsigned int index = z * width * height + y * width + x;
268 if (value > old_value) {
269 // The value got incremented, add to overlay
270 undo_overlay[undo_current][index] += value - old_value;
271 } else {
272 if ((old_value - value) < undo_overlay[undo_current][index]) {
273 undo_overlay[undo_current][index] -= (old_value - value);
274 } else {
275 // We cannot handle values smaller than the original value, this is
276 // due to choosing unsigned int as datatype, right now this should suffice
277 undo_overlay[undo_current][index] = 0;
278 }
279 }
280}
281
282/** Increase the value of the histogram at given position.
283 * @param x x coordinate in the histogram
284 * @param y y coordinate in the histogram
285 * @param z z coordinate in the histogram
286 */
287void
288Histogram::inc_value(unsigned int x, unsigned int y, unsigned int z)
289{
290 unsigned int old_value = histogram_block->get_value(x, y, z);
291 histogram_block->set_value(x, y, z, ++old_value);
292
293 ++number_of_values;
294
295 unsigned int index = z * width * height + y * width + x;
296 undo_overlay[undo_current][index] = 1;
297}
298
299/** Add value to value in histogram at given location.
300 * @param x x coordinate in histogram
301 * @param y y coordinate in histogram
302 * @param z z coordinate in histogram
303 * @param value the value to add
304 */
305void
306Histogram::add(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
307{
308 unsigned int cur_value = histogram_block->get_value(x, y, z);
309 histogram_block->set_value(x, y, z, cur_value + value);
310
311 number_of_values += value;
312
313 unsigned int index = z * width * height + y * width + x;
314 undo_overlay[undo_current][index] = value;
315}
316
317/** Substract value from value in histogram at given location.
318 * @param x x coordinate in histogram
319 * @param y y coordinate in histogram
320 * @param z z coordinate in histogram
321 * @param value the value to substract
322 */
323void
324Histogram::sub(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
325{
326 unsigned int cur_value = histogram_block->get_value(x, y, z);
327 if (value < cur_value) {
328 set_value(x, y, z, cur_value - value);
329 } else {
330 set_value(x, y, z, 0);
331 }
332
333 number_of_values -= value;
334
335 unsigned int index = z * width * height + y * width + x;
336 if (value < undo_overlay[undo_current][index]) {
337 undo_overlay[undo_current][index] -= value;
338 } else {
339 undo_overlay[undo_current][index] = 0;
340 }
341}
342
343/** Reset histogram. */
344void
346{
347 histogram_block->reset();
348 // memset(histogram, 0, histogram_size);
349 number_of_values = 0;
350 for (unsigned int i = 0; i < undo_num; ++i) {
351 switch_undo(i);
352 reset_undo();
353 }
354 switch_undo(0);
355}
356
357/** Print to stream.
358 * @param s stream
359 */
360void
362{
363 for (unsigned int z = 0; z < depth; ++z) {
364 for (unsigned int y = 0; y < height; ++y) {
365 for (unsigned int x = 0; x < width; ++x) {
366 // cout << histogram[z * width * height + y * width + x] << " ";
367 cout << histogram_block->get_value(x, y, z) << " ";
368 }
369 }
370 cout << endl;
371 }
372 cout << endl;
373}
374
375/** Save to file.
376 * @param filename file name to save to
377 * @param formatted_output one value per line
378 */
379void
380Histogram::save(const char *filename, bool formatted_output)
381{
382 HistogramFile histogram_file;
383 histogram_file.set_owns_blocks(false);
384 histogram_file.add_histogram_block(histogram_block);
385 histogram_file.write(filename);
386
387 cout << "Histogram: Saved histogram in file \"" << filename << "\"." << endl;
388}
389
390/** Load from file.
391 * @param filename file name to read from
392 * @return true on success, false otherwise
393 */
394bool
395Histogram::load(const char *filename)
396{
397 HistogramFile histogram_file;
398 histogram_file.read(filename);
399
400 if (histogram_file.num_blocks() != 1) {
401 printf("load() aborted: file contains more than one histogram");
402 return false;
403 }
404
405 histogram_block = (HistogramBlock *)histogram_file.blocks().front();
406 histogram = (unsigned int *)histogram_block->data_ptr();
407 histogram_size = (size_t)width * height * depth * sizeof(unsigned int);
408
409 for (unsigned int i = 0; i < undo_num; ++i) {
410 free(undo_overlay[i]);
411 }
412 free(undo_overlay);
413
414 undo_overlay = (unsigned int **)malloc(undo_num * sizeof(unsigned int *));
415 for (unsigned int i = 0; i < undo_num; ++i) {
416 undo_overlay[i] = (unsigned int *)malloc(histogram_size);
417 }
418
419 return true;
420}
421
422/** Reset undo. */
423void
425{
426 memset(undo_overlay[undo_current], 0, histogram_size);
427 undo_num_vals[undo_current] = 0;
428}
429
430/** Undo. */
431void
433{
434 for (unsigned int z = 0; z < depth; ++z) {
435 for (unsigned int y = 0; y < height; ++y) {
436 for (unsigned int x = 0; x < width; ++x) {
437 unsigned int index = z * width * height + y * width + x;
438 histogram[index] -= undo_overlay[undo_current][index];
439 }
440 }
441 }
442 number_of_values -= undo_num_vals[undo_current];
443 reset_undo();
444}
445
446/** Switch undo to another undo buffer.
447 * @param undo_id switch to buffer with this ID
448 * @return returns current undo buffer ID
449 */
450unsigned int
451Histogram::switch_undo(unsigned int undo_id)
452{
453 unsigned int undo_last = undo_current;
454
455 if (undo_id >= undo_num) {
456 cout << "Histogram::resetUndo: ID out of range" << endl;
457 } else {
458 undo_current = undo_id;
459 }
460
461 return undo_last;
462}
463
464/** Get number of undos.
465 * @return number of undos
466 */
467unsigned int
469{
470 return undo_num;
471}
472
473/** Get median of all values.
474 * @return median
475 */
476unsigned int
478{
479 vector<unsigned int> *values = new vector<unsigned int>((size_t)width * height * depth);
480
481 values->clear();
482 for (unsigned int z = 0; z < depth; ++z) {
483 for (unsigned int y = 0; y < height; ++y) {
484 for (unsigned int x = 0; x < width; ++x) {
485 values->push_back(histogram_block->get_value(x, y, z));
486 }
487 }
488 }
489
490 sort(values->begin(), values->end());
491
492 unsigned int median = values->at(values->size() / 2);
493
494 delete values;
495
496 return median;
497}
498
499/** Get average of all values.
500 * @return average
501 */
502unsigned int
504{
505 unsigned int sum = 0;
506 unsigned int num = 0;
507 for (unsigned int z = 0; z < depth; ++z) {
508 for (unsigned int y = 0; y < height; ++y) {
509 for (unsigned int x = 0; x < width; ++x) {
510 if (histogram[z * width * height + y * width + x]) {
511 sum += histogram_block->get_value(x, y, z);
512 num++;
513 }
514 }
515 }
516 }
517
518 return (sum / num);
519}
520
521/** Get sum of all values.
522 * @return sum of values
523 */
524unsigned int
526{
527 unsigned int sum = 0;
528 for (unsigned int z = 0; z < depth; ++z) {
529 for (unsigned int y = 0; y < height; ++y) {
530 for (unsigned int x = 0; x < width; ++x) {
531 if (histogram[z * width * height + y * width + x]) {
532 sum += histogram_block->get_value(x, y, z);
533 }
534 }
535 }
536 }
537
538 return sum;
539}
540
541} // end namespace firevision
Base class for exceptions in Fawkes.
Definition: exception.h:36
Index out of bounds.
Definition: software.h:86
void * data_ptr() const
Get data pointer.
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:290
size_t num_blocks()
Get the number of available info blocks.
Definition: fvfile.cpp:216
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:243
void set_owns_blocks(bool owns_blocks)
Lets the file take over the ownership and give up the ownership of the blocks, respectively.
Definition: fvfile.cpp:207
BlockList & blocks()
Get blocks.
Definition: fvfile.cpp:234
This class defines a file block for histograms.
uint16_t height() const
Returns the the height of the histogram.
uint32_t get_value(uint16_t x, uint16_t y)
Obtain a certain value from a 2-dimensional histogram.
uint16_t depth() const
Returns the the depth of the histogram.
uint16_t width() const
Returns the the width of the histogram.
void set_value(uint16_t x, uint16_t y, uint32_t val)
Store a value in a certain cell of a 2-dimensional histogram.
void reset()
Reset the histogram.
A fileformat for histograms.
void add_histogram_block(HistogramBlock *block)
Adds a new histogram block to the file.
unsigned int get_sum() const
Get sum of all values.
Definition: histogram.cpp:525
unsigned int * get_histogram()
Get histogram data buffer.
Definition: histogram.cpp:177
unsigned int get_average()
Get average of all values.
Definition: histogram.cpp:503
unsigned int get_value(unsigned int x, unsigned int y)
Get value from histogram.
Definition: histogram.cpp:210
void sub(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
Substract value from value in histogram at given location.
Definition: histogram.cpp:324
unsigned int get_median()
Get median of all values.
Definition: histogram.cpp:477
unsigned int get_num_undos()
Get number of undos.
Definition: histogram.cpp:468
void operator+=(fawkes::upoint_t *p)
Add point.
Definition: histogram.cpp:135
unsigned int switch_undo(unsigned int undo_id)
Switch undo to another undo buffer.
Definition: histogram.cpp:451
void reset_undo()
Reset undo.
Definition: histogram.cpp:424
void print_to_stream(std::ostream &s)
Print to stream.
Definition: histogram.cpp:361
void reset()
Reset histogram.
Definition: histogram.cpp:345
void add(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
Add value to value in histogram at given location.
Definition: histogram.cpp:306
void get_dimensions(unsigned int &width, unsigned int &height, unsigned int &depth)
Obtain dimensions of the histogram.
Definition: histogram.cpp:197
void set_value(unsigned int x, unsigned int y, unsigned int value)
Set value in histogram.
Definition: histogram.cpp:233
~Histogram()
Destructor.
Definition: histogram.cpp:121
Histogram(unsigned int width, unsigned int height, unsigned int depth=1, unsigned int num_undos=1)
Constructor.
Definition: histogram.cpp:53
bool load(const char *filename)
Load from file.
Definition: histogram.cpp:395
void save(const char *filename, bool formatted_output=false)
Save to file.
Definition: histogram.cpp:380
void inc_value(unsigned int x, unsigned int y, unsigned int z=0)
Increase the value of the histogram at given position.
Definition: histogram.cpp:288
HistogramBlock * get_histogram_block()
Obtain the histogram block of this histogram.
Definition: histogram.cpp:186
Fawkes library namespace.
Point with cartesian coordinates as unsigned integers.
Definition: types.h:35
unsigned int x
x coordinate
Definition: types.h:36
unsigned int y
y coordinate
Definition: types.h:37