Fawkes API  Fawkes Development Version
bayes_histos_to_lut.cpp
1 
2 /**************************************************************************
3  * bayes_histos_to_lut.cpp - This file implements a class
4  * that takes color histograms of objects as input,
5  * and, together with probabilities of objects,
6  * generates all the values for a lookup-table
7  * that maps from colors to objects
8  *
9  * Generated: Mon Jun 27 14:16:52 2005
10  * Copyright 2005 Martin Heracles
11  * 2005-2008 Tim Niemueller [www.niemueller.de]
12  * 2007-2008 Daniel Beck
13  *
14  ***************************************************************************/
15 
16 /* This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version. A runtime exception applies to
20  * this software (see LICENSE.GPL_WRE file mentioned below for details).
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Library General Public License for more details.
26  *
27  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
28  */
29 
30 #include <fvutils/colormap/bayes/bayes_histos_to_lut.h>
31 #include <fvutils/statistical/histogram.h>
32 #include <fvutils/colormap/yuvcm.h>
33 #include <fvutils/colormap/cmfile.h>
34 #include <core/exception.h>
35 
36 #include <fvutils/color/color_object_map.h>
37 
38 #include <iostream>
39 #include <string>
40 #include <cstdlib>
41 #include <cstdio>
42 
43 using namespace std;
44 
45 namespace firevision {
46 #if 0 /* just to make Emacs auto-indent happy */
47 }
48 #endif
49 
50 /** @class BayesHistosToLut <fvutils/colormap/bayes/bayes_histos_to_lut.h>
51  * LUT generation by using Bayesian method on histograms.
52  * Generates a YUV colormap.
53  * @author Martin Herakles.
54  * @author Tim Niemueller
55  * @author Daniel Beck
56  */
57 
58 /** Constructor.
59  * @param histos histograms
60  * @param d depth of lookup table
61  * @param fg_object type of the foreground object
62  * @param w the width of the lookup table (u-resolution)
63  * @param h the height of the lookup table (v-resolution)
64  */
65 BayesHistosToLut::BayesHistosToLut(std::map<hint_t, Histogram*> &histos,
66  unsigned int d, hint_t fg_object, unsigned int w, unsigned int h)
67  : histograms(histos), fg_object(fg_object)
68 {
69  width = w;
70  height = h;
71  depth = d;
72 
73  // no as shmem segment
74  lut = new YuvColormap(depth, width, height);
75 
76  min_probability = 0.3;
77  min_prob_ball = 0.0;
78  min_prob_green = 0.0;
79  min_prob_yellow = 0.0;
80  min_prob_blue = 0.0;
81  min_prob_white = 0.0;
82  min_prob_black = 0.0;
83 }
84 
85 /** Destructor. */
87 {
88  delete lut;
89 }
90 
91 /** Get name.
92  * @return BayesHistosToLut
93  */
94 string
96 {
97  return string("BayesHistosToLut");
98 }
99 
100 /** Get object probability.
101  * @param object object
102  * @return probability.
103  */
104 float
106 {
107  // These object probabilities should better be read from config file.
108 
109  if (fg_object == H_BALL) {
110  /*
111  switch (object) {
112  case H_BALL:
113  */
114  return 0.2;
115  /*
116  break;
117  case H_BACKGROUND:
118  return 0.8;
119  break;
120  case H_ROBOT:
121  return 0.0;
122  break;
123  case H_FIELD:
124  return 0.0;
125  break;
126  case H_GOAL_BLUE:
127  return 0.0;
128  break;
129  case H_GOAL_YELLOW:
130  return 0.0;
131  break;
132  case H_LINE:
133  return 0.0;
134  break;
135  case H_UNKNOWN:
136  return 0.0;
137  break;
138  default:
139  cout << "(BayesHistosToLut::getObjectProb): Invalid object." << endl;
140  exit(-1);
141  return 0.0f;
142  break;
143  }
144  */
145  } else {
146  if ( object_probabilities.find(object) != object_probabilities.end() ) {
147  return object_probabilities[object];
148  } else {
149  cout << "returning 0" << endl;
150  return 0.f;
151  }
152  }
153 }
154 
155 /** P(u, v| object).
156  * Get a-priori probability.
157  * @param u YUV U-value
158  * @param v YUV V-value
159  * @param object object.
160  * @return probability
161  */
162 float
164  unsigned int v,
165  hint_t object)
166 {
167  unsigned int sum = 0;
168  for (unsigned int y = 0; y < depth; ++y) {
169  sum += histograms[object]->get_value(u, v, y);
170  }
171 
172  return ( float(sum) / float(numberOfOccurrences[object]) );
173 }
174 
175 /** P(u, v| object).
176  * Get a-priori probability.
177  * @param y YUV Y-value
178  * @param u YUV U-value
179  * @param v YUV V-value
180  * @param object object.
181  * @return probability
182  */
183 float
185  unsigned int u,
186  unsigned int v,
187  hint_t object)
188 {
189  return ( float(histograms[object]->get_value(u, v, y)) / float(numberOfOccurrences[object]) );
190 }
191 
192 /** P(object| u, v).
193  * Get a-posteriori probability.
194  * @param object objcet
195  * @param u YUV U-value
196  * @param v YUV V-value
197  * @return a posteriori probability
198  */
199 float
201  unsigned int u,
202  unsigned int v)
203 {
204  /* calculate "nenner" for bayes-formula,
205  i.e. sum up the probabilities P(u, v| object) * P(object)
206  over all objects */
207  float sumOfProbabilities = 0.0;
208  map<hint_t, Histogram*>::iterator hit;
209  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
210  sumOfProbabilities += ( getAPrioriProb(u, v, (hint_t)hit->first) * getObjectProb((hint_t)hit->first) );
211  }
212 
213  if (sumOfProbabilities != 0) {
214  return getAPrioriProb(u, v, object) * getObjectProb(object) / sumOfProbabilities;
215  }
216  else
217  return 0;
218 }
219 
220 /** P(object| u, v).
221  * Get a-posteriori probability.
222  * @param object objcet
223  * @param y YUV Y-value
224  * @param u YUV U-value
225  * @param v YUV V-value
226  * @return a posteriori probability
227  */
228 float
230  unsigned int y,
231  unsigned int u,
232  unsigned int v)
233 {
234  /* calculate "nenner" for bayes-formula,
235  i.e. sum up the probabilities P(u, v| object) * P(object)
236  over all objects */
237  float sumOfProbabilities = 0.0;
238  map<hint_t, Histogram*>::iterator hit;
239  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
240  sumOfProbabilities += ( getAPrioriProb(y, u, v, (hint_t)hit->first) * getObjectProb((hint_t)hit->first) );
241  }
242 
243  if (sumOfProbabilities != 0) {
244  return getAPrioriProb(y, u, v, object) * getObjectProb(object) / sumOfProbabilities;
245  }
246  else
247  return 0;
248 }
249 
250 /** Get most likely object.
251  * @param u YUV U-value
252  * @param v YUV V-value
253  * @return most likely object for this color
254  */
255 hint_t
257  unsigned int v)
258 {
259  // TODO sum over all y-values
260 
261  hint_t mostLikelyObject = H_UNKNOWN;
262  float probOfMostLikelyObject = 0.0;
263  map<hint_t, Histogram*>::iterator hit;
264  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
265  float tmp = getAPosterioriProb((hint_t)hit->first, u, v);
266 
267  if (tmp > probOfMostLikelyObject) {
268  probOfMostLikelyObject = tmp;
269  mostLikelyObject = (hint_t)hit->first;
270  }
271  }
272 
273  if (probOfMostLikelyObject > min_probability) {
274  return mostLikelyObject;
275  }
276  else {
277  return H_UNKNOWN;
278  }
279 }
280 
281 /** Get most likely object.
282  * @param y YUV Y-value
283  * @param u YUV U-value
284  * @param v YUV V-value
285  * @return most likely object for this color
286  */
287 hint_t
289  unsigned int u,
290  unsigned int v)
291 {
292  hint_t mostLikelyObject = H_UNKNOWN;
293  float probOfMostLikelyObject = 0.0;
294  map<hint_t, Histogram*>::iterator hit;
295  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
296  float tmp = getAPosterioriProb((hint_t)hit->first, y, u, v);
297 
298  if (tmp > probOfMostLikelyObject) {
299  probOfMostLikelyObject = tmp;
300  mostLikelyObject = (hint_t)hit->first;
301  }
302  }
303 
304  if (probOfMostLikelyObject > min_probability) {
305  return mostLikelyObject;
306  }
307  else {
308  return H_UNKNOWN;
309  }
310 }
311 
312 /** Calculate all LUT colors. */
313 void
315 {
316  // for each histogram, sum up all of its entries
317  // numberOfOccurrences.resize( histograms.size() );
318  map<hint_t, Histogram*>::iterator hit;
319  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
320  unsigned int total = 0;
321  for (unsigned int v = 0; v < height; ++v) {
322  for (unsigned int u = 0; u < width; ++u) {
323  for (unsigned int y = 0; y < depth; ++y) {
324  unsigned int tmp = ((Histogram*)(hit->second))->get_value(u, v, y);
325  if (tmp > 0)
326  total += tmp;
327  }
328  }
329  }
330  numberOfOccurrences[ (hint_t)hit->first ] = total;
331  }
332 
333  /*
334  cout << "histo-BALL : " << numberOfOccurrences[0] << " counts." << endl
335  << "histo-GREEN: " << numberOfOccurrences[3] << " counts." << endl
336  << "histo-BLUE : " << numberOfOccurrences[5] << " counts." << endl;
337  */
338 
339  // for each color, mark it (in lut) as the color
340  // that has the highest probability (among all histograms)
341  hint_t color_with_highest_prob;
342  float highest_prob;
343  float current_prob;
344  for (unsigned int y = 0; y < depth; ++y) {
345  unsigned int y_index = y * lut->deepness() / lut->depth();
346  for (unsigned int v = 0; v < height; ++v) {
347  for (unsigned int u = 0; u < width; ++u) {
348 
349  // find most probable color for (u, v)
350  highest_prob = 0.0;
351  color_with_highest_prob = H_UNKNOWN; // ...maybe it is better to have default = H_BACKGROUND...
352  map<hint_t, Histogram*>::iterator hit;
353  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
354  // if current histogram is not empty...
355  if (numberOfOccurrences[ (hint_t)hit->first ] > 0) {
356  current_prob = float( hit->second->get_value(u, v, y) ) / float( numberOfOccurrences[ hit->first ] );
357  // if current histogram has higher probability for color (u, v),
358  // _and_ is above min_prob-threshold...
359  if ( current_prob > highest_prob &&
360  current_prob > min_probability ) {
361  // ...update color information
362  highest_prob = current_prob;
363  color_with_highest_prob = hit->first;
364  }
365  }
366  }
367 
368  // set lut value for color (u, v) to most probable color
369  lut->set(y_index, u, v, ColorObjectMap::get_instance().get(color_with_highest_prob));
370  }
371  }
372  }
373 
374 }
375 
376 
377 /** Calculate LUT values.
378  * @param penalty if true, non-ball colors are penalized
379  */
380 void
382 {
383 
384  unsigned int old_undo = 0;
385 
386  if ( penalty ) {
387  // We penalize all values, that have NOT been classified as ball
388  Histogram *histo_fg = histograms[fg_object];
389  Histogram *histo_bg = histograms[H_BACKGROUND];
390 
391  if ( histo_bg->get_num_undos() < 2 ) {
392  // No undo available for us
393  cout << "Histogram::calculateLutValues: There are not enough undos possible for background histogram, not penalizing" << endl;
394  } else {
395  unsigned int bg_median = histo_bg->get_median();
396  unsigned int bg_average = histo_bg->get_average();
397  unsigned int bg_val = 0;
398 
399  old_undo = histo_bg->switch_undo( 1 );
400 
401  cout << "Histogram: Setting low bg vals to median. median=" << bg_median
402  << " avg=" << bg_average << endl;
403 
404  for (unsigned int v = 0; v < height; ++v) {
405  for (unsigned int u = 0; u < width; ++u) {
406  for (unsigned int y = 0; y < depth; ++y) {
407 
408  if ( histo_fg->get_value(u, v, y) == 0 ) {
409  bg_val = histo_bg->get_value(u, v, y);
410  if (bg_val < bg_average) {
411  histo_bg->set_value(u, v, y, bg_average);
412  }
413  }
414  }
415  }
416  }
417  }
418  }
419 
420  /* count for each object
421  how many non-zero values its histogram has in total */
422  // numberOfOccurrences.resize(histograms.size());
423 
424  map<hint_t, Histogram*>::iterator hit;
425  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
426  unsigned int total = 0;
427  for (unsigned int y = 0; y < depth; ++y) {
428  for (unsigned int v = 0; v < height; ++v) {
429  for (unsigned int u = 0; u < width; ++u) {
430  unsigned int tmp = hit->second->get_value(u, v, y);
431  if (tmp > 0)
432  total += tmp;
433  }
434  }
435  }
436  numberOfOccurrences[hit->first] = total;
437  cout << "[" << hit->first << "]: " << numberOfOccurrences[hit->first] << " occurences" << endl;
438  }
439 
440  unsigned int total_count = 0;
441  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
442  total_count += hit->second->get_sum();
443  }
444  // cout << "Total count: " << total_count << endl;
445 
446  // Calculate overall object probabilities
447  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
448  object_probabilities[hit->first] = (float)hit->second->get_sum() / (float)total_count;
449 
450  // cout << "Setting a-priori probability for histogram " << hit->first << " to "
451  // << object_probabilities[hit->first] << endl;
452  }
453 
454 
455  unsigned int count_ball = 0;
456  unsigned int count_field = 0;
457  unsigned int count_line = 0;
458  unsigned int count_robot = 0;
459  unsigned int count_background = 0;
460  unsigned int count_goal = 0;
461  unsigned int count_unknown = 0;
462 
463  lut->reset();
464 
465  for (unsigned int y = 0; y < depth; ++y) {
466  unsigned int y_index = y * lut->deepness() / lut->depth();
467  for (unsigned int u = 0; u < width; ++u) {
468  unsigned int u_index = u * lut->deepness() / lut->width();
469  for (unsigned int v = 0; v < height; ++v) {
470  unsigned int v_index = v * lut->deepness() / lut->height();
471  hint_t mostLikelyObject = getMostLikelyObject(y, u, v);
472 
473  switch(mostLikelyObject) {
474  case H_BALL:
475  count_ball++;
476  break;
477  case H_BACKGROUND:
478  count_background++;
479  break;
480  case H_ROBOT:
481  case H_ROBOT_OPP:
482  count_robot++;
483  break;
484  case H_FIELD:
485  count_field++;
486  break;
487  case H_LINE:
488  count_line++;
489  break;
490  case H_GOAL_YELLOW:
491  case H_GOAL_BLUE:
492  count_goal++;
493  break;
494  case H_UNKNOWN:
495  count_unknown++;
496  break;
497  default:
498  cout << "(BayesHistosToLut::calculateLutValues(): Invalid object." << endl;
499  throw fawkes::Exception("BayesHistosToLut::calculateLutValues(): Invalid object.");
500  }
501  lut->set(y_index, u_index, v_index, ColorObjectMap::get_instance().get(mostLikelyObject));
502  }
503  }
504  }
505 
506  printf("d/w/h: %u/%u/%u ball: %d field: %d line: %d robot: %d goal: %d background: %d unknown: %d\n",
507  depth, width, height, count_ball, count_field, count_line,
508  count_robot, count_goal, count_background, count_unknown);
509 
510  if ( penalty ) {
511  Histogram *histo_bg = histograms[H_BACKGROUND];
512  if ( histo_bg->get_num_undos() >= 2 ) {
513  histo_bg->undo();
514  histo_bg->switch_undo( old_undo );
515  }
516  }
517 
518 
519  /*
520  // for testing: output ball colors
521  cout << " ============" << endl;
522  for (unsigned int v = 0; v < height; v++) {
523  for (unsigned int u = 0; u < width; u++) {
524  if (lut->determine(128, u, v) == BACKGROUND)
525  cout << "lut says that (" << u << ", " << v << ") is background color." << endl;
526  }
527  }
528  cout << "===============" << endl;
529  */
530 }
531 
532 /** Save LUT to file.
533  * @param file file name
534  */
535 void
537 {
538  ColormapFile cmf;
539  cmf.add_colormap(lut);
540  cmf.write(file);
541 }
542 
543 /** Save LUT to file.
544  * @param filename file name
545  */
546 void
547 BayesHistosToLut::save(std::string filename)
548 {
549  ColormapFile cmf;
550  cmf.add_colormap(lut);
551  cmf.write(filename.c_str());
552 }
553 
554 
555 /** Set min probability.
556  * @param min_prob minimum probability
557  */
558 void
560 {
561  min_probability = min_prob;
562 }
563 
564 
565 /** Set min probability for color.
566  * @param min_prob minimum probability
567  * @param hint color hint
568  */
569 void
570 BayesHistosToLut::setMinProbForColor( float min_prob, hint_t hint ) {
571  switch( hint ) {
572  case H_BALL:
573  min_prob_ball = min_prob;
574  break;
575  case H_FIELD:
576  min_prob_green = min_prob;
577  break;
578  case H_GOAL_YELLOW:
579  min_prob_yellow = min_prob;
580  break;
581  case H_GOAL_BLUE:
582  min_prob_blue = min_prob;
583  break;
584  case H_LINE:
585  min_prob_white = min_prob;
586  break;
587  case H_ROBOT:
588  min_prob_black = min_prob;
589  break;
590  default:
591  /**/
592  break;
593  }
594 }
595 
596 
597 /** Get generated color model.
598  * @return generated color model
599  */
600 YuvColormap *
602 {
603  return lut;
604 }
605 
606 } // end namespace firevision
unsigned int get_average()
Get average of all values.
Definition: histogram.cpp:534
virtual unsigned int deepness() const
Get deepness of colormap.
Definition: yuvcm.cpp:343
void saveLut(char *file)
Save LUT to file.
void add_colormap(Colormap *colormap)
Add colormap.
Definition: cmfile.cpp:98
float getAPosterioriProb(hint_t object, unsigned int u, unsigned int v)
P(object| u, v).
static const ColorObjectMap & get_instance()
ColorObjectMap getter.
void setMinProbability(float min_prob)
Set min probability.
virtual unsigned int width() const
Get width of colormap.
Definition: yuvcm.cpp:322
unsigned int get_median()
Get median of all values.
Definition: histogram.cpp:507
STL namespace.
unsigned int get_num_undos()
Get number of undos.
Definition: histogram.cpp:497
YUV Colormap.
Definition: yuvcm.h:39
std::string getName()
Get name.
void setMinProbForColor(float min_prob, hint_t hint)
Set min probability for color.
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:262
Colormap file.
Definition: cmfile.h:55
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
float getAPrioriProb(unsigned int u, unsigned int v, hint_t object)
P(u, v| object).
void set_value(unsigned int x, unsigned int y, unsigned int value)
Set value in histogram.
Definition: histogram.cpp:246
virtual void set(unsigned int y, unsigned int u, unsigned int v, color_t c)
Set color class for given YUV value.
Definition: yuvcm.cpp:182
void calculateLutValues(bool penalty=false)
Calculate LUT values.
void save(std::string filename)
Save LUT to file.
float getObjectProb(hint_t object)
Get object probability.
virtual unsigned int depth() const
Get depth of colormap.
Definition: yuvcm.cpp:336
void calculateLutAllColors()
Calculate all LUT colors.
YuvColormap * get_colormap()
Get generated color model.
hint_t getMostLikelyObject(unsigned int u, unsigned int v)
Get most likely object.
virtual void reset()
Reset colormap.
Definition: yuvcm.cpp:189
unsigned int switch_undo(unsigned int undo_id)
Switch undo to another undo buffer.
Definition: histogram.cpp:479
virtual unsigned int height() const
Get height of colormap.
Definition: yuvcm.cpp:329