Fawkes API Fawkes Development Version
|
00001 00002 /************************************************************************** 00003 * bayes_generator.cpp - generator for colormaps using a bayesian method 00004 * 00005 * Created: Wed Mar 01 14:14:41 2006 00006 * Copyright 2005-2006 Tim Niemueller [www.niemueller.de] 00007 * 2007-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/colormap/bayes/bayes_generator.h> 00026 #include <fvutils/statistical/histogram_file.h> 00027 #include <fvutils/statistical/histogram_block.h> 00028 00029 #include <fvutils/color/yuv.h> 00030 #include <fvutils/statistical/histogram.h> 00031 #include <fvutils/colormap/yuvcm.h> 00032 #include <fvutils/colormap/bayes/bayes_histos_to_lut.h> 00033 #include <core/exception.h> 00034 00035 #include <cmath> 00036 00037 using namespace std; 00038 using namespace fawkes; 00039 00040 namespace firevision { 00041 #if 0 /* just to make Emacs auto-indent happy */ 00042 } 00043 #endif 00044 00045 /** @class BayesColormapGenerator <fvutils/colormap/bayes/bayes_generator.h> 00046 * Colormap Generator using Bayes method. 00047 * @author Tim Niemueller 00048 * @author Daniel Beck 00049 */ 00050 00051 /** Constructor. 00052 * @param lut_depth the depth of the lookup table 00053 * @param fg_object the type of a foreground object 00054 * @param lut_width the width of the lookup table (u-resolution) 00055 * @param lut_height the height of the lookup table (v-resolution) 00056 */ 00057 BayesColormapGenerator::BayesColormapGenerator(unsigned int lut_depth, hint_t fg_object, unsigned int lut_width, unsigned int lut_height) 00058 { 00059 this->lut_width = lut_width; 00060 this->lut_height = lut_height; 00061 this->lut_depth = lut_depth; 00062 00063 set_fg_object(fg_object); 00064 00065 histos.clear(); 00066 fg_histos.clear(); 00067 bg_histos.clear(); 00068 00069 image_width = image_height = 0; 00070 selection_mask = 0; 00071 00072 bhtl = new BayesHistosToLut(histos, lut_depth, fg_object, lut_width, lut_height); 00073 cm = bhtl->get_colormap(); 00074 } 00075 00076 00077 /** Destructor. */ 00078 BayesColormapGenerator::~BayesColormapGenerator() 00079 { 00080 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) { 00081 delete histo_it->second; 00082 } 00083 00084 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00085 delete histo_it->second; 00086 } 00087 00088 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) { 00089 delete histo_it->second; 00090 } 00091 00092 delete[] selection_mask; 00093 } 00094 00095 00096 /** Set foreground object. 00097 * @param object the new foreground object 00098 */ 00099 void 00100 BayesColormapGenerator::set_fg_object(hint_t object) 00101 { 00102 if (H_UNKNOWN == object) 00103 { return; } 00104 00105 if ( fg_histos.find(object) == fg_histos.end() ) { 00106 fg_histos[object] = new Histogram(lut_width, lut_height, lut_depth); 00107 bg_histos[object] = new Histogram(lut_width, lut_height, lut_depth, 2); 00108 histos[object] = new Histogram(lut_width, lut_height, lut_depth); 00109 } 00110 00111 fg_object = object; 00112 } 00113 00114 00115 /** Set buffer. 00116 * @param buffer image buffer 00117 * @param width image width 00118 * @param height image height 00119 */ 00120 void 00121 BayesColormapGenerator::set_buffer(unsigned char *buffer, 00122 unsigned int width, unsigned int height) 00123 { 00124 this->buffer = buffer; 00125 image_width = width; 00126 image_height = height; 00127 00128 selection_mask = new bool[image_width * image_height]; 00129 00130 for (unsigned int i = 0; i < image_width * image_height; ++i) { 00131 selection_mask[i] = false; 00132 } 00133 00134 norm_size = image_width * image_height; 00135 } 00136 00137 00138 /** Get current color model. 00139 * @return current color model 00140 */ 00141 YuvColormap * 00142 BayesColormapGenerator::get_current() 00143 { 00144 return cm; 00145 } 00146 00147 00148 /** Check if pixel is in region. 00149 * @param x image x coordinate 00150 * @param y image y coordinate 00151 * @return true if pixel is in region, false otherwise 00152 */ 00153 bool 00154 BayesColormapGenerator::is_in_region(unsigned int x, unsigned int y) 00155 { 00156 return selection_mask[image_width * y + x]; 00157 } 00158 00159 00160 /** Set selection. 00161 * @param region selected region. 00162 */ 00163 void 00164 BayesColormapGenerator::set_selection(vector< rectangle_t > region) 00165 { 00166 this->region = region; 00167 00168 for (unsigned int i = 0; i < image_width * image_height; ++i) { 00169 selection_mask[i] = false; 00170 } 00171 00172 vector<rectangle_t>::iterator it; 00173 00174 // store selection in selection mask 00175 for (it = region.begin(); it != region.end(); it++) { 00176 for (unsigned int w = 0; w < (*it).extent.w; ++w) { 00177 for (unsigned int h = 0; h < (*it).extent.h; ++h) { 00178 unsigned int x = (*it).start.x + w; 00179 unsigned int y = (*it).start.y + h; 00180 00181 selection_mask[image_width * y + x] = true; 00182 } 00183 } 00184 } 00185 } 00186 00187 00188 /** Set min probability. 00189 * @param min_prob min probability. 00190 * @see BayesHistosToLut::setMinProbability() 00191 */ 00192 void 00193 BayesColormapGenerator::set_min_probability(float min_prob) 00194 { 00195 bhtl->setMinProbability( min_prob ); 00196 } 00197 00198 00199 /** Consider current image. */ 00200 void 00201 BayesColormapGenerator::consider() 00202 { 00203 00204 if (region.size() == 0) { 00205 cout << "Region empty, cannot consider" << endl; 00206 return; 00207 } 00208 00209 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) { 00210 (*histo_it).second->reset_undo(); 00211 } 00212 00213 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00214 (*histo_it).second->reset_undo(); 00215 } 00216 00217 unsigned int y; 00218 unsigned int u; 00219 unsigned int v; 00220 00221 for (unsigned int w = 0; w < image_width; ++w) { 00222 for (unsigned int h = 0; h < image_height; ++h) { 00223 00224 y = YUV422_PLANAR_Y_AT(buffer, image_width, w, h); 00225 u = YUV422_PLANAR_U_AT(buffer, image_width, image_height, w, h); 00226 v = YUV422_PLANAR_V_AT(buffer, image_width, image_height, w, h); 00227 00228 unsigned int y_index = (unsigned int)( y / 256.0f * float(lut_depth) ); 00229 unsigned int u_index = (unsigned int)( u / 256.0f * float(lut_width) ); 00230 unsigned int v_index = (unsigned int)( v / 256.0f * float(lut_height) ); 00231 00232 if ( is_in_region(w, h) ) { 00233 fg_histos[fg_object]->inc_value(u_index, v_index, y_index ); 00234 } else { 00235 bg_histos[fg_object]->inc_value(u_index, v_index, y_index ); 00236 } 00237 } 00238 cout << "." << flush; 00239 } 00240 cout << endl; 00241 } 00242 00243 00244 /** Calculate. */ 00245 void 00246 BayesColormapGenerator::calc() 00247 { 00248 normalize_histos(); 00249 bhtl->calculateLutValues( false /* no penalty*/ ); 00250 } 00251 00252 00253 /** Undo last inclusion. */ 00254 void 00255 BayesColormapGenerator::undo() 00256 { 00257 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) { 00258 (*histo_it).second->undo(); 00259 } 00260 00261 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00262 (*histo_it).second->undo(); 00263 } 00264 00265 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) { 00266 (*histo_it).second->undo(); 00267 } 00268 } 00269 00270 00271 /** Reset color model. */ 00272 void 00273 BayesColormapGenerator::reset() 00274 { 00275 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) { 00276 (*histo_it).second->reset(); 00277 } 00278 00279 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) { 00280 (*histo_it).second->reset(); 00281 } 00282 00283 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00284 (*histo_it).second->reset(); 00285 } 00286 00287 cm->reset(); 00288 00289 for (unsigned int i = 0; i < image_width * image_height; ++i) { 00290 selection_mask[i] = false; 00291 } 00292 } 00293 00294 00295 /** Reset undo. */ 00296 void 00297 BayesColormapGenerator::reset_undo() 00298 { 00299 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) { 00300 (*histo_it).second->reset_undo(); 00301 } 00302 00303 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) { 00304 (*histo_it).second->reset_undo(); 00305 } 00306 00307 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00308 (*histo_it).second->reset_undo(); 00309 } 00310 } 00311 00312 00313 /** Check if this color model uses histograms. 00314 * @return true 00315 */ 00316 bool 00317 BayesColormapGenerator::has_histograms() 00318 { 00319 return true; 00320 } 00321 00322 00323 /** Get histograms. 00324 * @return histograms 00325 */ 00326 std::map< hint_t, Histogram * > * 00327 BayesColormapGenerator::get_histograms() 00328 { 00329 return &histos; 00330 } 00331 00332 00333 /** Load histogram from a file. 00334 * @param filename the filename 00335 */ 00336 void 00337 BayesColormapGenerator::load_histograms(const char *filename) 00338 { 00339 HistogramFile histogram_file; 00340 histogram_file.set_owns_blocks(false); 00341 histogram_file.read(filename); 00342 00343 HistogramFile::HistogramBlockList histogram_list = histogram_file.histogram_blocks(); 00344 HistogramFile::HistogramBlockList::iterator lit; 00345 00346 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) { 00347 delete histo_it->second; 00348 } 00349 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00350 delete histo_it->second; 00351 } 00352 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) { 00353 delete histo_it->second; 00354 } 00355 fg_histos.clear(); 00356 bg_histos.clear(); 00357 histos.clear(); 00358 00359 // search background histogram block 00360 HistogramBlock* bg_histogram_block = NULL; 00361 for (lit = histogram_list.begin(); lit != histogram_list.end(); ++lit) 00362 { 00363 if ( (*lit)->object_type() == H_BACKGROUND ) 00364 { 00365 bg_histogram_block = *lit; 00366 lut_width = bg_histogram_block->width(); 00367 lut_height = bg_histogram_block->height(); 00368 lut_depth = bg_histogram_block->depth(); 00369 00370 break; 00371 } 00372 } 00373 00374 if ( !bg_histogram_block ) 00375 { 00376 throw fawkes::Exception("Histograms file does not contain a background histogram"); 00377 } 00378 00379 // read in foreground histograms 00380 norm_size = 0; 00381 for (lit = histogram_list.begin(); lit != histogram_list.end(); ++lit) 00382 { 00383 hint_t cur_object = (*lit)->object_type(); 00384 00385 if (cur_object == H_BACKGROUND) 00386 { continue; } 00387 00388 fg_histos[cur_object] = new Histogram(*lit); 00389 bg_histos[cur_object] = new Histogram(bg_histogram_block); 00390 00391 norm_size += fg_histos[cur_object]->get_sum(); 00392 } 00393 00394 norm_size += bg_histos.begin()->second->get_sum(); 00395 00396 // reconstruct background histograms 00397 HistogramMap::iterator hit; 00398 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00399 hint_t cur_object = histo_it->first; 00400 00401 for (hit = fg_histos.begin(); hit != fg_histos.end(); ++hit) { 00402 if (cur_object == hit->first) 00403 { continue; } 00404 00405 for (unsigned int x = 0; x < lut_width; ++x) { 00406 for (unsigned int y = 0; y < lut_height; ++y) { 00407 for (unsigned int z = 0; z < lut_depth; ++z) { 00408 unsigned int val = hit->second->get_value(x, y, z); 00409 histo_it->second->add(x, y, z, val); 00410 } 00411 } 00412 } 00413 } 00414 } 00415 00416 // normalize background histograms 00417 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) { 00418 hint_t cur_object = histo_it->first; 00419 float factor = ( norm_size - fg_histos[cur_object]->get_sum() ) / float( histo_it->second->get_sum() ); 00420 00421 if (factor == 1.0) 00422 { continue; } 00423 00424 for (unsigned int x = 0; x < lut_width; ++x) { 00425 for (unsigned int y = 0; y < lut_height; ++y) { 00426 for (unsigned int z = 0; z < lut_depth; ++z) { 00427 unsigned int cur_val = histo_it->second->get_value(x, y, z); 00428 unsigned int new_val = (unsigned int) rint(factor * cur_val); 00429 histo_it->second->set_value(x, y, z, new_val); 00430 } 00431 } 00432 } 00433 } 00434 00435 delete bhtl; 00436 bhtl = new BayesHistosToLut(histos, lut_depth, H_UNKNOWN, lut_width, lut_height); 00437 cm = bhtl->get_colormap(); 00438 00439 // re-compute colormap 00440 calc(); 00441 } 00442 00443 00444 /** Save histograms to a file. 00445 * @param filename the filename 00446 */ 00447 void 00448 BayesColormapGenerator::save_histograms(const char *filename) 00449 { 00450 HistogramFile histogram_file; 00451 histogram_file.set_owns_blocks(false); 00452 HistogramBlock *histogram_block; 00453 00454 normalize_histos(); 00455 00456 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) 00457 { 00458 histogram_block = histo_it->second->get_histogram_block(); 00459 histogram_block->set_object_type( histo_it->first ); 00460 histogram_file.add_histogram_block(histogram_block); 00461 } 00462 00463 histogram_file.write(filename); 00464 } 00465 00466 00467 /** Normalize histograms and compute overall background histogram. */ 00468 void 00469 BayesColormapGenerator::normalize_histos() 00470 { 00471 for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) { 00472 delete histo_it->second; 00473 } 00474 histos.clear(); 00475 00476 unsigned int fg_size = 0; 00477 unsigned int hval; 00478 float norm_factor; 00479 00480 // generate normalized fg histograms 00481 for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) 00482 { 00483 hint_t cur_object = histo_it->first; 00484 00485 if ( bg_histos.find(cur_object) == bg_histos.end() ) { 00486 throw fawkes::Exception("Corresponding background histogram is missing"); 00487 } 00488 00489 Histogram *fg = fg_histos[cur_object]; 00490 Histogram *bg = bg_histos[cur_object]; 00491 00492 unsigned int fg_sum = fg->get_sum(); 00493 unsigned int bg_sum = bg->get_sum(); 00494 00495 if ( (fg_sum + bg_sum) == 0 ) 00496 { continue; } 00497 00498 Histogram *h = new Histogram(lut_width, lut_height, lut_depth); 00499 histos[cur_object] = h; 00500 00501 norm_factor = norm_size / float(fg_sum + bg_sum); 00502 00503 for (unsigned int x = 0; x < lut_width; ++x) { 00504 for (unsigned int y = 0; y < lut_height; ++y) { 00505 for (unsigned int z = 0; z < lut_depth; ++z) { 00506 hval = (unsigned int) rint(float(fg->get_value(x, y, z)) * norm_factor); 00507 h->set_value(x, y, z, hval); 00508 } 00509 } 00510 } 00511 00512 fg_size += h->get_sum(); 00513 } 00514 00515 // compute overall background histogram 00516 Histogram *bh = new Histogram(lut_width, lut_height, lut_depth); 00517 histos[H_BACKGROUND] = bh; 00518 for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++ histo_it) 00519 { 00520 hint_t cur_object = histo_it->first; 00521 00522 Histogram *fg = fg_histos[cur_object]; 00523 Histogram *bg = bg_histos[cur_object]; 00524 00525 unsigned int fg_sum = fg->get_sum(); 00526 unsigned int bg_sum = bg->get_sum(); 00527 00528 if ( (fg_sum + bg_sum) == 0 ) 00529 { continue; } 00530 00531 norm_factor = norm_size / float(fg_sum + bg_sum); 00532 00533 for (unsigned int x = 0; x < lut_width; ++x) { 00534 for (unsigned int y = 0; y < lut_height; ++y) { 00535 for (unsigned int z = 0; z < lut_depth; ++z) { 00536 // normalize 00537 hval = (unsigned int) rint( float(bg->get_value(x, y, z)) * norm_factor); 00538 bh->add(x, y, z, hval); 00539 00540 // substract all other normalized fg histograms 00541 std::map< hint_t, Histogram * >::iterator hit; 00542 for (hit = histos.begin(); hit != histos.end(); ++hit) { 00543 if (hit->first == cur_object || hit->first == H_BACKGROUND) 00544 { continue; } 00545 00546 hval = hit->second->get_value(x, y, z); 00547 bh->sub(x, y, z, hval); 00548 } 00549 } 00550 } 00551 } 00552 } 00553 00554 // normalize overall background histogram 00555 norm_factor = (norm_size - fg_size) / float( bh->get_sum() ); 00556 00557 for (unsigned int x = 0; x < lut_width; ++x) { 00558 for (unsigned int y = 0; y < lut_height; ++y) { 00559 for (unsigned int z = 0; z < lut_depth; ++z) { 00560 hval = (unsigned int) rint( float(bh->get_value(x, y, z)) * norm_factor ); 00561 bh->set_value(x, y, z, hval); 00562 } 00563 } 00564 } 00565 } 00566 00567 } // end namespace firevision