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 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 object, unsigned int w, unsigned int h)
67  : histograms(histos)
68 {
69  width = w;
70  height = h;
71  depth = d;
72 
73  fg_object = object;
74  // histograms = histos;
75 
76  // no as shmem segment
77  lut = new YuvColormap(depth, width, height);
78 
79  min_probability = 0.3;
80  min_prob_ball = 0.0;
81  min_prob_green = 0.0;
82  min_prob_yellow = 0.0;
83  min_prob_blue = 0.0;
84  min_prob_white = 0.0;
85  min_prob_black = 0.0;
86 }
87 
88 /** Destructor. */
90 {
91  delete lut;
92 }
93 
94 /** Get name.
95  * @return BayesHistosToLut
96  */
97 string
99 {
100  return string("BayesHistosToLut");
101 }
102 
103 /** Get object probability.
104  * @param object object
105  * @return probability.
106  */
107 float
109 {
110  // These object probabilities should better be read from config file.
111 
112  if (fg_object == H_BALL) {
113  /*
114  switch (object) {
115  case H_BALL:
116  */
117  return 0.2;
118  /*
119  break;
120  case H_BACKGROUND:
121  return 0.8;
122  break;
123  case H_ROBOT:
124  return 0.0;
125  break;
126  case H_FIELD:
127  return 0.0;
128  break;
129  case H_GOAL_BLUE:
130  return 0.0;
131  break;
132  case H_GOAL_YELLOW:
133  return 0.0;
134  break;
135  case H_LINE:
136  return 0.0;
137  break;
138  case H_UNKNOWN:
139  return 0.0;
140  break;
141  default:
142  cout << "(BayesHistosToLut::getObjectProb): Invalid object." << endl;
143  exit(-1);
144  return 0.0f;
145  break;
146  }
147  */
148  } else {
149  if ( object_probabilities.find(object) != object_probabilities.end() ) {
150  return object_probabilities[object];
151  } else {
152  cout << "returning 0" << endl;
153  return 0.f;
154  }
155  }
156 }
157 
158 /** P(u, v| object).
159  * Get a-priori probability.
160  * @param u YUV U-value
161  * @param v YUV V-value
162  * @param object object.
163  * @return probability
164  */
165 float
167  unsigned int v,
168  hint_t object)
169 {
170  unsigned int sum = 0;
171  for (unsigned int y = 0; y < depth; ++y) {
172  sum += histograms[object]->get_value(u, v, y);
173  }
174 
175  return ( float(sum) / float(numberOfOccurrences[object]) );
176 }
177 
178 /** P(u, v| object).
179  * Get a-priori probability.
180  * @param y YUV Y-value
181  * @param u YUV U-value
182  * @param v YUV V-value
183  * @param object object.
184  * @return probability
185  */
186 float
188  unsigned int u,
189  unsigned int v,
190  hint_t object)
191 {
192  return ( float(histograms[object]->get_value(u, v, y)) / float(numberOfOccurrences[object]) );
193 }
194 
195 /** P(object| u, v).
196  * Get a-posteriori probability.
197  * @param object objcet
198  * @param u YUV U-value
199  * @param v YUV V-value
200  * @return a posteriori probability
201  */
202 float
204  unsigned int u,
205  unsigned int v)
206 {
207  /* calculate "nenner" for bayes-formula,
208  i.e. sum up the probabilities P(u, v| object) * P(object)
209  over all objects */
210  float sumOfProbabilities = 0.0;
211  map<hint_t, Histogram*>::iterator hit;
212  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
213  sumOfProbabilities += ( getAPrioriProb(u, v, (hint_t)hit->first) * getObjectProb((hint_t)hit->first) );
214  }
215 
216  if (sumOfProbabilities != 0) {
217  return getAPrioriProb(u, v, object) * getObjectProb(object) / sumOfProbabilities;
218  }
219  else
220  return 0;
221 }
222 
223 /** P(object| u, v).
224  * Get a-posteriori probability.
225  * @param object objcet
226  * @param y YUV Y-value
227  * @param u YUV U-value
228  * @param v YUV V-value
229  * @return a posteriori probability
230  */
231 float
233  unsigned int y,
234  unsigned int u,
235  unsigned int v)
236 {
237  /* calculate "nenner" for bayes-formula,
238  i.e. sum up the probabilities P(u, v| object) * P(object)
239  over all objects */
240  float sumOfProbabilities = 0.0;
241  map<hint_t, Histogram*>::iterator hit;
242  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
243  sumOfProbabilities += ( getAPrioriProb(y, u, v, (hint_t)hit->first) * getObjectProb((hint_t)hit->first) );
244  }
245 
246  if (sumOfProbabilities != 0) {
247  return getAPrioriProb(y, u, v, object) * getObjectProb(object) / sumOfProbabilities;
248  }
249  else
250  return 0;
251 }
252 
253 /** Get most likely object.
254  * @param u YUV U-value
255  * @param v YUV V-value
256  * @return most likely object for this color
257  */
258 hint_t
260  unsigned int v)
261 {
262  // TODO sum over all y-values
263 
264  hint_t mostLikelyObject = H_UNKNOWN;
265  float probOfMostLikelyObject = 0.0;
266  map<hint_t, Histogram*>::iterator hit;
267  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
268  float tmp = getAPosterioriProb((hint_t)hit->first, u, v);
269 
270  if (tmp > probOfMostLikelyObject) {
271  probOfMostLikelyObject = tmp;
272  mostLikelyObject = (hint_t)hit->first;
273  }
274  }
275 
276  if (probOfMostLikelyObject > min_probability) {
277  return mostLikelyObject;
278  }
279  else {
280  return H_UNKNOWN;
281  }
282 }
283 
284 /** Get most likely object.
285  * @param y YUV Y-value
286  * @param u YUV U-value
287  * @param v YUV V-value
288  * @return most likely object for this color
289  */
290 hint_t
292  unsigned int u,
293  unsigned int v)
294 {
295  hint_t mostLikelyObject = H_UNKNOWN;
296  float probOfMostLikelyObject = 0.0;
297  map<hint_t, Histogram*>::iterator hit;
298  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
299  float tmp = getAPosterioriProb((hint_t)hit->first, y, u, v);
300 
301  if (tmp > probOfMostLikelyObject) {
302  probOfMostLikelyObject = tmp;
303  mostLikelyObject = (hint_t)hit->first;
304  }
305  }
306 
307  if (probOfMostLikelyObject > min_probability) {
308  return mostLikelyObject;
309  }
310  else {
311  return H_UNKNOWN;
312  }
313 }
314 
315 /** Calculate all LUT colors. */
316 void
318 {
319  // for each histogram, sum up all of its entries
320  // numberOfOccurrences.resize( histograms.size() );
321  map<hint_t, Histogram*>::iterator hit;
322  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
323  unsigned int total = 0;
324  for (unsigned int v = 0; v < height; ++v) {
325  for (unsigned int u = 0; u < width; ++u) {
326  for (unsigned int y = 0; y < depth; ++y) {
327  unsigned int tmp = ((Histogram*)(hit->second))->get_value(u, v, y);
328  if (tmp > 0)
329  total += tmp;
330  }
331  }
332  }
333  numberOfOccurrences[ (hint_t)hit->first ] = total;
334  }
335 
336  /*
337  cout << "histo-BALL : " << numberOfOccurrences[0] << " counts." << endl
338  << "histo-GREEN: " << numberOfOccurrences[3] << " counts." << endl
339  << "histo-BLUE : " << numberOfOccurrences[5] << " counts." << endl;
340  */
341 
342  // for each color, mark it (in lut) as the color
343  // that has the highest probability (among all histograms)
344  hint_t color_with_highest_prob;
345  float highest_prob;
346  float current_prob;
347  for (unsigned int y = 0; y < depth; ++y) {
348  unsigned int y_index = y * lut->deepness() / lut->depth();
349  for (unsigned int v = 0; v < height; ++v) {
350  for (unsigned int u = 0; u < width; ++u) {
351 
352  // find most probable color for (u, v)
353  highest_prob = 0.0;
354  color_with_highest_prob = H_UNKNOWN; // ...maybe it is better to have default = H_BACKGROUND...
355  map<hint_t, Histogram*>::iterator hit;
356  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
357  // if current histogram is not empty...
358  if (numberOfOccurrences[ (hint_t)hit->first ] > 0) {
359  current_prob = float( hit->second->get_value(u, v, y) ) / float( numberOfOccurrences[ hit->first ] );
360  // if current histogram has higher probability for color (u, v),
361  // _and_ is above min_prob-threshold...
362  if ( current_prob > highest_prob &&
363  current_prob > min_probability ) {
364  // ...update color information
365  highest_prob = current_prob;
366  color_with_highest_prob = hit->first;
367  }
368  }
369  }
370 
371  // set lut value for color (u, v) to most probable color
372  lut->set(y_index, u, v, ColorObjectMap::get_instance().get(color_with_highest_prob));
373  }
374  }
375  }
376 
377 }
378 
379 
380 /** Calculate LUT values.
381  * @param penalty if true, non-ball colors are penalized
382  */
383 void
385 {
386 
387  unsigned int old_undo = 0;
388 
389  if ( penalty ) {
390  // We penalize all values, that have NOT been classified as ball
391  Histogram *histo_fg = histograms[fg_object];
392  Histogram *histo_bg = histograms[H_BACKGROUND];
393 
394  if ( histo_bg->get_num_undos() < 2 ) {
395  // No undo available for us
396  cout << "Histogram::calculateLutValues: There are not enough undos possible for background histogram, not penalizing" << endl;
397  } else {
398  unsigned int bg_median = histo_bg->get_median();
399  unsigned int bg_average = histo_bg->get_average();
400  unsigned int bg_val = 0;
401 
402  old_undo = histo_bg->switch_undo( 1 );
403 
404  cout << "Histogram: Setting low bg vals to median. median=" << bg_median
405  << " avg=" << bg_average << endl;
406 
407  for (unsigned int v = 0; v < height; ++v) {
408  for (unsigned int u = 0; u < width; ++u) {
409  for (unsigned int y = 0; y < depth; ++y) {
410 
411  if ( histo_fg->get_value(u, v, y) == 0 ) {
412  bg_val = histo_bg->get_value(u, v, y);
413  if (bg_val < bg_average) {
414  histo_bg->set_value(u, v, y, bg_average);
415  }
416  }
417  }
418  }
419  }
420  }
421  }
422 
423  /* count for each object
424  how many non-zero values its histogram has in total */
425  // numberOfOccurrences.resize(histograms.size());
426 
427  map<hint_t, Histogram*>::iterator hit;
428  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
429  unsigned int total = 0;
430  for (unsigned int y = 0; y < depth; ++y) {
431  for (unsigned int v = 0; v < height; ++v) {
432  for (unsigned int u = 0; u < width; ++u) {
433  unsigned int tmp = hit->second->get_value(u, v, y);
434  if (tmp > 0)
435  total += tmp;
436  }
437  }
438  }
439  numberOfOccurrences[hit->first] = total;
440  cout << "[" << hit->first << "]: " << numberOfOccurrences[hit->first] << " occurences" << endl;
441  }
442 
443  unsigned int total_count = 0;
444  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
445  total_count += hit->second->get_sum();
446  }
447  // cout << "Total count: " << total_count << endl;
448 
449  // Calculate overall object probabilities
450  for (hit = histograms.begin(); hit != histograms.end(); hit++) {
451  object_probabilities[hit->first] = (float)hit->second->get_sum() / (float)total_count;
452 
453  // cout << "Setting a-priori probability for histogram " << hit->first << " to "
454  // << object_probabilities[hit->first] << endl;
455  }
456 
457 
458  unsigned int count_ball = 0;
459  unsigned int count_field = 0;
460  unsigned int count_line = 0;
461  unsigned int count_robot = 0;
462  unsigned int count_background = 0;
463  unsigned int count_goal = 0;
464  unsigned int count_unknown = 0;
465 
466  lut->reset();
467 
468  for (unsigned int y = 0; y < depth; ++y) {
469  unsigned int y_index = y * lut->deepness() / lut->depth();
470  for (unsigned int u = 0; u < width; ++u) {
471  unsigned int u_index = u * lut->deepness() / lut->width();
472  for (unsigned int v = 0; v < height; ++v) {
473  unsigned int v_index = v * lut->deepness() / lut->height();
474  hint_t mostLikelyObject = getMostLikelyObject(y, u, v);
475 
476  switch(mostLikelyObject) {
477  case H_BALL:
478  count_ball++;
479  break;
480  case H_BACKGROUND:
481  count_background++;
482  break;
483  case H_ROBOT:
484  case H_ROBOT_OPP:
485  count_robot++;
486  break;
487  case H_FIELD:
488  count_field++;
489  break;
490  case H_LINE:
491  count_line++;
492  break;
493  case H_GOAL_YELLOW:
494  case H_GOAL_BLUE:
495  count_goal++;
496  break;
497  case H_UNKNOWN:
498  count_unknown++;
499  break;
500  default:
501  cout << "(BayesHistosToLut::calculateLutValues(): Invalid object." << endl;
502  throw fawkes::Exception("BayesHistosToLut::calculateLutValues(): Invalid object.");
503  }
504  lut->set(y_index, u_index, v_index, ColorObjectMap::get_instance().get(mostLikelyObject));
505  }
506  }
507  }
508 
509  printf("d/w/h: %u/%u/%u ball: %d field: %d line: %d robot: %d goal: %d background: %d unknown: %d\n",
510  depth, width, height, count_ball, count_field, count_line,
511  count_robot, count_goal, count_background, count_unknown);
512 
513  if ( penalty ) {
514  Histogram *histo_bg = histograms[H_BACKGROUND];
515  if ( histo_bg->get_num_undos() >= 2 ) {
516  histo_bg->undo();
517  histo_bg->switch_undo( old_undo );
518  }
519  }
520 
521 
522  /*
523  // for testing: output ball colors
524  cout << " ============" << endl;
525  for (unsigned int v = 0; v < height; v++) {
526  for (unsigned int u = 0; u < width; u++) {
527  if (lut->determine(128, u, v) == BACKGROUND)
528  cout << "lut says that (" << u << ", " << v << ") is background color." << endl;
529  }
530  }
531  cout << "===============" << endl;
532  */
533 }
534 
535 /** Save LUT to file.
536  * @param file file name
537  */
538 void
540 {
541  ColormapFile cmf;
542  cmf.add_colormap(lut);
543  cmf.write(file);
544 }
545 
546 /** Save LUT to file.
547  * @param filename file name
548  */
549 void
550 BayesHistosToLut::save(std::string filename)
551 {
552  ColormapFile cmf;
553  cmf.add_colormap(lut);
554  cmf.write(filename.c_str());
555 }
556 
557 
558 /** Set min probability.
559  * @param min_prob minimum probability
560  */
561 void
563 {
564  min_probability = min_prob;
565 }
566 
567 
568 /** Set min probability for color.
569  * @param min_prob minimum probability
570  * @param hint color hint
571  */
572 void
573 BayesHistosToLut::setMinProbForColor( float min_prob, hint_t hint ) {
574  switch( hint ) {
575  case H_BALL:
576  min_prob_ball = min_prob;
577  break;
578  case H_FIELD:
579  min_prob_green = min_prob;
580  break;
581  case H_GOAL_YELLOW:
582  min_prob_yellow = min_prob;
583  break;
584  case H_GOAL_BLUE:
585  min_prob_blue = min_prob;
586  break;
587  case H_LINE:
588  min_prob_white = min_prob;
589  break;
590  case H_ROBOT:
591  min_prob_black = min_prob;
592  break;
593  default:
594  /**/
595  break;
596  }
597 }
598 
599 
600 /** Get generated color model.
601  * @return generated color model
602  */
603 YuvColormap *
605 {
606  return lut;
607 }
608 
609 } // end namespace firevision
virtual unsigned int width() const
Get width of colormap.
Definition: yuvcm.cpp:322
unsigned int get_average()
Get average of all values.
Definition: histogram.cpp:534
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 height() const
Get height of colormap.
Definition: yuvcm.cpp:329
unsigned int get_median()
Get median of all values.
Definition: histogram.cpp:507
virtual unsigned int depth() const
Get depth of colormap.
Definition: yuvcm.cpp:336
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
virtual unsigned int deepness() const
Get deepness of colormap.
Definition: yuvcm.cpp:343
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.
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