Fawkes API  Fawkes Development Version
firestation.cpp
00001 /***************************************************************************
00002  *  firestation.cpp - Firestation
00003  *
00004  *  Created: Wed Oct 10 14:19:30 2007
00005  *  Copyright  2007-2008  Daniel Beck
00006  *
00007  ****************************************************************************/
00008 
00009 /*  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU Library General Public License for more details.
00018  *
00019  *  Read the full text in the LICENSE.GPL file in the doc directory.
00020  */
00021 
00022 #include "firestation.h"
00023 #include "color_train_widget.h"
00024 #include "fuse_transfer_widget.h"
00025 
00026 #include <utils/math/angle.h>
00027 
00028 #include <fvwidgets/fuse_image_list_widget.h>
00029 #include <gui_utils/avahi_dispatcher.h>
00030 
00031 #include <fvcams/fileloader.h>
00032 #include <fvcams/shmem.h>
00033 #include <fvcams/net.h>
00034 
00035 #ifdef HAVE_MIRROR_CALIB
00036 #include <fvmodels/mirror/mirror_calib.h>
00037 #endif
00038 
00039 #include <fvutils/ipc/shm_image.h>
00040 #include <fvutils/color/conversions.h>
00041 #include <fvutils/color/yuv.h>
00042 #include <fvutils/colormap/yuvcm.h>
00043 #include <fvutils/scalers/lossy.h>
00044 #include <fvutils/system/camargp.h>
00045 #include <fvutils/writers/jpeg.h>
00046 #include <fvutils/writers/fvraw.h>
00047 #include <fvutils/draw/drawer.h>
00048 
00049 #include <core/exception.h>
00050 
00051 #include <gdkmm/pixbuf.h>
00052 
00053 #include <arpa/inet.h>
00054 
00055 #include <iostream>
00056 
00057 using namespace std;
00058 using namespace fawkes;
00059 using namespace firevision;
00060 
00061 /** @class Firestation "firestation.h"
00062  * Control GUI for vision related stuff.
00063  * @author Daniel Beck
00064  */
00065 
00066 /** Constructor.
00067  * @param builder Gtk Builder
00068  */
00069 Firestation::Firestation(Glib::RefPtr<Gtk::Builder> builder)
00070 {
00071   // --- main window ------------------------------------------------
00072   builder->get_widget("wndMain", m_wnd_main);
00073   builder->get_widget("imgImage", m_img_image);
00074   builder->get_widget("evtImageEventBox", m_evt_image);
00075   builder->get_widget("trvShmImageIds", m_trv_shm_image_ids);
00076   builder->get_widget("stbStatus", m_stb_status);
00077   builder->get_widget("ckbContTrans", m_ckb_cont_trans);
00078   builder->get_widget("spbUpdateTime", m_spb_update_time);
00079 
00080   m_img_image->signal_size_allocate().connect( sigc::mem_fun(*this, &Firestation::resize_image) );
00081   m_evt_image->signal_button_press_event().connect( sigc::mem_fun(*this, &Firestation::image_click) );
00082   m_ckb_cont_trans->signal_toggled().connect( sigc::mem_fun(*this, &Firestation::enable_cont_img_trans) );
00083 
00084   // ----------------------------------------------------------------
00085 
00086 
00087   // --- toolbar widgets --------------------------------------------
00088   builder->get_widget("tbtnExit", m_tbtn_exit);
00089   builder->get_widget("tbtnCloseCamera", m_tbtn_close_camera);
00090   builder->get_widget("tbtnUpdate", m_tbtn_update);
00091   builder->get_widget("tbtnSave", m_tbtn_save);
00092   builder->get_widget("tbtnOpenFile", m_tbtn_open_file);
00093   builder->get_widget("tbtnOpenFolder", m_tbtn_open_folder);
00094   builder->get_widget("tbtnOpenShm", m_tbtn_open_shm);
00095   builder->get_widget("tbtnOpenFuse", m_tbtn_open_fuse);
00096 
00097   m_tbtn_exit->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::exit) );
00098   m_tbtn_close_camera->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::close_camera) );
00099   m_tbtn_update->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::update_image) );
00100   m_tbtn_save->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::save_image) );
00101   m_tbtn_open_file->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_file) );
00102   m_tbtn_open_folder->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_folder) );
00103   m_tbtn_open_shm->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_shm) );
00104   m_tbtn_open_fuse->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_fuse) );
00105   // ----------------------------------------------------------------
00106 
00107 
00108   // --- dialogs ----------------------------------------------------
00109   builder->get_widget("fcdOpenImage", m_fcd_open_image);
00110   builder->get_widget("fcdSaveImage", m_fcd_save_image);
00111   builder->get_widget("dlgOpenShm", m_dlg_open_shm);
00112   builder->get_widget("trvShmImageIds", m_trv_shm_image_ids);
00113   builder->get_widget("dlgOpenFuse", m_dlg_open_fuse);
00114   builder->get_widget("ckbFuseJpeg", m_ckb_fuse_jpeg);
00115   builder->get_widget("trvFuseServices", m_trv_fuse_services);
00116 
00117 #if GTK_VERSION_GE(3,0)
00118   Glib::RefPtr<Gtk::FileFilter> filter_jpg = Gtk::FileFilter::create();
00119 #else
00120   Gtk::FileFilter *filter_jpg = Gtk::manage(new Gtk::FileFilter());
00121 #endif
00122   filter_jpg->set_name("JPEG");
00123   filter_jpg->add_pattern("*.jpg");
00124   filter_jpg->add_pattern("*.jpeg");
00125 
00126 #if GTK_VERSION_GE(3,0)
00127   Glib::RefPtr<Gtk::FileFilter> filter_fvraw = Gtk::FileFilter::create();
00128 #else
00129   Gtk::FileFilter *filter_fvraw = Gtk::manage(new Gtk::FileFilter());
00130 #endif
00131   filter_fvraw->set_name("FVRaw");
00132   filter_fvraw->add_pattern("*.raw");
00133   filter_fvraw->add_pattern("*.fvraw");
00134 
00135 #if GTK_VERSION_GE(3,0)
00136   m_fcd_open_image->add_filter(filter_jpg);
00137   m_fcd_open_image->add_filter(filter_fvraw);
00138 
00139   m_fcd_save_image->add_filter(filter_jpg);
00140   m_fcd_save_image->add_filter(filter_fvraw);
00141 
00142 #else
00143   m_fcd_open_image->add_filter(*filter_jpg);
00144   m_fcd_open_image->add_filter(*filter_fvraw);
00145 
00146   m_fcd_save_image->add_filter(*filter_jpg);
00147   m_fcd_save_image->add_filter(*filter_fvraw);
00148 #endif
00149 
00150   m_shm_list_store = Gtk::ListStore::create(m_shm_columns);
00151   m_trv_shm_image_ids->set_model(m_shm_list_store);
00152   m_trv_shm_image_ids->append_column("#", m_shm_columns.m_id);
00153   m_trv_shm_image_ids->append_column("Name", m_shm_columns.m_name);
00154 
00155   m_fuse_tree_store = Gtk::TreeStore::create(m_fuse_columns);
00156   m_trv_fuse_services->set_model(m_fuse_tree_store);
00157   //  m_trv_fuse_services->append_column("#", m_fuse_columns.m_id);
00158   m_trv_fuse_services->append_column("Name", m_fuse_columns.m_name);
00159   // ----------------------------------------------------------------
00160 
00161 
00162   // --- color train widget -----------------------------------------
00163   m_ctw = new ColorTrainWidget(this);
00164   builder->get_widget("cmbCtObjectType", m_cmb_ct_type);
00165   builder->get_widget("btnCtStart", m_btn_ct_start);
00166   builder->get_widget("btnCtSeg", m_btn_ct_seg);
00167   builder->get_widget("spbtnCtCmDepth", m_spbtn_depth);
00168   builder->get_widget("spbtnCtCmWidth", m_spbtn_width);
00169   builder->get_widget("spbtnCtCmHeight", m_spbtn_height);
00170 
00171   m_cmb_ct_type->signal_changed().connect(sigc::mem_fun(*this, &Firestation::ct_object_changed));
00172   m_cmb_ct_type->set_active(0);
00173 
00174   m_btn_ct_start->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::ct_start) );
00175 
00176   m_ctw->update_image().connect( sigc::mem_fun(*this, &Firestation::draw_image) );
00177   m_ctw->colormap_updated().connect( sigc::mem_fun(*this, &Firestation::on_colormap_updated) );
00178 
00179   Gtk::Button* btn;
00180   builder->get_widget("btnCtUnselect", btn);
00181   m_ctw->set_reset_selection_btn(btn);
00182 
00183   builder->get_widget("btnCtAdd", btn);
00184   m_ctw->set_add_to_colormap_btn(btn);
00185 
00186   builder->get_widget("btnCtReset", btn);
00187   m_ctw->set_reset_colormap_btn(btn);
00188 
00189   builder->get_widget("btnCtSaveHistos", btn);
00190   m_ctw->set_save_histos_btn(btn);
00191 
00192   builder->get_widget("btnCtLoadHistos", btn);
00193   m_ctw->set_load_histos_btn(btn);
00194 
00195   builder->get_widget("btnCtSaveColormap", btn);
00196   m_ctw->set_save_colormap_btn(btn);
00197 
00198   builder->get_widget("btnCtLoadColormap", btn);
00199   m_ctw->set_load_colormap_btn(btn);
00200 
00201   Gtk::Scale* scl;
00202   builder->get_widget("sclCtThreshold", scl);
00203   m_ctw->set_threshold_scl(scl);
00204 
00205   builder->get_widget("sclCtMinProb", scl);
00206   m_ctw->set_min_prob_scl(scl);
00207 
00208   builder->get_widget("sclCtLayerSelector", scl);
00209   m_ctw->set_cm_layer_selector(scl);
00210 
00211   Gtk::Image* img;
00212   builder->get_widget("imgCtSegmentation", img);
00213   m_ctw->set_segmentation_img(img);
00214 
00215   builder->get_widget("imgCtColormap", img);
00216   m_ctw->set_colormap_img(img);
00217 
00218   Gtk::FileChooserDialog* fcd;
00219   builder->get_widget("fcdFilechooser", fcd);
00220   m_ctw->set_filechooser_dlg(fcd);
00221 
00222 
00223   m_btn_ct_seg->signal_toggled().connect( sigc::mem_fun(*this, &Firestation::draw_image) );
00224   m_ctw->set_cm_selector(m_spbtn_depth, m_spbtn_width, m_spbtn_height);
00225   // ----------------------------------------------------------------
00226 
00227 
00228   // --- mirror calibration -----------------------------------------
00229 #ifdef HAVE_MIRROR_CALIB
00230   m_calib_tool = new firevision::MirrorCalibTool();
00231 #endif
00232 
00233 #ifndef HAVE_MIRROR_CALIB
00234   Gtk::Notebook *nb;
00235   Gtk::HBox *box;
00236   builder->get_widget("ntbOptions", nb);
00237   builder->get_widget("boxMirrorCalib", box);
00238   nb->get_tab_label(*box)->set_sensitive(false);
00239   box->set_sensitive(false);
00240 #endif
00241 
00242   builder->get_widget("sclMcLine", m_scl_mc_line);
00243   m_scl_mc_line->signal_change_value().connect( sigc::mem_fun(*this, &Firestation::mc_on_line_angle_changed) );
00244 
00245   builder->get_widget("btnMcLoadMask", m_btn_mc_load_mask);
00246   m_btn_mc_load_mask->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_load_mask) );
00247 
00248   //builder->get_widget("btnMcStart", m_btn_mc_start);
00249   builder->get_widget("btnCalibLoad", m_btn_mc_load);
00250   builder->get_widget("btnCalibSave", m_btn_mc_save);
00251   builder->get_widget("entCalibDist", m_ent_mc_dist);
00252   builder->get_widget("entCalibOri", m_ent_mc_ori);
00253   builder->get_widget("fcdCalibSave", m_fcd_mc_save);
00254   builder->get_widget("fcdCalibLoad", m_fcd_mc_load);
00255 
00256   //m_btn_mc_start->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_start) );
00257   m_btn_mc_load->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_load) );
00258   m_btn_mc_save->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_save) );
00259 
00260   builder->get_widget("btnMcSetCenter", m_btn_mc_set_center);
00261   m_btn_mc_set_center->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_set_center) );
00262 
00263   builder->get_widget("btnMcMemorize", m_btn_mc_memorize);
00264   m_btn_mc_memorize->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_memorize) );
00265 
00266   builder->get_widget("btnMcSimulateClicks", m_btn_mc_simulate_clicks);
00267   m_btn_mc_simulate_clicks->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_simulate_clicks) );
00268 
00269   builder->get_widget("entCalibDist", m_ent_mc_dist);
00270   builder->get_widget("entCalibOri", m_ent_mc_ori);
00271 
00272   // ----------------------------------------------------------------
00273   builder->get_widget("fcdMcLoadMask", m_fcd_mc_load_mask);
00274   builder->get_widget("fcdCalibSave", m_fcd_mc_save);
00275   builder->get_widget("fcdCalibLoad", m_fcd_mc_load);
00276   // ----------------------------------------------------------------
00277 
00278 
00279   // --- fuse transfer widget ---------------------------------------
00280   m_ftw = new FuseTransferWidget();
00281 
00282   Gtk::TreeView* trv;
00283   builder->get_widget("trvFuseRemoteLuts", trv);
00284   m_ftw->set_remote_lut_list_trv(trv);
00285   builder->get_widget("trvFuseLocalLuts", trv);
00286   m_ftw->set_local_lut_list_trv(trv);
00287   builder->get_widget("imgFuseLocal", img);
00288   m_ftw->set_local_img(img);
00289   builder->get_widget("imgFuseRemote", img);
00290   m_ftw->set_remote_img(img);
00291   builder->get_widget("btnFuseUpload", btn);
00292   m_ftw->set_upload_btn(btn);
00293   builder->get_widget("sclLocalLayerSelector", scl);
00294   m_ftw->set_local_layer_selector(scl);
00295   builder->get_widget("sclRemoteLayerSelector", scl);
00296   m_ftw->set_remote_layer_selector(scl);
00297   // ----------------------------------------------------------------
00298 
00299 
00300   // --- fuse image list widget -------------------------------------
00301   m_filw = new FuseImageListWidget();
00302   builder->get_widget("trvFuseImageList", trv);
00303   m_filw->set_image_list_trv(trv);
00304   Gtk::CheckButton* chk;
00305   builder->get_widget("chkFuseImageListUpdate", chk);
00306   m_filw->set_auto_update_chk(chk);
00307   builder->get_widget("chkFuseCompression", chk);
00308   m_filw->set_toggle_compression_chk(chk);
00309   m_filw->image_selected().connect( sigc::mem_fun(*this, &Firestation::on_fuse_image_selected) );
00310   // ----------------------------------------------------------------
00311 
00312   m_yuv_orig_buffer   = 0;
00313   m_yuv_draw_buffer   = 0;
00314   m_yuv_scaled_buffer = 0;
00315   m_rgb_scaled_buffer = 0;
00316 
00317   m_img_width  = 0;
00318   m_img_height = 0;
00319   m_img_size   = 0;
00320   m_img_cs     = CS_UNKNOWN;
00321 
00322   m_img_writer = 0;
00323   m_camera     = 0;
00324   m_shm_buffer = 0;
00325 
00326   m_img_src = SRC_NONE;
00327   m_op_mode = MODE_VIEWER;
00328 
00329   m_cont_img_trans = false;
00330 
00331   mc_line_angle_deg = 0.0;
00332 
00333   m_max_img_width  = m_evt_image->get_width();
00334   m_max_img_height = m_evt_image->get_height();
00335   m_scaled_img_width  = m_evt_image->get_width();
00336   m_scaled_img_height = m_evt_image->get_height();
00337   m_scale_factor = 1.0;
00338 
00339   m_avahi_thread = new AvahiThread();
00340   m_avahi_dispatcher = new AvahiDispatcher;
00341   
00342   m_avahi_dispatcher->signal_service_added().connect( sigc::mem_fun( *this, &Firestation::on_service_added ) );
00343   m_avahi_dispatcher->signal_service_removed().connect( sigc::mem_fun( *this, &Firestation::on_service_removed ) );
00344 
00345   m_avahi_thread->watch_service("_fountain._tcp", m_avahi_dispatcher);
00346   m_avahi_thread->start();
00347 }
00348 
00349 /** Destructor. */
00350 Firestation::~Firestation()
00351 {
00352   if (m_yuv_orig_buffer)    free(m_yuv_orig_buffer);
00353   if (m_yuv_draw_buffer)    free(m_yuv_draw_buffer);
00354   if (m_yuv_scaled_buffer)  free(m_yuv_scaled_buffer);
00355   if (m_rgb_scaled_buffer)  free(m_rgb_scaled_buffer);
00356 
00357   delete m_camera;
00358   delete m_img_writer;
00359 
00360 #ifdef HAVE_MIRROR_CALIB
00361   delete m_calib_tool;
00362 #endif
00363   delete m_ctw;
00364   delete m_ftw;
00365   delete m_filw;
00366 
00367   m_avahi_thread->cancel();
00368   m_avahi_thread->join();
00369   delete m_avahi_thread;
00370   delete m_avahi_dispatcher;
00371 
00372   delete m_wnd_main;
00373   delete m_fcd_open_image;
00374   delete m_fcd_save_image;
00375   delete m_dlg_open_shm;
00376   delete m_dlg_open_fuse;
00377 }
00378 
00379 /** Returns reference to main window.
00380  * @return reference to main window
00381  */
00382 Gtk::Window&
00383 Firestation::get_window() const
00384 {
00385   return *m_wnd_main;
00386 }
00387 
00388 /** Exit routine. */
00389 void
00390 Firestation::exit()
00391 {
00392   if (SRC_NONE != m_img_src)
00393     { m_camera->close(); }
00394 
00395   m_wnd_main->hide();
00396 }
00397 
00398 void
00399 Firestation::close_camera()
00400 {
00401   if (SRC_NONE == m_img_src)
00402     { return; }
00403 
00404   m_img_src = SRC_NONE;
00405 
00406   m_camera->close();
00407   delete m_camera;
00408   m_camera = 0;
00409 
00410   m_img_width = 0;
00411   m_img_height = 0;
00412   m_img_cs = CS_UNKNOWN;
00413 
00414   m_img_size = 0;
00415 
00416   m_img_image->clear();
00417   m_img_image->set("gtk-missing-image");
00418 
00419   m_ctw->set_src_buffer(NULL, 0, 0);
00420   m_ctw->set_draw_buffer(NULL);
00421 }
00422 
00423 /** Saves the current image. */
00424 void
00425 Firestation::save_image()
00426 {
00427   if (m_img_src == SRC_NONE)
00428     { return; }
00429 
00430   m_fcd_save_image->set_transient_for(*this);
00431 
00432   int result = m_fcd_save_image->run();
00433 
00434   switch(result)
00435     {
00436     case(Gtk::RESPONSE_OK):
00437       {
00438         delete m_img_writer;
00439 
00440         Glib::ustring filter_name = m_fcd_save_image->get_filter()->get_name();
00441         if ( Glib::ustring("JPEG") == filter_name )
00442           {
00443             m_img_writer = new JpegWriter();
00444           }
00445         else if( Glib::ustring("FVRaw") == filter_name )
00446           {
00447             m_img_writer = new FvRawWriter();
00448           }
00449         else
00450           {
00451             cout << "save_file(): unknown file format" << endl;
00452             break;
00453           }
00454 
00455         std::string filename = m_fcd_save_image->get_filename();
00456         m_img_writer->set_filename( filename.c_str() );
00457         m_img_writer->set_dimensions(m_img_width, m_img_height);
00458         m_img_writer->set_buffer(m_img_cs, m_yuv_orig_buffer);
00459         m_img_writer->write();
00460 
00461         std::cout << "Save file: " <<  filename << std::endl;
00462         break;
00463       }
00464 
00465     case(Gtk::RESPONSE_CANCEL):
00466       break;
00467 
00468     default:
00469       break;
00470     }
00471 
00472   m_fcd_save_image->hide();
00473 }
00474 
00475 /** Reads in a new image for the current image source. */
00476 void
00477 Firestation::update_image()
00478 {
00479   if (m_img_src == SRC_NONE)
00480     { return; }
00481 
00482   try
00483     {
00484       m_camera->capture();
00485       convert(m_img_cs, YUV422_PLANAR,
00486               m_camera->buffer(), m_yuv_orig_buffer,
00487               m_img_width, m_img_height);
00488       memcpy(m_yuv_draw_buffer, m_yuv_orig_buffer,
00489              colorspace_buffer_size(YUV422_PLANAR, m_img_width, m_img_height));
00490       m_camera->dispose_buffer();
00491 
00492       draw_image();
00493 
00494       m_ctw->draw_segmentation_result();
00495     }
00496   catch (Exception& e)
00497     {
00498       e.print_trace();
00499     }
00500 }
00501 
00502 bool
00503 Firestation::call_update_image()
00504 {
00505   if ( !m_cont_img_trans )
00506     { return false; }
00507 
00508   update_image();
00509 
00510   return true;
00511 }
00512 
00513 void
00514 Firestation::enable_cont_img_trans()
00515 {
00516   if (m_cont_img_trans)
00517     {
00518       m_cont_img_trans = false;
00519       return;
00520     }
00521 
00522   int timeout = (int) rint( m_spb_update_time->get_value() );
00523   sigc::connection conn = Glib::signal_timeout().connect( sigc::mem_fun(*this, &Firestation::call_update_image), timeout);
00524   m_cont_img_trans = true;
00525 }
00526 
00527 /** Reads in an image from a file. */
00528 void
00529 Firestation::open_file()
00530 {
00531   m_fcd_open_image->set_action(Gtk::FILE_CHOOSER_ACTION_OPEN);
00532   m_fcd_open_image->set_transient_for(*this);
00533 
00534   int result = m_fcd_open_image->run();
00535 
00536   switch(result)
00537     {
00538     case Gtk::RESPONSE_OK:
00539       {
00540         pre_open_img_src();
00541 
00542         std::string filename = m_fcd_open_image->get_filename();
00543 
00544         m_camera = new FileLoader( filename.c_str() );
00545         m_img_src = SRC_FILE;
00546         post_open_img_src();
00547         break;
00548       }
00549 
00550     case Gtk::RESPONSE_CANCEL:
00551       {
00552         break;
00553       }
00554 
00555     default:
00556       {
00557         break;
00558       }
00559     }
00560 
00561   m_fcd_open_image->hide();
00562 }
00563 
00564 /** Reads in images from a directory. */
00565 void
00566 Firestation::open_folder()
00567 {
00568   m_fcd_open_image->set_action(Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
00569   m_fcd_open_image->set_transient_for(*this);
00570 
00571   int result = m_fcd_open_image->run();
00572 
00573   switch(result)
00574     {
00575     case Gtk::RESPONSE_OK:
00576       {
00577         pre_open_img_src();
00578 
00579         std::string extension;
00580         Glib::ustring filter_name = m_fcd_save_image->get_filter()->get_name();
00581         if ( Glib::ustring("JPEG") == filter_name )
00582           { extension = "jpg"; }
00583         else if ( Glib::ustring("FVRaw") == filter_name )
00584           { extension = "raw"; }
00585 
00586         std::string folder = m_fcd_open_image->get_current_folder();
00587         char* as;
00588         if (asprintf(&as, "file:file:dir=%s:ext=%s", folder.c_str(), extension.c_str()) != -1) {
00589           CameraArgumentParser cap(as);
00590           m_camera = new FileLoader( &cap );
00591           m_img_src = SRC_FILE;
00592           post_open_img_src();
00593           free(as);
00594         } else {
00595           printf("Cannot open folder, asprintf() ran out of memory");
00596         }
00597 
00598         break;
00599       }
00600 
00601     case Gtk::RESPONSE_CANCEL:
00602       {
00603         break;
00604       }
00605 
00606     default:
00607       {
00608         break;
00609       }
00610     }
00611 
00612   m_fcd_open_image->hide();
00613 }
00614 
00615 /** Opens a SHM image. */
00616 void
00617 Firestation::open_shm()
00618 {
00619   unsigned int num_buffers = 0;
00620   SharedMemory::SharedMemoryIterator shmit;
00621   SharedMemoryImageBufferHeader* h = new SharedMemoryImageBufferHeader;
00622   shmit = SharedMemory::find(FIREVISION_SHM_IMAGE_MAGIC_TOKEN, h);
00623 
00624   if (shmit == SharedMemory::end())
00625     {
00626       m_stb_status->push("No SHM images found");
00627       return;
00628     }
00629   else
00630     {
00631       m_shm_list_store->clear();
00632 
00633       while ( shmit != SharedMemory::end() )
00634         {
00635           ++num_buffers;
00636           Gtk::TreeModel::Row row = *(m_shm_list_store->append());
00637           row[m_shm_columns.m_id] = num_buffers;
00638           const SharedMemoryImageBufferHeader* h = (SharedMemoryImageBufferHeader*)*shmit;
00639           row[m_shm_columns.m_name] = h->image_id();
00640           shmit++;
00641         }
00642     }
00643 
00644   m_dlg_open_shm->set_transient_for(*this);
00645 
00646   int result = m_dlg_open_shm->run();
00647 
00648   switch(result)
00649     {
00650     case Gtk::RESPONSE_OK:
00651       {
00652         delete m_shm_buffer;
00653 
00654         Gtk::TreeModel::Path path;
00655         Gtk::TreeViewColumn* column;
00656         m_trv_shm_image_ids->get_cursor(path, column);
00657 
00658         Gtk::TreeModel::iterator iter = m_shm_list_store->get_iter(path);
00659 
00660         if (iter)
00661           {
00662             Gtk::TreeModel::Row row = *iter;
00663             if (row)
00664               {
00665                 Glib::ustring name = row[m_shm_columns.m_name];
00666                 pre_open_img_src();
00667 
00668                 try
00669                   {
00670                     m_camera = new SharedMemoryCamera( name.c_str() );
00671                   }
00672                 catch (Exception& e)
00673                   {
00674                     e.print_trace();
00675                   }
00676 
00677                 m_img_src = SRC_SHM;
00678 
00679                 post_open_img_src();
00680               }
00681           }
00682         else
00683           {
00684             std::cout << "invalid iter" << std::endl;
00685           }
00686 
00687         break;
00688       }
00689 
00690     case Gtk::RESPONSE_CANCEL:
00691       break;
00692 
00693     default:
00694       break;
00695     }
00696 
00697   m_dlg_open_shm->hide();
00698 }
00699 
00700 /** Connects to a FUSE server. */
00701 void
00702 Firestation::open_fuse()
00703 {
00704   Gtk::TreeModel::Children children = m_fuse_tree_store->children();
00705   if ( 0 == children.size() )
00706     {
00707       m_stb_status->push("No FUSE services found");
00708       return;
00709     }
00710 
00711   m_trv_fuse_services->expand_all();
00712   m_dlg_open_fuse->set_transient_for(*this);
00713 
00714   int result = m_dlg_open_fuse->run();
00715 
00716   switch(result)
00717     {
00718     case Gtk::RESPONSE_OK:
00719       {
00720         Gtk::TreeModel::Path path;
00721         Gtk::TreeViewColumn* column;
00722         m_trv_fuse_services->get_cursor(path, column);
00723 
00724         Gtk::TreeModel::iterator iter = m_fuse_tree_store->get_iter(path);
00725 
00726         if (iter)
00727           {
00728             Gtk::TreeModel::Row row = *iter;
00729             if (row)
00730               {
00731                 Glib::ustring hostname = row[m_fuse_columns.m_service_hostname];
00732                 unsigned short int port = row[m_fuse_columns.m_service_port];
00733                 Glib::ustring image_id = row[m_fuse_columns.m_image_id];
00734                 bool jpeg = m_ckb_fuse_jpeg->get_active();
00735 
00736                 pre_open_img_src();
00737 
00738                 try
00739                   {
00740                     m_camera = new NetworkCamera(hostname.c_str(), port, image_id.c_str(), jpeg);
00741                     m_img_src = SRC_FUSE;
00742                     post_open_img_src();
00743                   }
00744                 catch (Exception& e)
00745                   {
00746                     m_img_src = SRC_NONE;
00747                     e.print_trace();
00748                   }
00749               }
00750           }
00751         else
00752           {
00753             std::cout << "invalid iter" << std::endl;
00754           }
00755 
00756         break;
00757       }
00758 
00759     case Gtk::RESPONSE_CANCEL:
00760       break;
00761 
00762     default:
00763       break;
00764     }
00765 
00766   m_dlg_open_fuse->hide();
00767 }
00768 
00769 void
00770 Firestation::pre_open_img_src()
00771 {
00772   if (SRC_NONE != m_img_src)
00773     {
00774       m_camera->stop();
00775       m_camera->close();
00776 
00777       delete m_camera;
00778       m_camera = 0;
00779 
00780       m_img_src = SRC_NONE;
00781     }
00782 }
00783 
00784 /** Stuff that is executed after an image source has been selected. */
00785 void
00786 Firestation::post_open_img_src()
00787 {
00788   if (m_img_src == SRC_NONE) { return; }
00789 
00790   try
00791     {
00792       m_camera->open();
00793       m_camera->start();
00794       m_camera->capture();
00795       m_img_width = m_camera->pixel_width();
00796       m_img_height = m_camera->pixel_height();
00797       m_img_cs = m_camera->colorspace();
00798 
00799       m_img_size = colorspace_buffer_size( m_img_cs,
00800                                            m_img_width,
00801                                            m_img_height );
00802 
00803       m_yuv_orig_buffer = malloc_buffer(YUV422_PLANAR, m_img_width, m_img_height);
00804       m_yuv_draw_buffer = malloc_buffer(YUV422_PLANAR, m_img_width, m_img_height);
00805 
00806       convert(m_img_cs, YUV422_PLANAR,
00807               m_camera->buffer(), m_yuv_orig_buffer,
00808               m_img_width, m_img_height);
00809       memcpy(m_yuv_draw_buffer, m_yuv_orig_buffer,
00810              colorspace_buffer_size(YUV422_PLANAR, m_img_width, m_img_height));
00811 
00812       m_camera->dispose_buffer();
00813 
00814       m_tbtn_update->set_sensitive(true);
00815       m_tbtn_save->set_sensitive(true);
00816 
00817       draw_image();
00818 
00819       m_ctw->set_src_buffer(m_yuv_orig_buffer, m_img_width, m_img_height);
00820       m_ctw->set_draw_buffer(m_yuv_draw_buffer);
00821       m_ctw->draw_segmentation_result();
00822 
00823       mc_draw_line();
00824     }
00825   catch (Exception& e)
00826     {
00827       e.print_trace();
00828       printf("Opening camera failed.\n");
00829     }
00830 
00831 }
00832 
00833 void
00834 Firestation::on_fuse_image_selected()
00835 {
00836   string host_name;
00837   unsigned short port;
00838   string image_id;
00839   bool compression;
00840 
00841   m_filw->get_selected_image(host_name, port, image_id, compression);
00842 
00843   pre_open_img_src();
00844 
00845   try
00846     {
00847       m_camera = new NetworkCamera( host_name.c_str(), port, image_id.c_str(), compression );
00848       m_img_src = SRC_FUSE;
00849     }
00850   catch (Exception& e)
00851     {
00852       m_img_src = SRC_NONE;
00853       e.print_trace();
00854     }
00855 
00856   post_open_img_src();
00857 }
00858 
00859 void
00860 Firestation::on_colormap_updated()
00861 {
00862   m_ftw->set_current_colormap( m_ctw->get_colormap() );
00863 }
00864 
00865 /** Draws the image. */
00866 void
00867 Firestation::draw_image()
00868 {
00869   if ( m_img_src == SRC_NONE ) { return; }
00870 
00871   LossyScaler scaler;
00872   scaler.set_original_buffer( m_yuv_draw_buffer );
00873   scaler.set_original_dimensions(m_img_width, m_img_height);
00874   scaler.set_scaled_dimensions(m_max_img_width, m_max_img_height);
00875 
00876   unsigned int scaled_width  = scaler.needed_scaled_width();
00877   unsigned int scaled_height = scaler.needed_scaled_height();
00878 
00879   if (scaled_width != m_scaled_img_width || scaled_height != m_scaled_img_height)
00880     {
00881       m_scaled_img_width  = scaled_width;
00882       m_scaled_img_height = scaled_height;
00883       m_scale_factor = scaler.get_scale_factor();
00884     }
00885 
00886   if (m_rgb_scaled_buffer)  free(m_rgb_scaled_buffer);
00887   if (m_yuv_scaled_buffer)  free(m_yuv_scaled_buffer);
00888   m_yuv_scaled_buffer = malloc_buffer(YUV422_PLANAR, m_scaled_img_width,
00889                                       m_scaled_img_height);
00890   scaler.set_scaled_buffer(m_yuv_scaled_buffer);
00891   scaler.scale();
00892 
00893   if (m_btn_ct_seg->get_active()) {
00894     unsigned int sld_img_size = m_scaled_img_width * m_scaled_img_height;
00895     unsigned char u_seg = 255 / (unsigned int)pow(2, m_spbtn_width->get_value());
00896     unsigned char v_seg = 255 / (unsigned int)pow(2, m_spbtn_height->get_value());
00897     unsigned int u = 0;
00898     for (u = sld_img_size; u < sld_img_size + sld_img_size / 2; ++u) {
00899       m_yuv_scaled_buffer[u] = (m_yuv_scaled_buffer[u] / u_seg) * u_seg;
00900     }
00901 
00902     for (; u < 2 * sld_img_size; ++u) {
00903       m_yuv_scaled_buffer[u] = (m_yuv_scaled_buffer[u] / v_seg) * v_seg;
00904     }
00905   }
00906 
00907   if ( m_img_src == SRC_SHM )
00908     {
00909       SharedMemoryCamera* shm_camera = dynamic_cast<SharedMemoryCamera*>(m_camera);
00910       if ( shm_camera->shared_memory_image_buffer()->circle_found() )
00911         {
00912           Drawer drawer;
00913           drawer.set_buffer(m_yuv_scaled_buffer, m_scaled_img_width, m_scaled_img_height);
00914           drawer.set_color(YUV_t::white());
00915           unsigned int roi_x = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_x() * m_scale_factor );
00916           unsigned int roi_y = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_y() * m_scale_factor );
00917           unsigned int roi_width  = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_width() * m_scale_factor );
00918           unsigned int roi_height = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_height() * m_scale_factor );
00919           drawer.draw_rectangle( roi_x, roi_y, roi_width, roi_height );
00920         }
00921     }
00922 
00923   m_rgb_scaled_buffer = (unsigned char*) malloc( colorspace_buffer_size( RGB,
00924                                                                          m_scaled_img_width,
00925                                                                          m_scaled_img_height ) );
00926 
00927   convert( YUV422_PLANAR, RGB,
00928            m_yuv_scaled_buffer, m_rgb_scaled_buffer,
00929            m_scaled_img_width, m_scaled_img_height );
00930 
00931   Glib::RefPtr<Gdk::Pixbuf> image = Gdk::Pixbuf::create_from_data( m_rgb_scaled_buffer,
00932                                                                    Gdk::COLORSPACE_RGB,
00933                                                                    false,
00934                                                                    8,
00935                                                                    m_scaled_img_width,
00936                                                                    m_scaled_img_height,
00937                                                                    3 * m_scaled_img_width );
00938 
00939   m_img_image->set(image);
00940 }
00941 
00942 /** Signal handler that is called whenever the window size is changed.
00943  * @param allocation a Gtk allocation
00944  */
00945 void
00946 Firestation::resize_image(Gtk::Allocation& allocation)
00947 {
00948   unsigned int new_width = (unsigned int) allocation.get_width();
00949   unsigned int new_height = (unsigned int) allocation.get_height();
00950 
00951   if (new_width != m_max_img_width ||  new_height != m_max_img_height)
00952     {
00953       m_max_img_width = new_width;
00954       m_max_img_height = new_height;
00955       draw_image();
00956     }
00957 }
00958 
00959 /** Handles mouse clicks in the image area.
00960  * @param event a Gtk event
00961  * @return true if signal was handled
00962  */
00963 bool
00964 Firestation::image_click(GdkEventButton* event)
00965 {
00966   unsigned int offset_x;
00967   unsigned int offset_y;
00968 
00969   offset_x = (m_max_img_width - m_scaled_img_width) / 2;
00970   offset_y = (m_max_img_height - m_scaled_img_height) / 2;
00971 
00972   offset_x = offset_x > m_max_img_width ? 0 : offset_x;
00973   offset_y = offset_y > m_max_img_height ? 0 : offset_y;
00974 
00975   unsigned int image_x;
00976   unsigned int image_y;
00977 
00978   if (event != NULL) {
00979     image_x = (unsigned int)rint( (event->x - offset_x) / m_scale_factor);
00980     image_y = (unsigned int)rint( (event->y - offset_y) / m_scale_factor);
00981   } else {
00982     image_x = 0;
00983     image_y = 0;
00984   }
00985 
00986   if ( image_x < 0 || image_x > m_img_width ||
00987        image_y < 0 || image_y > m_img_height )
00988     { return true; }
00989 
00990   switch (m_op_mode)
00991     {
00992     case MODE_VIEWER:
00993       if (m_img_src != SRC_NONE)
00994         {
00995           register unsigned char y;
00996           register unsigned char u;
00997           register unsigned char v;
00998           YUV422_PLANAR_YUV( m_yuv_orig_buffer,
00999                              m_img_width,
01000                              m_img_height,
01001                              image_x,
01002                              image_y,
01003                              y, u, v );
01004           printf( "Y=%d  U=%d  Y=%d @ (%d, %d)\n",
01005                   (unsigned int) y, (unsigned int) u, (unsigned int) v,
01006                   image_x, image_y );
01007         }
01008       break;
01009 
01010     case MODE_COLOR_TRAIN:
01011       m_ctw->click(image_x, image_y, event->button);
01012       draw_image();
01013      break;
01014 
01015     case MODE_MIRROR_CALIB:
01016       {
01017 #ifdef HAVE_MIRROR_CALIB
01018         if (m_btn_mc_set_center->get_active()) {
01019           m_calib_tool->set_center(image_x, image_y);
01020           m_btn_mc_set_center->set_active(false);
01021           mc_draw_line();
01022           printf("Setting center to %d, %d\n", image_x, image_y);
01023         } else {
01024           printf("Using center to %d, %d\n", m_calib_tool->center_x(), m_calib_tool->center_y());
01025           m_calib_tool->next_step();
01026           const unsigned char* last_yuv = m_calib_tool->get_last_yuv_buffer();
01027           memcpy(m_yuv_draw_buffer, last_yuv, m_img_size);
01028           memcpy(m_yuv_orig_buffer, last_yuv, m_img_size);
01029           m_calib_tool->draw_mark_lines(m_yuv_draw_buffer);
01030           draw_image();
01031           m_stb_status->push(m_calib_tool->get_state_description());
01032         }
01033 #else
01034         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01035 #endif
01036         break;
01037       }
01038 
01039     case MODE_MIRROR_CALIB_EVAL:
01040       {
01041 #ifdef HAVE_MIRROR_CALIB
01042         float dist;
01043         float phi;
01044         m_calib_tool->eval(image_x, image_y, &dist, &phi);
01045         phi = normalize_mirror_rad(phi);
01046         printf("(%d, %d) = POLAR(%.2f deg, %.2f meters)\n",
01047             image_x, image_y,
01048             rad2deg(phi), dist);
01049         //printf("Distance: %2f\t Phi: %2f\n", dist, phi);
01050 #else
01051         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01052 #endif
01053         break;
01054       }
01055 
01056     default:
01057       break;
01058     }
01059 
01060   return true;
01061 }
01062 
01063 /** Starts the color training. */
01064 void
01065 Firestation::ct_start()
01066 {
01067   if (m_op_mode == MODE_COLOR_TRAIN)
01068     {
01069       m_op_mode = MODE_VIEWER;
01070       m_stb_status->push("Leaving color training mode");
01071     }
01072   else
01073     {
01074       if (m_img_src != SRC_NONE)
01075         {
01076           m_ctw->set_fg_object( ct_get_fg_object() );
01077 
01078           m_op_mode = MODE_COLOR_TRAIN;
01079 
01080           m_stb_status->push("Entering color training mode");
01081         }
01082     }
01083 }
01084 
01085 hint_t
01086 Firestation::ct_get_fg_object()
01087 {
01088         int active = m_cmb_ct_type->get_active_row_number();
01089         switch(active)
01090         {
01091                 case 0: //Ball
01092                         return H_BALL;
01093 
01094                 case 1: //Field
01095                         return H_FIELD;
01096 
01097                 case 2: //Lines
01098                         return H_LINE;
01099 
01100                 case 3: //Robot (Team A or all)
01101                         return H_ROBOT;
01102 
01103                 case 4: //Robot (Team B)
01104                         return H_ROBOT_OPP;
01105 
01106                 case 5: //Goal (yellow)
01107                         return H_GOAL_YELLOW;
01108 
01109                 case 6: //Goal (sky-blue)
01110                         return H_GOAL_BLUE;
01111 
01112                 case 7: //Background
01113                         return H_UNKNOWN;
01114 
01115                 default:
01116                         printf("ct_get_fg_object(): UNKNOWN\n");
01117                         return H_UNKNOWN;
01118         }
01119 }
01120 
01121 void
01122 Firestation::ct_object_changed()
01123 {
01124         hint_t object = ct_get_fg_object();
01125         m_ctw->set_fg_object(object);
01126 }
01127 
01128 void
01129 Firestation::mc_draw_line()
01130 {
01131   if (m_img_src != SRC_NONE) {
01132 #ifdef HAVE_MIRROR_CALIB
01133     memcpy(m_yuv_draw_buffer, m_yuv_orig_buffer, m_img_size);
01134     MirrorCalibTool::draw_line(m_yuv_draw_buffer,
01135                                mc_line_angle_deg,
01136                                m_calib_tool->center_x(),
01137                                m_calib_tool->center_y(),
01138                                m_img_width,
01139                                m_img_height);
01140     draw_image();
01141 #else
01142         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01143 #endif
01144   }
01145 }
01146 
01147 bool
01148 Firestation::mc_on_line_angle_changed(Gtk::ScrollType scroll, double value)
01149 {
01150   mc_line_angle_deg = -1.0f * value;
01151   mc_line_angle_deg =
01152     rad2deg(normalize_mirror_rad(deg2rad(mc_line_angle_deg)));
01153   // Why -1.0f * value?
01154   // We want to display angles from the robot's real-world perspective.
01155   // We want to calculate with angles from the (mirrored!) image's perspective.
01156   // So when the user chooses 90 degrees, he wants to look to the left from the
01157   // robots perspective. But due to the mirroring, that's the right side in the
01158   // image, so we take -90 degrees.
01159   mc_draw_line();
01160   return true;
01161 }
01162 
01163 void
01164 Firestation::mc_load_mask()
01165 {
01166   m_fcd_mc_load_mask->set_transient_for(*this);
01167 
01168 #if GTK_VERSION_GE(3,0)
01169   Glib::RefPtr<Gtk::FileFilter> filter_mirror = Gtk::FileFilter::create();
01170 #else
01171   Gtk::FileFilter *filter_mirror = Gtk::manage(new Gtk::FileFilter());
01172 #endif
01173   filter_mirror->set_name("Robot Mask");
01174   filter_mirror->add_pattern("*.pnm");
01175 #if GTK_VERSION_GE(3,0)
01176   m_fcd_mc_load_mask->add_filter(filter_mirror);
01177 #else
01178   m_fcd_mc_load_mask->add_filter(*filter_mirror);
01179 #endif
01180 
01181   int result = m_fcd_mc_load_mask->run();
01182 
01183   switch(result)
01184     {
01185     case Gtk::RESPONSE_OK:
01186       {
01187 #ifdef HAVE_MIRROR_CALIB
01188         std::string filename = m_fcd_mc_load_mask->get_filename();
01189         m_calib_tool->load_mask( filename.c_str() );
01190         //m_op_mode = MODE_MIRROR_CALIB_EVAL;
01191 #else
01192         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01193 #endif
01194         break;
01195       }
01196     case Gtk::RESPONSE_CANCEL:
01197       break;
01198     default:
01199       break;
01200     }
01201 
01202   m_fcd_mc_load_mask->hide();
01203 }
01204 
01205 /** Enters MODE_MIRROR_CALIB mode which waits for a click to mark the
01206  * preliminary center of the image. */
01207 void
01208 Firestation::mc_set_center()
01209 {
01210   m_op_mode = MODE_MIRROR_CALIB;
01211 }
01212 
01213 /** Start the mirror calibration process. */
01214 void
01215 Firestation::mc_memorize()
01216 {
01217   /* if (m_op_mode == MODE_MIRROR_CALIB)
01218     {
01219       m_op_mode = MODE_VIEWER;
01220       m_stb_status->push("Leaving mirror calibration mode");
01221     }
01222   else */ if (m_img_src != SRC_NONE)
01223     {
01224 #ifdef HAVE_MIRROR_CALIB
01225       double ori = mc_line_angle_deg;
01226       std::cout << "Starting calibration for ori = " << ori << std::endl;
01227       m_calib_tool->push_back(m_yuv_orig_buffer, m_img_size,
01228                               m_img_width, m_img_height, deg2rad(ori));
01229       m_op_mode = MODE_MIRROR_CALIB;
01230       std::cout << "Initialization for ori = " << ori << " completed" << std::endl;
01231 
01232       mc_line_angle_deg -= 120.0;
01233       mc_line_angle_deg =
01234         rad2deg(normalize_mirror_rad(deg2rad(mc_line_angle_deg)));
01235       m_scl_mc_line->set_value(-1.0f * mc_line_angle_deg);
01236       // Why -1.0f * mc_line_angle_deg?
01237       // We want to display angles from the robot's real-world perspective.
01238       // We want to calculate with angles from the (mirrored!) image's perspective.
01239       // So when the user chooses 90 degrees, he wants to look to the left from the
01240       // robots perspective. But due to the mirroring, that's the right side in the
01241       // image, so we take -90 degrees.
01242       mc_draw_line();
01243 #else
01244         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01245 #endif
01246   }
01247 }
01248 
01249 /** Start the mirror calibration process. */
01250 void
01251 Firestation::mc_simulate_clicks()
01252 {
01253   for (int i = 1; i <= 3; ++i) {
01254     image_click(NULL); // SHARPENING
01255     for (int j = 1; j <= 8; ++j) { image_click(NULL); } // EDGE_DETECTION
01256     for (int j = 1; j <= 2*8; ++j) { image_click(NULL); } // COMBINATION
01257     image_click(NULL); // PRE_MARKING
01258     image_click(NULL); // FINAL_MARKING
01259   }
01260 }
01261 
01262 /** Load mirror calibration data from a file. */
01263 void
01264 Firestation::mc_load()
01265 {
01266   m_fcd_mc_load->set_transient_for(*this);
01267 
01268 #if GTK_VERSION_GE(3,0)
01269   Glib::RefPtr<Gtk::FileFilter> filter_mirror = Gtk::FileFilter::create();
01270 #else
01271   Gtk::FileFilter *filter_mirror = Gtk::manage(new Gtk::FileFilter());
01272 #endif
01273   filter_mirror->set_name("Mirror Calibration");
01274   filter_mirror->add_pattern("*.mirror");
01275   filter_mirror->add_pattern("*.bulb");
01276 #if GTK_VERSION_GE(3,0)
01277   m_fcd_mc_load->add_filter(filter_mirror);
01278 #else
01279   m_fcd_mc_load->add_filter(*filter_mirror);
01280 #endif
01281 
01282   int result = m_fcd_mc_load->run();
01283 
01284   switch(result)
01285     {
01286     case Gtk::RESPONSE_OK:
01287       {
01288 #ifdef HAVE_MIRROR_CALIB
01289         std::string filename = m_fcd_mc_load->get_filename();
01290         m_calib_tool->load( filename.c_str() );
01291         m_op_mode = MODE_MIRROR_CALIB_EVAL;
01292 #else
01293         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01294 #endif
01295         break;
01296       }
01297     case Gtk::RESPONSE_CANCEL:
01298       break;
01299     default:
01300       break;
01301     }
01302 
01303   m_fcd_mc_load->hide();
01304 }
01305 
01306 /** Save calibration data to a file. */
01307 void
01308 Firestation::mc_save()
01309 {
01310   m_fcd_mc_save->set_transient_for(*this);
01311 
01312   int result = m_fcd_mc_save->run();
01313 
01314   switch(result)
01315     {
01316     case(Gtk::RESPONSE_OK):
01317       {
01318 #ifdef HAVE_MIRROR_CALIB
01319         std::string filename = m_fcd_mc_save->get_filename();
01320 
01321         m_calib_tool->save( filename.c_str() );
01322 #else
01323         printf("IPP and OpenCV not installed; mirror calibration does not work.\n");
01324 #endif
01325         break;
01326       }
01327 
01328     case(Gtk::RESPONSE_CANCEL):
01329       break;
01330 
01331     default:
01332       break;
01333     }
01334 
01335   m_fcd_mc_save->hide();
01336 
01337 }
01338 
01339 void
01340 Firestation::on_service_added( NetworkService* service )
01341 {
01342   const char* host        = service->host();
01343   const char* name        = service->name();
01344   const char* type        = service->type();
01345   const char* domain      = service->domain();
01346   unsigned short int port = service->port();
01347   
01348   std::vector<FUSE_imageinfo_t> image_list;
01349   NetworkCamera cam(host, port);
01350   try
01351     {
01352       cam.open();
01353       cam.start();
01354       image_list = cam.image_list();
01355     }
01356   catch (Exception& e)
01357     {
01358       e.append("Could not open camera on %s:%d", host, port);
01359       e.print_trace();
01360       return;
01361     }
01362   cam.close();
01363 
01364 #ifdef DEBUG_PRINT
01365   printf("%zu images available on host %s.\n", image_list.size(), host);
01366 #endif /* DEBUG_PRINT */
01367 
01368   std::vector<FUSE_imageinfo_t>::iterator fit;
01369 
01370   Gtk::TreeModel::Children children = m_fuse_tree_store->children();
01371   Gtk::TreeModel::Row row = *(m_fuse_tree_store->append());
01372   row[m_fuse_columns.m_id] = children.size();
01373   row[m_fuse_columns.m_name] = Glib::ustring(name);
01374   row[m_fuse_columns.m_service_name] = Glib::ustring(name);
01375   row[m_fuse_columns.m_service_type] = Glib::ustring(type);
01376   row[m_fuse_columns.m_service_domain] = Glib::ustring(domain);
01377   row[m_fuse_columns.m_service_hostname] = Glib::ustring(host);
01378   row[m_fuse_columns.m_service_port] = port;
01379 
01380   for (fit = image_list.begin(); fit != image_list.end(); ++fit)
01381     {
01382       Gtk::TreeModel::Row childrow = *(m_fuse_tree_store->append(row.children()));
01383       childrow[m_fuse_columns.m_name] = Glib::ustring(fit->image_id);
01384       childrow[m_fuse_columns.m_service_name] = Glib::ustring(name);
01385       childrow[m_fuse_columns.m_service_type] = Glib::ustring(type);
01386       childrow[m_fuse_columns.m_service_domain] = Glib::ustring(domain);
01387       childrow[m_fuse_columns.m_service_hostname] = Glib::ustring(host);
01388       childrow[m_fuse_columns.m_service_port] = port;
01389       childrow[m_fuse_columns.m_image_id] = Glib::ustring(fit->image_id);
01390       childrow[m_fuse_columns.m_image_width] = fit->width;
01391       childrow[m_fuse_columns.m_image_height] = fit->height;
01392       childrow[m_fuse_columns.m_image_colorspace] = Glib::ustring( colorspace_to_string((colorspace_t) fit->colorspace) );
01393     }
01394 
01395   m_ftw->add_fountain_service(name, host, port);
01396   m_filw->add_fountain_service(name, host, port);
01397 }
01398 
01399 void
01400 Firestation::on_service_removed( NetworkService* service )
01401 {
01402   const char* name   = service->name();
01403   const char* type   = service->type();
01404   const char* domain = service->domain();
01405 
01406   Gtk::TreeModel::Children children = m_fuse_tree_store->children();
01407   Gtk::TreeModel::iterator rit;
01408   for (rit = children.begin(); rit != children.end(); ++rit)
01409     {
01410       Glib::ustring n = (*rit)[m_fuse_columns.m_service_name];
01411       Glib::ustring t = (*rit)[m_fuse_columns.m_service_type];
01412       Glib::ustring d = (*rit)[m_fuse_columns.m_service_domain];
01413 
01414       if ( strcmp( n.c_str(), name) == 0 &&
01415            strcmp( t.c_str(), type) == 0 &&
01416            strcmp( d.c_str(), domain) == 0 )
01417         {
01418           m_fuse_tree_store->erase(rit);
01419         }
01420     }
01421 
01422   m_ftw->remove_fountain_service(name);
01423   m_filw->remove_fountain_service(name);
01424 }