bayes_generator.cpp

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

Generated on 1 Mar 2011 for Fawkes API by  doxygen 1.6.1