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