00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <tools/firestation/color_train_widget.h>
00024 #include <tools/firestation/colormap_viewer_widget.h>
00025 #include <fvutils/color/yuv.h>
00026 #include <fvutils/color/zauberstab.h>
00027 #include <fvutils/color/colorspaces.h>
00028 #include <fvutils/color/conversions.h>
00029 #include <fvutils/draw/drawer.h>
00030 #include <fvutils/scalers/lossy.h>
00031 #include <fvutils/colormap/bayes/bayes_generator.h>
00032 #include <fvutils/colormap/yuvcm.h>
00033 #include <fvutils/colormap/cmfile.h>
00034
00035 #include <fvutils/writers/jpeg.h>
00036
00037 #include <fvutils/color/color_object_map.h>
00038
00039 #include <core/exceptions/software.h>
00040
00041 using namespace firevision;
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 ColorTrainWidget::ColorTrainWidget(Gtk::Window* parent)
00053 {
00054 m_generator = 0;
00055 m_zauberstab = new Zauberstab();
00056 m_cvw = new ColormapViewerWidget();
00057
00058 m_src_buffer = 0;
00059 m_draw_buffer = 0;
00060
00061 m_wnd_parent = parent;
00062 m_btn_reset_selection = 0;
00063 m_btn_add_to_colormap = 0;
00064 m_btn_reset_colormap = 0;
00065 m_btn_load_histos = 0;
00066 m_btn_save_histos = 0;
00067 m_btn_load_colormap = 0;
00068 m_btn_save_colormap = 0;
00069 m_spbtn_cm_depth = 0;
00070 m_spbtn_cm_width = 0;
00071 m_spbtn_cm_height = 0;
00072 m_img_segmentation = 0;
00073 m_scl_threshold = 0;
00074 m_scl_min_prob = 0;
00075 m_fcd_filechooser = 0;
00076 }
00077
00078
00079 ColorTrainWidget::~ColorTrainWidget()
00080 {
00081 delete m_cvw;
00082 delete m_generator;
00083 delete m_zauberstab;
00084 }
00085
00086
00087
00088
00089 void
00090 ColorTrainWidget::set_fg_object(hint_t fg_object)
00091 {
00092 m_fg_object = fg_object;
00093 }
00094
00095
00096
00097
00098
00099
00100 void
00101 ColorTrainWidget::set_src_buffer(unsigned char* yuv422_buffer,
00102 unsigned int img_width, unsigned int img_height)
00103 {
00104 m_img_width = img_width;
00105 m_img_height = img_height;
00106 m_src_buffer = yuv422_buffer;
00107 m_img_cs = YUV422_PLANAR;
00108 m_img_size = colorspace_buffer_size( m_img_cs, m_img_width, m_img_height );
00109
00110 if (yuv422_buffer)
00111 {
00112 m_zauberstab->deleteRegion();
00113 m_zauberstab->setBuffer(m_src_buffer, m_img_width, m_img_height);
00114 m_zauberstab->setThreshold(10);
00115 }
00116 else
00117 {
00118 m_img_segmentation->clear();
00119 m_img_segmentation->set("gtk-missing-image");
00120 }
00121 }
00122
00123
00124
00125
00126
00127
00128 void
00129 ColorTrainWidget::set_draw_buffer(unsigned char* buffer)
00130 {
00131 m_draw_buffer = buffer;
00132 }
00133
00134
00135
00136
00137
00138
00139 void
00140 ColorTrainWidget::click(unsigned int x, unsigned int y, unsigned int button)
00141 {
00142 if (m_src_buffer == 0 || m_draw_buffer == 0)
00143 { return; }
00144
00145 if ( m_zauberstab->isEmptyRegion() )
00146 {
00147 if (button == MOUSE_BUTTON_LEFT)
00148 {
00149 m_zauberstab->findRegion(x, y);
00150 }
00151 }
00152 else
00153 {
00154 if (button == MOUSE_BUTTON_LEFT)
00155 {
00156 m_zauberstab->addRegion(x, y);
00157 }
00158
00159 if (button == MOUSE_BUTTON_RIGHT)
00160 {
00161 m_zauberstab->deleteRegion(x, y);
00162 }
00163 }
00164
00165 memcpy(m_draw_buffer, m_src_buffer, m_img_size);
00166
00167 ZRegion *region = m_zauberstab->getRegion();
00168 Drawer *d = new Drawer();
00169 d->set_buffer( m_draw_buffer, m_img_width, m_img_height );
00170
00171 for (unsigned int s = 0; s < region->slices->size(); s++)
00172 {
00173 d->draw_rectangle_inverted( region->slices->at(s)->leftX,
00174 region->slices->at(s)->y,
00175 region->slices->at(s)->rightX - region->slices->at(s)->leftX,
00176 1 );
00177 }
00178
00179 delete d;
00180
00181 m_signal_update_image();
00182 }
00183
00184
00185 void
00186 ColorTrainWidget::reset_selection()
00187 {
00188 if (m_zauberstab)
00189 { m_zauberstab->deleteRegion(); }
00190
00191 if( m_src_buffer && m_draw_buffer )
00192 { memcpy(m_draw_buffer, m_src_buffer, m_img_size); }
00193
00194 m_signal_update_image();
00195 }
00196
00197
00198
00199
00200 void
00201 ColorTrainWidget::set_reset_selection_btn(Gtk::Button* btn)
00202 {
00203 m_btn_reset_selection = btn;
00204 m_btn_reset_selection->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::reset_selection) );
00205 }
00206
00207
00208
00209
00210 void
00211 ColorTrainWidget::set_add_to_colormap_btn(Gtk::Button* btn)
00212 {
00213 m_btn_add_to_colormap = btn;
00214 m_btn_add_to_colormap->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::add_to_colormap) );
00215 }
00216
00217
00218
00219
00220 void
00221 ColorTrainWidget::set_reset_colormap_btn(Gtk::Button* btn)
00222 {
00223 m_btn_reset_colormap = btn;
00224 m_btn_reset_colormap->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::reset_colormap) );
00225 }
00226
00227
00228
00229
00230 void
00231 ColorTrainWidget::set_load_histos_btn(Gtk::Button* btn)
00232 {
00233 m_btn_load_histos = btn;
00234 m_btn_load_histos->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::load_histograms) );
00235 }
00236
00237
00238
00239
00240 void
00241 ColorTrainWidget::set_save_histos_btn(Gtk::Button* btn)
00242 {
00243 m_btn_save_histos = btn;
00244 m_btn_save_histos->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::save_histograms) );
00245 }
00246
00247
00248
00249
00250 void
00251 ColorTrainWidget::set_load_colormap_btn(Gtk::Button* btn)
00252 {
00253 m_btn_load_colormap = btn;
00254 m_btn_load_colormap->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::load_colormap) );
00255 }
00256
00257
00258
00259
00260 void
00261 ColorTrainWidget::set_save_colormap_btn(Gtk::Button* btn)
00262 {
00263 m_btn_save_colormap = btn;
00264 m_btn_save_colormap->signal_clicked().connect( sigc::mem_fun(*this, &ColorTrainWidget::save_colormap) );
00265 }
00266
00267
00268
00269
00270 void
00271 ColorTrainWidget::set_colormap_img(Gtk::Image* img)
00272 {
00273 m_cvw->set_colormap_img(img);
00274 }
00275
00276
00277
00278
00279 void
00280 ColorTrainWidget::set_segmentation_img(Gtk::Image* img)
00281 {
00282 m_img_segmentation = img;
00283 m_seg_img_max_width = m_img_segmentation->get_width();
00284 m_seg_img_max_height = m_img_segmentation->get_height();
00285 m_img_segmentation->signal_size_allocate().connect( sigc::mem_fun( *this, &ColorTrainWidget::resize_seg_image) );
00286 }
00287
00288 void
00289 ColorTrainWidget::resize_seg_image(Gtk::Allocation& allocation)
00290 {
00291 unsigned int new_width = (unsigned int) allocation.get_width();
00292 unsigned int new_height = (unsigned int) allocation.get_height();
00293
00294 if (new_width != m_seg_img_max_width || new_height != m_seg_img_max_height)
00295 {
00296 m_seg_img_max_width = new_width;
00297 m_seg_img_max_height = new_height;
00298 draw_segmentation_result();
00299 }
00300 }
00301
00302
00303
00304
00305 void
00306 ColorTrainWidget::set_threshold_scl(Gtk::Scale* scl)
00307 {
00308 m_scl_threshold = scl;
00309 m_scl_threshold->signal_change_value().connect( sigc::mem_fun(*this, &ColorTrainWidget::set_threshold) );
00310 }
00311
00312
00313
00314
00315 void
00316 ColorTrainWidget::set_min_prob_scl(Gtk::Scale* scl)
00317 {
00318 m_scl_min_prob = scl;
00319 m_scl_min_prob->signal_change_value().connect( sigc::mem_fun(*this, &ColorTrainWidget::set_min_prob) );
00320 }
00321
00322
00323
00324
00325 void
00326 ColorTrainWidget::set_filechooser_dlg(Gtk::FileChooserDialog* dlg)
00327 {
00328 m_fcd_filechooser = dlg;
00329 }
00330
00331
00332
00333
00334 void
00335 ColorTrainWidget::set_cm_layer_selector(Gtk::Scale* scl)
00336 {
00337 m_cvw->set_layer_selector(scl);
00338 }
00339
00340
00341
00342
00343
00344
00345 void
00346 ColorTrainWidget::set_cm_selector(Gtk::SpinButton* depth, Gtk::SpinButton* width, Gtk::SpinButton* height)
00347 {
00348 m_spbtn_cm_depth = depth;
00349 m_spbtn_cm_width = width;
00350 m_spbtn_cm_height = height;
00351 }
00352
00353
00354
00355
00356 Glib::Dispatcher&
00357 ColorTrainWidget::update_image()
00358 {
00359 return m_signal_update_image;
00360 }
00361
00362
00363
00364
00365 Glib::Dispatcher&
00366 ColorTrainWidget::colormap_updated()
00367 {
00368 return m_signal_colormap_updated;
00369 }
00370
00371
00372 void
00373 ColorTrainWidget::load_histograms()
00374 {
00375 if ( !m_fcd_filechooser )
00376 { return; }
00377
00378 m_fcd_filechooser->set_title("Load histograms");
00379 m_fcd_filechooser->set_action(Gtk::FILE_CHOOSER_ACTION_OPEN);
00380
00381 m_fcd_filechooser->set_transient_for(*m_wnd_parent);
00382
00383 int result = m_fcd_filechooser->run();
00384
00385 switch(result)
00386 {
00387 case (Gtk::RESPONSE_OK):
00388 {
00389 std::string filename = m_fcd_filechooser->get_filename();
00390 if (!m_generator)
00391 { m_generator = new BayesColormapGenerator(); }
00392 m_generator->load_histograms( filename.c_str() );
00393 m_generator->calc();
00394 m_signal_colormap_updated();
00395
00396 YuvColormap *cur = m_generator->get_current();
00397 if (m_spbtn_cm_depth) m_spbtn_cm_depth->set_value(log(cur->depth()) / log(2));
00398 if (m_spbtn_cm_width) m_spbtn_cm_width->set_value(log(cur->width()) / log(2));
00399 if (m_spbtn_cm_height) m_spbtn_cm_height->set_value(log(cur->height()) / log(2));
00400
00401 m_cvw->set_colormap(cur);
00402 m_cvw->draw();
00403 draw_segmentation_result();
00404 break;
00405 }
00406
00407 case (Gtk::RESPONSE_CANCEL):
00408 break;
00409
00410 default:
00411 break;
00412 }
00413
00414 m_fcd_filechooser->hide();
00415 }
00416
00417
00418 void
00419 ColorTrainWidget::save_histograms()
00420 {
00421 if ( !m_fcd_filechooser )
00422 { return; }
00423
00424 m_fcd_filechooser->set_title("Save histograms");
00425 m_fcd_filechooser->set_action(Gtk::FILE_CHOOSER_ACTION_SAVE);
00426
00427 m_fcd_filechooser->set_transient_for(*m_wnd_parent);
00428
00429 int result = m_fcd_filechooser->run();
00430
00431 switch(result)
00432 {
00433 case (Gtk::RESPONSE_OK):
00434 {
00435 std::string filename = m_fcd_filechooser->get_filename();
00436 m_generator->save_histograms( filename.c_str() );
00437 break;
00438 }
00439
00440 case (Gtk::RESPONSE_CANCEL):
00441 break;
00442
00443 default:
00444 break;
00445 }
00446
00447 m_fcd_filechooser->hide();
00448 }
00449
00450
00451 void
00452 ColorTrainWidget::add_to_colormap()
00453 {
00454 if ( !m_src_buffer )
00455 { return; }
00456
00457 unsigned int cm_depth;
00458 if (m_spbtn_cm_depth)
00459 { cm_depth = (unsigned int) rint( pow(2.0, m_spbtn_cm_depth->get_value()) ); }
00460 else
00461 { cm_depth = 1; }
00462
00463 unsigned int cm_width;
00464 if (m_spbtn_cm_width)
00465 { cm_width = (unsigned int) rint( pow(2.0, m_spbtn_cm_width->get_value()) ); }
00466 else
00467 { cm_width = 256; }
00468
00469 unsigned int cm_height;
00470 if (m_spbtn_cm_height)
00471 { cm_height = (unsigned int) rint( pow(2.0, m_spbtn_cm_height->get_value()) ); }
00472 else
00473 { cm_height = 256; }
00474
00475 if ( !m_generator
00476 || cm_depth != m_generator->get_current()->depth()
00477 || cm_width != m_generator->get_current()->width()
00478 || cm_height != m_generator->get_current()->height())
00479 {
00480 delete m_generator;
00481 m_generator = new BayesColormapGenerator(cm_depth, H_UNKNOWN, cm_width, cm_height);
00482 m_cvw->set_colormap( m_generator->get_current() );
00483 }
00484
00485 if (m_fg_object == H_UNKNOWN)
00486 {
00487 printf("CTW::add_to_colormap(): no fg object set\n");
00488 return;
00489 }
00490
00491 m_generator->set_fg_object(m_fg_object);
00492 m_generator->reset_undo();
00493 m_generator->set_buffer(m_src_buffer, m_img_width, m_img_height);
00494 m_generator->set_selection( m_zauberstab->getSelection() );
00495 m_generator->consider();
00496 m_generator->calc();
00497 m_signal_colormap_updated();
00498
00499
00500 m_cvw->draw(-1);
00501
00502
00503 draw_segmentation_result();
00504 }
00505
00506
00507 void
00508 ColorTrainWidget::reset_colormap()
00509 {
00510 Gtk::MessageDialog dialog(*m_wnd_parent, "Are you sure you want to reset the colormap?",
00511 false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL);
00512
00513 int result = dialog.run();
00514
00515 if (result != Gtk::RESPONSE_OK) return;
00516
00517 if (m_generator)
00518 {
00519 m_generator->reset();
00520 m_signal_colormap_updated();
00521
00522 if (m_cvw)
00523 { m_cvw->draw(); }
00524
00525 draw_segmentation_result();
00526 }
00527 }
00528
00529
00530 void
00531 ColorTrainWidget::load_colormap()
00532 {
00533 if ( !m_fcd_filechooser )
00534 { return; }
00535
00536 m_fcd_filechooser->set_title("Load colormap colormap");
00537 m_fcd_filechooser->set_action(Gtk::FILE_CHOOSER_ACTION_OPEN);
00538
00539 m_fcd_filechooser->set_transient_for(*m_wnd_parent);
00540
00541 int result = m_fcd_filechooser->run();
00542
00543 switch(result)
00544 {
00545 case (Gtk::RESPONSE_OK):
00546 {
00547 delete m_generator;
00548
00549 std::string filename = m_fcd_filechooser->get_filename();
00550 ColormapFile cmf;
00551 cmf.read(filename.c_str());
00552 Colormap *tcm = cmf.get_colormap();
00553 YuvColormap *tycm = dynamic_cast<YuvColormap *>(tcm);
00554 if ( ! tycm ) {
00555 delete tcm;
00556 throw fawkes::TypeMismatchException("File does not contain a YUV colormap");
00557 }
00558 unsigned int cm_depth = tcm->depth();
00559 unsigned int cm_width = tcm->width();
00560 unsigned int cm_height = tcm->height();
00561 m_generator = new BayesColormapGenerator(cm_depth, H_UNKNOWN, cm_width, cm_height);
00562 YuvColormap *current = m_generator->get_current();
00563 *current = *tycm;
00564 delete tcm;
00565
00566 if (m_spbtn_cm_depth) m_spbtn_cm_depth->set_value(log(cm_depth) / log(2));
00567 if (m_spbtn_cm_width) m_spbtn_cm_width->set_value(log(cm_width) / log(2));
00568 if (m_spbtn_cm_height) m_spbtn_cm_height->set_value(log(cm_height) / log(2));
00569
00570 m_signal_colormap_updated();
00571 m_cvw->set_colormap( m_generator->get_current() );
00572 m_cvw->draw();
00573 draw_segmentation_result();
00574 break;
00575 }
00576
00577 case (Gtk::RESPONSE_CANCEL):
00578 break;
00579
00580 default:
00581 break;
00582 }
00583
00584 m_fcd_filechooser->hide();
00585 }
00586
00587
00588 void
00589 ColorTrainWidget::save_colormap()
00590 {
00591 if ( !m_fcd_filechooser )
00592 { return; }
00593
00594 m_fcd_filechooser->set_title("Save colormap colormap");
00595 m_fcd_filechooser->set_action(Gtk::FILE_CHOOSER_ACTION_SAVE);
00596
00597 m_fcd_filechooser->set_transient_for(*m_wnd_parent);
00598
00599 int result = m_fcd_filechooser->run();
00600
00601 switch(result)
00602 {
00603 case(Gtk::RESPONSE_OK):
00604 {
00605 std::string filename = m_fcd_filechooser->get_filename();
00606 YuvColormap *current = m_generator->get_current();
00607 ColormapFile cmf(current->depth(), current->width(), current->height());
00608 cmf.add_colormap(current);
00609 cmf.write( filename.c_str() );
00610 break;
00611 }
00612
00613 case(Gtk::RESPONSE_CANCEL):
00614 break;
00615
00616 default:
00617 break;
00618 }
00619
00620 m_fcd_filechooser->hide();
00621 }
00622
00623
00624
00625
00626 YuvColormap *
00627 ColorTrainWidget::get_colormap() const
00628 {
00629 if ( !m_generator )
00630 { return 0; }
00631
00632 return m_generator->get_current();
00633 }
00634
00635 bool
00636 ColorTrainWidget::set_threshold(Gtk::ScrollType scroll, double value)
00637 {
00638 unsigned int threshold = (unsigned int) rint(value);
00639 m_zauberstab->setThreshold(threshold);
00640
00641 return true;
00642 }
00643
00644 bool
00645 ColorTrainWidget::set_min_prob(Gtk::ScrollType scroll, double value)
00646 {
00647 if ( !m_generator )
00648 { return true; }
00649
00650 m_generator->set_min_probability(value);
00651
00652 return true;
00653 }
00654
00655 void
00656 ColorTrainWidget::reset_gui()
00657 {
00658 m_scl_min_prob->set_value(0.0);
00659 }
00660
00661
00662
00663
00664 void
00665 ColorTrainWidget::draw_segmentation_result()
00666 {
00667 if ( !m_src_buffer || !m_img_segmentation || !m_generator)
00668 { return; }
00669
00670 unsigned char* seg_buffer = (unsigned char*) malloc(m_img_size);
00671 bzero(seg_buffer, m_img_size);
00672
00673 Drawer d;
00674 d.set_buffer(seg_buffer, m_img_width, m_img_height);
00675
00676 YuvColormap* cm = m_generator->get_current();
00677
00678 for (unsigned int w = 0; w < m_img_width; ++w)
00679 {
00680 for (unsigned int h = 0; h < m_img_height; ++h)
00681 {
00682 unsigned int y = YUV422_PLANAR_Y_AT(m_src_buffer, m_img_width, w, h);
00683 unsigned int u = YUV422_PLANAR_U_AT(m_src_buffer, m_img_width, m_img_height, w, h);
00684 unsigned int v = YUV422_PLANAR_V_AT(m_src_buffer, m_img_width, m_img_height, w, h);
00685
00686 d.set_color(ColorObjectMap::get_color(cm->determine(y, u, v)));
00687 d.color_point(w, h);
00688 }
00689 }
00690
00691 LossyScaler scaler;
00692 scaler.set_original_buffer(seg_buffer);
00693 scaler.set_original_dimensions(m_img_width, m_img_height);
00694 scaler.set_scaled_dimensions(m_seg_img_max_width, m_seg_img_max_height);
00695 unsigned int width = scaler.needed_scaled_width();
00696 unsigned int height = scaler.needed_scaled_height();
00697
00698 unsigned char* scaled_buffer = (unsigned char*) malloc( colorspace_buffer_size( m_img_cs,
00699 width,
00700 height ) );
00701 scaler.set_scaled_buffer(scaled_buffer);
00702 scaler.scale();
00703
00704 unsigned char* rgb_buffer = (unsigned char*) malloc( colorspace_buffer_size( RGB,
00705 width,
00706 height ) );
00707 convert(m_img_cs, RGB, scaled_buffer, rgb_buffer, width, height);
00708
00709 Glib::RefPtr<Gdk::Pixbuf> image = Gdk::Pixbuf::create_from_data( rgb_buffer,
00710 Gdk::COLORSPACE_RGB,
00711 false,
00712 8,
00713 width,
00714 height,
00715 3 * width,
00716 Gdk::Pixbuf::SlotDestroyData(&free_rgb_buffer));
00717
00718 m_img_segmentation->set(image);
00719
00720 free(scaled_buffer);
00721 free(seg_buffer);
00722 }
00723
00724
00725
00726
00727 void ColorTrainWidget::free_rgb_buffer(const guint8* rgb_buffer)
00728 {
00729 free(const_cast<guint8 *>(rgb_buffer));
00730 }