Fawkes API
Fawkes Development Version
|
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