Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
bayes_generator.cpp
1 
2 /**************************************************************************
3  * bayes_generator.cpp - generator for colormaps using a bayesian method
4  *
5  * Created: Wed Mar 01 14:14:41 2006
6  * Copyright 2005-2006 Tim Niemueller [www.niemueller.de]
7  * 2007-2008 Daniel Beck
8  *
9  ***************************************************************************/
10 
11 /* This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version. A runtime exception applies to
15  * this software (see LICENSE.GPL_WRE file mentioned below for details).
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Library General Public License for more details.
21  *
22  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
23  */
24 
25 #include <fvutils/colormap/bayes/bayes_generator.h>
26 #include <fvutils/statistical/histogram_file.h>
27 #include <fvutils/statistical/histogram_block.h>
28 
29 #include <fvutils/color/yuv.h>
30 #include <fvutils/statistical/histogram.h>
31 #include <fvutils/colormap/yuvcm.h>
32 #include <fvutils/colormap/bayes/bayes_histos_to_lut.h>
33 #include <core/exception.h>
34 
35 #include <cmath>
36 
37 using namespace std;
38 using namespace fawkes;
39 
40 namespace firevision {
41 #if 0 /* just to make Emacs auto-indent happy */
42 }
43 #endif
44 
45 /** @class BayesColormapGenerator <fvutils/colormap/bayes/bayes_generator.h>
46  * Colormap Generator using Bayes method.
47  * @author Tim Niemueller
48  * @author Daniel Beck
49  */
50 
51 /** Constructor.
52  * @param lut_depth the depth of the lookup table
53  * @param fg_object the type of a foreground object
54  * @param lut_width the width of the lookup table (u-resolution)
55  * @param lut_height the height of the lookup table (v-resolution)
56  */
57 BayesColormapGenerator::BayesColormapGenerator(unsigned int lut_depth, hint_t fg_object, unsigned int lut_width, unsigned int lut_height)
58 {
59  this->lut_width = lut_width;
60  this->lut_height = lut_height;
61  this->lut_depth = lut_depth;
62 
63  set_fg_object(fg_object);
64 
65  histos.clear();
66  fg_histos.clear();
67  bg_histos.clear();
68 
69  image_width = image_height = 0;
70  selection_mask = 0;
71 
72  bhtl = new BayesHistosToLut(histos, lut_depth, fg_object, lut_width, lut_height);
73  cm = bhtl->get_colormap();
74 }
75 
76 
77 /** Destructor. */
78 BayesColormapGenerator::~BayesColormapGenerator()
79 {
80  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) {
81  delete histo_it->second;
82  }
83 
84  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
85  delete histo_it->second;
86  }
87 
88  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) {
89  delete histo_it->second;
90  }
91 
92  delete[] selection_mask;
93 }
94 
95 
96 /** Set foreground object.
97  * @param object the new foreground object
98  */
99 void
100 BayesColormapGenerator::set_fg_object(hint_t object)
101 {
102  if (H_UNKNOWN == object)
103  { return; }
104 
105  if ( fg_histos.find(object) == fg_histos.end() ) {
106  fg_histos[object] = new Histogram(lut_width, lut_height, lut_depth);
107  bg_histos[object] = new Histogram(lut_width, lut_height, lut_depth, 2);
108  histos[object] = new Histogram(lut_width, lut_height, lut_depth);
109  }
110 
111  fg_object = object;
112 }
113 
114 
115 /** Set buffer.
116  * @param buffer image buffer
117  * @param width image width
118  * @param height image height
119  */
120 void
121 BayesColormapGenerator::set_buffer(unsigned char *buffer,
122  unsigned int width, unsigned int height)
123 {
124  this->buffer = buffer;
125  image_width = width;
126  image_height = height;
127 
128  selection_mask = new bool[image_width * image_height];
129 
130  for (unsigned int i = 0; i < image_width * image_height; ++i) {
131  selection_mask[i] = false;
132  }
133 
134  norm_size = image_width * image_height;
135 }
136 
137 
138 /** Get current color model.
139  * @return current color model
140  */
141 YuvColormap *
142 BayesColormapGenerator::get_current()
143 {
144  return cm;
145 }
146 
147 
148 /** Check if pixel is in region.
149  * @param x image x coordinate
150  * @param y image y coordinate
151  * @return true if pixel is in region, false otherwise
152  */
153 bool
154 BayesColormapGenerator::is_in_region(unsigned int x, unsigned int y)
155 {
156  return selection_mask[image_width * y + x];
157 }
158 
159 
160 /** Set selection.
161  * @param region selected region.
162  */
163 void
164 BayesColormapGenerator::set_selection(vector< rectangle_t > region)
165 {
166  this->region = region;
167 
168  for (unsigned int i = 0; i < image_width * image_height; ++i) {
169  selection_mask[i] = false;
170  }
171 
172  vector<rectangle_t>::iterator it;
173 
174  // store selection in selection mask
175  for (it = region.begin(); it != region.end(); it++) {
176  for (unsigned int w = 0; w < (*it).extent.w; ++w) {
177  for (unsigned int h = 0; h < (*it).extent.h; ++h) {
178  unsigned int x = (*it).start.x + w;
179  unsigned int y = (*it).start.y + h;
180 
181  selection_mask[image_width * y + x] = true;
182  }
183  }
184  }
185 }
186 
187 
188 /** Set min probability.
189  * @param min_prob min probability.
190  * @see BayesHistosToLut::setMinProbability()
191  */
192 void
193 BayesColormapGenerator::set_min_probability(float min_prob)
194 {
195  bhtl->setMinProbability( min_prob );
196 }
197 
198 
199 /** Consider current image. */
200 void
201 BayesColormapGenerator::consider()
202 {
203 
204  if (region.size() == 0) {
205  cout << "Region empty, cannot consider" << endl;
206  return;
207  }
208 
209  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) {
210  (*histo_it).second->reset_undo();
211  }
212 
213  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
214  (*histo_it).second->reset_undo();
215  }
216 
217  unsigned int y;
218  unsigned int u;
219  unsigned int v;
220 
221  for (unsigned int w = 0; w < image_width; ++w) {
222  for (unsigned int h = 0; h < image_height; ++h) {
223 
224  y = YUV422_PLANAR_Y_AT(buffer, image_width, w, h);
225  u = YUV422_PLANAR_U_AT(buffer, image_width, image_height, w, h);
226  v = YUV422_PLANAR_V_AT(buffer, image_width, image_height, w, h);
227 
228  unsigned int y_index = (unsigned int)( y / 256.0f * float(lut_depth) );
229  unsigned int u_index = (unsigned int)( u / 256.0f * float(lut_width) );
230  unsigned int v_index = (unsigned int)( v / 256.0f * float(lut_height) );
231 
232  if ( is_in_region(w, h) ) {
233  fg_histos[fg_object]->inc_value(u_index, v_index, y_index );
234  } else {
235  bg_histos[fg_object]->inc_value(u_index, v_index, y_index );
236  }
237  }
238  cout << "." << flush;
239  }
240  cout << endl;
241 }
242 
243 
244 /** Calculate. */
245 void
246 BayesColormapGenerator::calc()
247 {
248  normalize_histos();
249  bhtl->calculateLutValues( false /* no penalty*/ );
250 }
251 
252 
253 /** Undo last inclusion. */
254 void
255 BayesColormapGenerator::undo()
256 {
257  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) {
258  (*histo_it).second->undo();
259  }
260 
261  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
262  (*histo_it).second->undo();
263  }
264 
265  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) {
266  (*histo_it).second->undo();
267  }
268 }
269 
270 
271 /** Reset color model. */
272 void
273 BayesColormapGenerator::reset()
274 {
275  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) {
276  (*histo_it).second->reset();
277  }
278 
279  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) {
280  (*histo_it).second->reset();
281  }
282 
283  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
284  (*histo_it).second->reset();
285  }
286 
287  cm->reset();
288 
289  for (unsigned int i = 0; i < image_width * image_height; ++i) {
290  selection_mask[i] = false;
291  }
292 }
293 
294 
295 /** Reset undo. */
296 void
297 BayesColormapGenerator::reset_undo()
298 {
299  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) {
300  (*histo_it).second->reset_undo();
301  }
302 
303  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) {
304  (*histo_it).second->reset_undo();
305  }
306 
307  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
308  (*histo_it).second->reset_undo();
309  }
310 }
311 
312 
313 /** Check if this color model uses histograms.
314  * @return true
315  */
316 bool
317 BayesColormapGenerator::has_histograms()
318 {
319  return true;
320 }
321 
322 
323 /** Get histograms.
324  * @return histograms
325  */
326 std::map< hint_t, Histogram * > *
327 BayesColormapGenerator::get_histograms()
328 {
329  return &histos;
330 }
331 
332 
333 /** Load histogram from a file.
334  * @param filename the filename
335  */
336 void
337 BayesColormapGenerator::load_histograms(const char *filename)
338 {
339  HistogramFile histogram_file;
340  histogram_file.set_owns_blocks(false);
341  histogram_file.read(filename);
342 
343  HistogramFile::HistogramBlockList histogram_list = histogram_file.histogram_blocks();
344  HistogramFile::HistogramBlockList::iterator lit;
345 
346  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it) {
347  delete histo_it->second;
348  }
349  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
350  delete histo_it->second;
351  }
352  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) {
353  delete histo_it->second;
354  }
355  fg_histos.clear();
356  bg_histos.clear();
357  histos.clear();
358 
359  // search background histogram block
360  HistogramBlock* bg_histogram_block = NULL;
361  for (lit = histogram_list.begin(); lit != histogram_list.end(); ++lit)
362  {
363  if ( (*lit)->object_type() == H_BACKGROUND )
364  {
365  bg_histogram_block = *lit;
366  lut_width = bg_histogram_block->width();
367  lut_height = bg_histogram_block->height();
368  lut_depth = bg_histogram_block->depth();
369 
370  break;
371  }
372  }
373 
374  if ( !bg_histogram_block )
375  {
376  throw fawkes::Exception("Histograms file does not contain a background histogram");
377  }
378 
379  // read in foreground histograms
380  norm_size = 0;
381  for (lit = histogram_list.begin(); lit != histogram_list.end(); ++lit)
382  {
383  hint_t cur_object = (*lit)->object_type();
384 
385  if (cur_object == H_BACKGROUND)
386  { continue; }
387 
388  fg_histos[cur_object] = new Histogram(*lit);
389  bg_histos[cur_object] = new Histogram(bg_histogram_block);
390 
391  norm_size += fg_histos[cur_object]->get_sum();
392  }
393 
394  norm_size += bg_histos.begin()->second->get_sum();
395 
396  // reconstruct background histograms
397  HistogramMap::iterator hit;
398  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
399  hint_t cur_object = histo_it->first;
400 
401  for (hit = fg_histos.begin(); hit != fg_histos.end(); ++hit) {
402  if (cur_object == hit->first)
403  { continue; }
404 
405  for (unsigned int x = 0; x < lut_width; ++x) {
406  for (unsigned int y = 0; y < lut_height; ++y) {
407  for (unsigned int z = 0; z < lut_depth; ++z) {
408  unsigned int val = hit->second->get_value(x, y, z);
409  histo_it->second->add(x, y, z, val);
410  }
411  }
412  }
413  }
414  }
415 
416  // normalize background histograms
417  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++histo_it) {
418  hint_t cur_object = histo_it->first;
419  float factor = ( norm_size - fg_histos[cur_object]->get_sum() ) / float( histo_it->second->get_sum() );
420 
421  if (factor == 1.0)
422  { continue; }
423 
424  for (unsigned int x = 0; x < lut_width; ++x) {
425  for (unsigned int y = 0; y < lut_height; ++y) {
426  for (unsigned int z = 0; z < lut_depth; ++z) {
427  unsigned int cur_val = histo_it->second->get_value(x, y, z);
428  unsigned int new_val = (unsigned int) rint(factor * cur_val);
429  histo_it->second->set_value(x, y, z, new_val);
430  }
431  }
432  }
433  }
434 
435  delete bhtl;
436  bhtl = new BayesHistosToLut(histos, lut_depth, H_UNKNOWN, lut_width, lut_height);
437  cm = bhtl->get_colormap();
438 
439  // re-compute colormap
440  calc();
441 }
442 
443 
444 /** Save histograms to a file.
445  * @param filename the filename
446  */
447 void
448 BayesColormapGenerator::save_histograms(const char *filename)
449 {
450  HistogramFile histogram_file;
451  histogram_file.set_owns_blocks(false);
452  HistogramBlock *histogram_block;
453 
454  normalize_histos();
455 
456  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it)
457  {
458  histogram_block = histo_it->second->get_histogram_block();
459  histogram_block->set_object_type( histo_it->first );
460  histogram_file.add_histogram_block(histogram_block);
461  }
462 
463  histogram_file.write(filename);
464 }
465 
466 
467 /** Normalize histograms and compute overall background histogram. */
468 void
469 BayesColormapGenerator::normalize_histos()
470 {
471  for (histo_it = histos.begin(); histo_it != histos.end(); ++histo_it) {
472  delete histo_it->second;
473  }
474  histos.clear();
475 
476  unsigned int fg_size = 0;
477  unsigned int hval;
478  float norm_factor;
479 
480  // generate normalized fg histograms
481  for (histo_it = fg_histos.begin(); histo_it != fg_histos.end(); ++histo_it)
482  {
483  hint_t cur_object = histo_it->first;
484 
485  if ( bg_histos.find(cur_object) == bg_histos.end() ) {
486  throw fawkes::Exception("Corresponding background histogram is missing");
487  }
488 
489  Histogram *fg = fg_histos[cur_object];
490  Histogram *bg = bg_histos[cur_object];
491 
492  unsigned int fg_sum = fg->get_sum();
493  unsigned int bg_sum = bg->get_sum();
494 
495  if ( (fg_sum + bg_sum) == 0 )
496  { continue; }
497 
498  Histogram *h = new Histogram(lut_width, lut_height, lut_depth);
499  histos[cur_object] = h;
500 
501  norm_factor = norm_size / float(fg_sum + bg_sum);
502 
503  for (unsigned int x = 0; x < lut_width; ++x) {
504  for (unsigned int y = 0; y < lut_height; ++y) {
505  for (unsigned int z = 0; z < lut_depth; ++z) {
506  hval = (unsigned int) rint(float(fg->get_value(x, y, z)) * norm_factor);
507  h->set_value(x, y, z, hval);
508  }
509  }
510  }
511 
512  fg_size += h->get_sum();
513  }
514 
515  // compute overall background histogram
516  Histogram *bh = new Histogram(lut_width, lut_height, lut_depth);
517  histos[H_BACKGROUND] = bh;
518  for (histo_it = bg_histos.begin(); histo_it != bg_histos.end(); ++ histo_it)
519  {
520  hint_t cur_object = histo_it->first;
521 
522  Histogram *fg = fg_histos[cur_object];
523  Histogram *bg = bg_histos[cur_object];
524 
525  unsigned int fg_sum = fg->get_sum();
526  unsigned int bg_sum = bg->get_sum();
527 
528  if ( (fg_sum + bg_sum) == 0 )
529  { continue; }
530 
531  norm_factor = norm_size / float(fg_sum + bg_sum);
532 
533  for (unsigned int x = 0; x < lut_width; ++x) {
534  for (unsigned int y = 0; y < lut_height; ++y) {
535  for (unsigned int z = 0; z < lut_depth; ++z) {
536  // normalize
537  hval = (unsigned int) rint( float(bg->get_value(x, y, z)) * norm_factor);
538  bh->add(x, y, z, hval);
539 
540  // substract all other normalized fg histograms
541  std::map< hint_t, Histogram * >::iterator hit;
542  for (hit = histos.begin(); hit != histos.end(); ++hit) {
543  if (hit->first == cur_object || hit->first == H_BACKGROUND)
544  { continue; }
545 
546  hval = hit->second->get_value(x, y, z);
547  bh->sub(x, y, z, hval);
548  }
549  }
550  }
551  }
552  }
553 
554  // normalize overall background histogram
555  norm_factor = (norm_size - fg_size) / float( bh->get_sum() );
556 
557  for (unsigned int x = 0; x < lut_width; ++x) {
558  for (unsigned int y = 0; y < lut_height; ++y) {
559  for (unsigned int z = 0; z < lut_depth; ++z) {
560  hval = (unsigned int) rint( float(bh->get_value(x, y, z)) * norm_factor );
561  bh->set_value(x, y, z, hval);
562  }
563  }
564  }
565 }
566 
567 } // end namespace firevision
void set_object_type(hint_t object_type)
Set the type of the object the histogram is associated with.
LUT generation by using Bayesian method on histograms.
HistogramBlockList histogram_blocks()
Generates a list of histogram blocks attached to the file.
uint16_t depth() const
Returns the the depth of the histogram.
uint16_t height() const
Returns the the height of the histogram.
YUV Colormap.
Definition: yuvcm.h:39
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:262
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:308
Base class for exceptions in Fawkes.
Definition: exception.h:36
uint16_t width() const
Returns the the width of the histogram.
void add_histogram_block(HistogramBlock *block)
Adds a new histogram block to the file.
std::list< HistogramBlock * > HistogramBlockList
Convenience typdef for a STL list of pointers to histogram blocks.
void set_owns_blocks(bool owns_blocks)
Lets the file take over the ownership and give up the ownership of the blocks, respectively.
Definition: fvfile.cpp:222
This class defines a file block for histograms.
A fileformat for histograms.