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 
37 using namespace std;
38 using namespace fawkes;
39 
40 namespace 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  */
53 Histogram::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  */
93 Histogram::Histogram(HistogramBlock *block)
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. */
121 Histogram::~Histogram()
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  */
134 void
135 Histogram::operator+=(upoint_t *p)
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  */
155 void
156 Histogram::operator+=(upoint_t p)
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  */
176 unsigned int *
177 Histogram::get_histogram()
178 {
179  return histogram;
180 }
181 
182 /** Obtain the histogram block of this histogram.
183  * @return pointer to the histogram block
184  */
186 Histogram::get_histogram_block()
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  */
196 void
197 Histogram::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  */
209 unsigned int
210 Histogram::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  */
221 unsigned int
222 Histogram::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  */
232 void
233 Histogram::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  */
260 void
261 Histogram::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  */
287 void
288 Histogram::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  */
305 void
306 Histogram::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  */
323 void
324 Histogram::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. */
344 void
345 Histogram::reset()
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  */
360 void
361 Histogram::print_to_stream(std::ostream &s)
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  */
379 void
380 Histogram::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  */
394 bool
395 Histogram::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. */
423 void
424 Histogram::reset_undo()
425 {
426  memset(undo_overlay[undo_current], 0, histogram_size);
427  undo_num_vals[undo_current] = 0;
428 }
429 
430 /** Undo. */
431 void
432 Histogram::undo()
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  */
450 unsigned int
451 Histogram::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  */
467 unsigned int
468 Histogram::get_num_undos()
469 {
470  return undo_num;
471 }
472 
473 /** Get median of all values.
474  * @return median
475  */
476 unsigned int
477 Histogram::get_median()
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  */
502 unsigned int
503 Histogram::get_average()
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  */
524 unsigned int
525 Histogram::get_sum() const
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
size_t num_blocks()
Get the number of available info blocks.
Definition: fvfile.cpp:216
uint16_t depth() const
Returns the the depth of the histogram.
Fawkes library namespace.
unsigned int y
y coordinate
Definition: types.h:37
uint16_t width() const
Returns the the width of the histogram.
unsigned int x
x coordinate
Definition: types.h:36
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:243
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:290
void * data_ptr() const
Get data pointer.
Base class for exceptions in Fawkes.
Definition: exception.h:35
void add_histogram_block(HistogramBlock *block)
Adds a new histogram block to the file.
Point with cartesian coordinates as unsigned integers.
Definition: types.h:34
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
uint16_t height() const
Returns the the height of the histogram.
This class defines a file block for histograms.
Index out of bounds.
Definition: software.h:85
uint32_t get_value(uint16_t x, uint16_t y)
Obtain a certain value from a 2-dimensional histogram.
A fileformat for histograms.
BlockList & blocks()
Get blocks.
Definition: fvfile.cpp:234