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
36using namespace std;
37using namespace fawkes;
38
39namespace 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 */
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. */
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 */
96void
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 */
117void
118BayesColormapGenerator::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 */
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 */
147bool
148BayesColormapGenerator::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 */
156void
157BayesColormapGenerator::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 */
184void
186{
187 bhtl->setMinProbability(min_prob);
188}
189
190/** Consider current image. */
191void
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. */
233void
235{
236 normalize_histos();
237 bhtl->calculateLutValues(false /* no penalty*/);
238}
239
240/** Undo last inclusion. */
241void
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. */
258void
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. */
281void
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 */
300bool
302{
303 return true;
304}
305
306/** Get histograms.
307 * @return histograms
308 */
309std::map<hint_t, Histogram *> *
311{
312 return &histos;
313}
314
315/** Load histogram from a file.
316 * @param filename the filename
317 */
318void
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 */
428void
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. */
447void
448BayesColormapGenerator::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
virtual void reset_undo()
Reset undo.
virtual void set_selection(std::vector< fawkes::rectangle_t > region)
Set selection.
virtual void save_histograms(const char *filename)
Save histograms to a file.
virtual void load_histograms(const char *filename)
Load histogram from a file.
virtual YuvColormap * get_current()
Get current color model.
virtual std::map< hint_t, Histogram * > * get_histograms()
Get histograms.
virtual void undo()
Undo last inclusion.
void set_min_probability(float min_prob)
Set min probability.
BayesColormapGenerator(unsigned int lut_depth=1, hint_t fg_object=H_UNKNOWN, unsigned int lut_width=256, unsigned int lut_height=256)
Constructor.
virtual void reset()
Reset color model.
virtual void set_fg_object(hint_t object)
Set foreground object.
virtual void set_buffer(unsigned char *buffer, unsigned int width, unsigned int height)
Set buffer.
virtual bool has_histograms()
Check if this color model uses histograms.
virtual void consider()
Consider current image.
LUT generation by using Bayesian method on histograms.
YuvColormap * get_colormap()
Get generated color model.
void calculateLutValues(bool penalty=false)
Calculate LUT values.
void setMinProbability(float min_prob)
Set min probability.
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
virtual void reset()
Reset colormap.
Definition: yuvcm.cpp:200
Fawkes library namespace.