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