histogram.cpp

00001 
00002 /***************************************************************************
00003  *  histogram.cpp - Implementation of the histogram
00004  *
00005  *  Generated: Tue Jun 14 11:11:29 2005
00006  *  Copyright  2005-2009  Tim Niemueller [www.niemueller.de]
00007  *             2008       Daniel Beck
00008  *
00009  ****************************************************************************/
00010 
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version. A runtime exception applies to
00015  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU Library General Public License for more details.
00021  *
00022  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00023  */
00024 
00025 #include <fvutils/statistical/histogram.h>
00026 #include <fvutils/statistical/histogram_file.h>
00027 #include <fvutils/statistical/histogram_block.h>
00028 
00029 #include <core/exceptions/software.h>
00030 
00031 #include <iostream>
00032 #include <fstream>
00033 #include <vector>
00034 #include <cstdlib>
00035 #include <algorithm>
00036 #include <cstring>
00037 
00038 using namespace std;
00039 using namespace fawkes;
00040 
00041 
00042 namespace firevision {
00043 #if 0 /* just to make Emacs auto-indent happy */
00044 }
00045 #endif
00046 
00047 /** @class Histogram <fvutils/statistical/histogram.h>
00048  * Histogram.
00049  * Histrogram with 2D or 3D coordinates for buckets.
00050  */
00051 
00052 /** Constructor.
00053  * @param width width of histogram plane
00054  * @param height height of histogram plane
00055  * @param depth depth of the histogram
00056  * @param num_undos number of possible undos
00057  */
00058 Histogram::Histogram(unsigned int width, unsigned int height, 
00059                      unsigned int depth, unsigned int num_undos) 
00060 {
00061   if ( (width == 0) || (height == 0) || (depth == 0) ) {
00062     throw Exception("Width or height or depth is zero.");
00063   }
00064 
00065   this->width        = width;
00066   this->height       = height;
00067   this->depth        = depth;
00068   this->undo_num     = num_undos;
00069   this->undo_current = 0;
00070 
00071   if (depth == 1) {
00072     dimension = 2;
00073   } else {
00074     dimension = 3;
00075   }
00076 
00077   histogram_block = new HistogramBlock(FIREVISION_HISTOGRAM_TYPE_32, H_UNKNOWN,
00078                                        width, height, depth);
00079   histogram = (unsigned int*) histogram_block->data_ptr();
00080 
00081   histogram_size = width * height * depth * sizeof(unsigned int);
00082 
00083   undo_overlay = (unsigned int **)malloc(undo_num * sizeof(unsigned int *));
00084   for (unsigned int i = 0; i < undo_num; ++i) {
00085     undo_overlay[i] = (unsigned int *)malloc(histogram_size);
00086   }
00087 
00088   undo_num_vals = (unsigned int *)malloc(undo_num * sizeof(unsigned int));
00089 
00090   reset();
00091 }
00092 
00093 
00094 /** Constructor. 
00095  * @param block construct a histogram from the given histogram block
00096  */
00097 Histogram::Histogram(HistogramBlock* block)
00098 {
00099   width = block->width();
00100   height = block->height();
00101   depth = block->depth();
00102 
00103   if (depth == 1) {
00104     dimension = 2;
00105   } else {
00106     dimension = 3;
00107   }
00108   
00109   undo_num = 1;
00110   undo_current = 0;
00111 
00112   histogram_block = block;
00113   histogram = (unsigned int*) histogram_block->data_ptr();
00114   histogram_size = width * height * depth * sizeof(unsigned int);
00115 
00116   undo_overlay = (unsigned int **)malloc(undo_num * sizeof(unsigned int *));
00117   for (unsigned int i = 0; i < undo_num; ++i) {
00118     undo_overlay[i] = (unsigned int *)malloc(histogram_size);
00119   }
00120 
00121   undo_num_vals = (unsigned int *)malloc(undo_num * sizeof(unsigned int));
00122 }
00123 
00124 
00125 /** Destructor. */
00126 Histogram::~Histogram()
00127 {
00128   delete histogram_block;
00129   for (unsigned int i = 0; i < undo_num; ++i) {
00130     free(undo_overlay[i]);
00131   }
00132   free(undo_overlay);
00133   free(undo_num_vals);
00134 }
00135 
00136 
00137 /** Add point.
00138  * @param p point
00139  */
00140 void
00141 Histogram::operator+=(point_t *p)
00142 {
00143   if ( dimension != 2 ) {
00144     throw Exception("Trying to add 2-dim data to 3-dim histogram");
00145   }
00146 
00147   if (p->x >= width || p->y >= height) {
00148     throw OutOfBoundsException("Point lies outside of histogram range");
00149   }
00150 
00151   unsigned int index = p->y * width + p->x;
00152   histogram[index] += 1;
00153   undo_overlay[undo_current][index] += 1;
00154   ++number_of_values;
00155   undo_num_vals[undo_current] += 1;
00156 }
00157 
00158 
00159 /** Add point.
00160  * @param p point
00161  */
00162 void
00163 Histogram::operator+=(point_t p)
00164 {
00165   if ( dimension != 2 ) {
00166     throw Exception("Trying to add 2-dim data to 3-dim histogram");
00167   }
00168 
00169   if (p.x >= width || p.y >= height) {
00170     throw OutOfBoundsException("Point lies outside of histogram range");
00171   }
00172 
00173   unsigned int index = p.y * width + p.x;
00174   histogram[index] += 1;
00175   undo_overlay[undo_current][index] += 1;
00176   ++number_of_values;
00177   undo_num_vals[undo_current] += 1;
00178 }
00179 
00180 
00181 /** Get histogram data buffer.
00182  * @return histogram
00183  */
00184 unsigned int *
00185 Histogram::get_histogram()
00186 {
00187   return histogram;
00188 }
00189 
00190 
00191 /** Obtain the histogram block of this histogram.
00192  * @return pointer to the histogram block
00193  */
00194 HistogramBlock *
00195 Histogram::get_histogram_block()
00196 {
00197   return histogram_block;
00198 }
00199 
00200 
00201 /** Obtain dimensions of the histogram.
00202  * @param width reference to the variable where the width is stored
00203  * @param height reference to the variable where the height is stored
00204  * @param depth reference to the variable where the depth is stored
00205  */
00206 void
00207 Histogram::get_dimensions(unsigned int& width, unsigned int& height, unsigned int& depth)
00208 {
00209   width = this->width;
00210   height = this->height;
00211   depth = this->depth;
00212 }
00213 
00214 
00215 /** Get value from histogram.
00216  * @param x x coordinate in histogram plane
00217  * @param y y coordinate in histogram plane
00218  * @return value
00219  */
00220 unsigned int
00221 Histogram::get_value(unsigned int x, unsigned int y)
00222 {
00223   return histogram_block->get_value(x, y);
00224 }
00225 
00226 
00227 /** Get value from histogram.
00228  * @param x x coordinate in histogram plane
00229  * @param y y coordinate in histogram plane
00230  * @param z z coordinate in the histogram
00231  * @return value
00232  */
00233 unsigned int
00234 Histogram::get_value(unsigned int x, unsigned int y, unsigned int z)
00235 {
00236   return histogram_block->get_value(x, y, z);
00237 }
00238 
00239 
00240 /** Set value in histogram.
00241  * @param x x coordinate in histogram plane
00242  * @param y y coordinate in histogram plane
00243  * @param value value
00244  */
00245 void
00246 Histogram::set_value(unsigned int x, unsigned int y, unsigned int value) 
00247 {
00248   unsigned int old_value = histogram_block->get_value(x, y);
00249   histogram_block->set_value(x, y, value);
00250   number_of_values += value - old_value;
00251 
00252   unsigned int index = y * width + x;
00253   if ( value > old_value ) {
00254     // The value got incremented, add to overlay
00255     undo_overlay[undo_current][index] += value - old_value;
00256   } else {
00257     if ( (old_value - value) < undo_overlay[undo_current][index] ) {
00258       undo_overlay[undo_current][index] -= (old_value - value);
00259     } else {
00260       // We cannot handle values smaller than the original value, this is
00261       // due to choosing unsigned int as datatype, right now this should suffice
00262       undo_overlay[undo_current][index] = 0;
00263     }
00264   }
00265 }
00266 
00267 
00268 /** Set value in histogram.
00269  * @param x x coordinate in histogram plane
00270  * @param y y coordinate in histogram plane
00271  * @param z z coordinate in the histogram
00272  * @param value value
00273  */
00274 void
00275 Histogram::set_value(unsigned int x, unsigned int y, unsigned int z, unsigned int value) 
00276 {  
00277   unsigned int old_value = histogram_block->get_value(x, y, z);
00278   histogram_block->set_value(x, y, z, value);
00279 
00280   number_of_values += value - old_value;
00281   unsigned int index = z * width * height + y * width + x;
00282   if ( value > old_value ) {
00283     // The value got incremented, add to overlay
00284     undo_overlay[undo_current][index] += value - old_value;
00285   } else {
00286     if ( (old_value - value) < undo_overlay[undo_current][index] ) {
00287       undo_overlay[undo_current][index] -= (old_value - value);
00288     } else {
00289       // We cannot handle values smaller than the original value, this is
00290       // due to choosing unsigned int as datatype, right now this should suffice
00291       undo_overlay[undo_current][index] = 0;
00292     }
00293   }
00294 }
00295 
00296 
00297 /** Increase the value of the histogram at given position.
00298  * @param x x coordinate in the histogram
00299  * @param y y coordinate in the histogram
00300  * @param z z coordinate in the histogram
00301  */
00302 void
00303 Histogram::inc_value(unsigned int x, unsigned int y, unsigned int z)
00304 {
00305   unsigned int old_value = histogram_block->get_value(x, y, z);
00306   histogram_block->set_value(x, y, z, ++old_value);
00307 
00308   ++number_of_values;
00309   
00310   unsigned int index = z * width * height + y * width + x;
00311   undo_overlay[undo_current][index] = 1;
00312 }
00313 
00314 
00315 /** Add value to value in histogram at given location.
00316  * @param x x coordinate in histogram
00317  * @param y y coordinate in histogram
00318  * @param z z coordinate in histogram
00319  * @param value the value to add
00320  */
00321 void
00322 Histogram::add(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
00323 {
00324   unsigned int cur_value = histogram_block->get_value(x, y, z);
00325   histogram_block->set_value(x, y, z, cur_value + value);
00326 
00327   number_of_values += value;
00328 
00329   unsigned int index = z * width * height + y * width + x;
00330   undo_overlay[undo_current][index] = value;
00331 }
00332 
00333 
00334 /** Substract value from value in histogram at given location.
00335  * @param x x coordinate in histogram
00336  * @param y y coordinate in histogram
00337  * @param z z coordinate in histogram
00338  * @param value the value to substract
00339  */
00340 void
00341 Histogram::sub(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
00342 {
00343   unsigned int cur_value = histogram_block->get_value(x, y, z);
00344   if (value < cur_value) {
00345     set_value(x, y, z, cur_value - value);
00346   } else {
00347     set_value(x, y, z, 0);
00348   }
00349 
00350   number_of_values -= value;
00351 
00352   unsigned int index = z * width * height + y * width + x;
00353   if ( value < undo_overlay[undo_current][index] )
00354     {
00355       undo_overlay[undo_current][index] -= value;
00356     }
00357   else
00358     {
00359       undo_overlay[undo_current][index] = 0;
00360     }
00361 }
00362 
00363 
00364 /** Reset histogram. */
00365 void
00366 Histogram::reset()
00367 {
00368   histogram_block->reset();
00369   //  memset(histogram, 0, histogram_size);
00370   number_of_values = 0;
00371   for (unsigned int i = 0; i < undo_num; ++i) {
00372     switch_undo( i );
00373     reset_undo();
00374   }
00375   switch_undo( 0 );
00376 }
00377 
00378 
00379 /** Print to stream.
00380  * @param s stream
00381  */
00382 void
00383 Histogram::print_to_stream(std::ostream &s)
00384 {
00385   for (unsigned int z = 0; z < depth; ++z) {
00386     for (unsigned int y = 0; y < height; ++y) {
00387       for (unsigned int x = 0; x < width; ++x) {
00388 //      cout << histogram[z * width * height + y * width + x] << " ";
00389         cout << histogram_block->get_value(x, y, z) << " ";
00390       }
00391     }
00392     cout << endl;
00393   }
00394   cout << endl;
00395 }
00396 
00397 
00398 /** Save to file.
00399  * @param filename file name to save to
00400  * @param formatted_output one value per line
00401  */
00402 void
00403 Histogram::save(const char *filename, bool formatted_output) 
00404 {
00405   HistogramFile histogram_file;
00406   histogram_file.set_owns_blocks(false);
00407   histogram_file.add_histogram_block(histogram_block);
00408   histogram_file.write(filename);
00409 
00410   cout << "Histogram: Saved histogram in file \"" << filename << "\"." << endl;
00411 }
00412 
00413 
00414 /** Load from file.
00415  * @param filename file name to read from
00416  * @return true on success, false otherwise
00417  */
00418 bool
00419 Histogram::load(const char *filename) 
00420 {
00421   HistogramFile histogram_file;
00422   histogram_file.read(filename);
00423 
00424   if ( histogram_file.num_blocks() != 1 )
00425     {
00426       printf("load() aborted: file contains more than one histogram");
00427       return false;
00428     }
00429 
00430   histogram_block = (HistogramBlock*) histogram_file.blocks().front();
00431   histogram = (unsigned int*) histogram_block->data_ptr();
00432   histogram_size = width * height * depth * sizeof(unsigned int);
00433 
00434   for (unsigned int i = 0; i < undo_num; ++i) {
00435     free(undo_overlay[i]);
00436   }
00437   free(undo_overlay);
00438 
00439   undo_overlay = (unsigned int **)malloc(undo_num * sizeof(unsigned int *));
00440   for (unsigned int i = 0; i < undo_num; ++i) {
00441     undo_overlay[i] = (unsigned int *)malloc(histogram_size);
00442   }
00443 
00444   return true;
00445 }
00446 
00447 
00448 /** Reset undo. */
00449 void
00450 Histogram::reset_undo()
00451 {
00452   memset(undo_overlay[undo_current], 0, histogram_size);
00453   undo_num_vals[undo_current] = 0;
00454 }
00455 
00456 
00457 /** Undo. */
00458 void
00459 Histogram::undo()
00460 {
00461   for (unsigned int z = 0; z < depth; ++z) {
00462     for (unsigned int y = 0; y < height; ++y) {
00463       for (unsigned int x = 0; x < width; ++x) {
00464         unsigned int index = z * width * height + y * width + x;
00465         histogram[index] -= undo_overlay[undo_current][index];
00466       }
00467     }
00468   }
00469   number_of_values -= undo_num_vals[undo_current];
00470   reset_undo();
00471 }
00472 
00473 
00474 /** Switch undo to another undo buffer.
00475  * @param undo_id switch to buffer with this ID
00476  * @return returns current undo buffer ID
00477  */
00478 unsigned int
00479 Histogram::switch_undo( unsigned int undo_id )
00480 {
00481   unsigned int undo_last = undo_current;
00482 
00483   if (undo_id >= undo_num) {
00484     cout << "Histogram::resetUndo: ID out of range" << endl;
00485   } else {
00486     undo_current = undo_id;
00487   }
00488 
00489   return undo_last;
00490 }
00491 
00492 
00493 /** Get number of undos.
00494  * @return number of undos
00495  */
00496 unsigned int
00497 Histogram::get_num_undos()
00498 {
00499   return undo_num;
00500 }
00501 
00502 
00503 /** Get median of all values.
00504  * @return median
00505  */
00506 unsigned int
00507 Histogram::get_median()
00508 {
00509   vector< unsigned int > *values = new vector< unsigned int >( width * height * depth);
00510 
00511   values->clear();
00512   for (unsigned int z = 0; z < depth; ++z) {
00513     for (unsigned int y = 0; y < height; ++y) {
00514       for (unsigned int x = 0; x < width; ++x) {
00515         values->push_back( histogram_block->get_value(x, y, z) );
00516       }
00517     }
00518   }
00519 
00520   sort(values->begin(), values->end());
00521 
00522   unsigned int median = values->at( values->size() / 2 );
00523 
00524   delete values;
00525 
00526   return median;
00527 }
00528 
00529 
00530 /** Get average of all values.
00531  * @return average
00532  */
00533 unsigned int
00534 Histogram::get_average()
00535 {
00536   unsigned int sum = 0;
00537   unsigned int num = 0;
00538   for (unsigned int z = 0; z < depth; ++z) {
00539     for (unsigned int y = 0; y < height; ++y) {
00540       for (unsigned int x = 0; x < width; ++x) {
00541         if ( histogram[z * width * height + y * width + x ] ) {
00542           sum += histogram_block->get_value(x, y, z);
00543           num++;
00544         }
00545       }
00546     }
00547   }
00548   
00549   return (sum / num);
00550 }
00551 
00552 
00553 /** Get sum of all values.
00554  * @return sum of values
00555  */
00556 unsigned int
00557 Histogram::get_sum() const
00558 {
00559   unsigned int sum = 0;
00560   for (unsigned int z = 0; z < depth; ++z) {
00561     for (unsigned int y = 0; y < height; ++y) {
00562       for (unsigned int x = 0; x < width; ++x) {
00563         if ( histogram[z * width * height + y * width + x ] ) {
00564           sum += histogram_block->get_value(x, y, z);
00565         }
00566       }
00567     }
00568   }
00569 
00570   return sum;
00571 }
00572 
00573 } // end namespace firevision

Generated on 1 Mar 2011 for Fawkes API by  doxygen 1.6.1