Fawkes API  Fawkes Development Version
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.
unsigned int get_sum() const
Get sum of all values.
Definition: histogram.cpp:557
uint16_t depth() const
Returns the the depth of the histogram.
Fawkes library namespace.
uint16_t width() const
Returns the the width of the histogram.
STL namespace.
void add(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
Add value to value in histogram at given location.
Definition: histogram.cpp:322
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
unsigned int get_value(unsigned int x, unsigned int y)
Get value from histogram.
Definition: histogram.cpp:221
void set_value(unsigned int x, unsigned int y, unsigned int value)
Set value in histogram.
Definition: histogram.cpp:246
void sub(unsigned int x, unsigned int y, unsigned int z, unsigned int value)
Substract value from value in histogram at given location.
Definition: histogram.cpp:341
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
uint16_t height() const
Returns the the height of the histogram.
This class defines a file block for histograms.
A fileformat for histograms.