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