libeblearntools
/home/rex/ebltrunk/tools/libeblearntools/include/fprop_thread.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2011 by Pierre Sermanet *
00003  *   pierre.sermanet@gmail.com *
00004  *   All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Redistribution under a license not approved by the Open Source
00014  *       Initiative (http://www.opensource.org) must display the
00015  *       following acknowledgement in all advertising material:
00016  *        This product includes software developed at the Courant
00017  *        Institute of Mathematical Sciences (http://cims.nyu.edu).
00018  *     * The names of the authors may not be used to endorse or promote products
00019  *       derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024  * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY
00025  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00028  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  ***************************************************************************/
00032 
00033 #ifndef FPROP_THREAD_HPP_
00034 #define FPROP_THREAD_HPP_
00035 
00036 #include <map>
00037 #include <string>
00038 #include <iostream>
00039 #include <algorithm>
00040 #include <vector>
00041 #include <stdlib.h>
00042 #include <sstream>
00043 #include <iomanip>
00044 #include <time.h>
00045 
00046 #include "libeblearn.h"
00047 #include "libeblearntools.h"
00048 
00049 #ifdef __GUI__
00050 #include "libeblearngui.h"
00051 #endif
00052 
00053 using namespace std;
00054 
00055 namespace ebl {
00056 
00058   // detection thread
00059 
00060   template <typename Tnet>
00061   fprop_thread<Tnet>::fprop_thread(configuration &conf_,
00062                                    mutex *om,
00063                                    const char *name_,
00064                                    const char *arg2_, bool sync,
00065                                    t_chans tc)
00066     : thread(om, name_, sync), conf(conf_), arg2(arg2_), frame(120, 160, 1),
00067       mutex_in(), mutex_out(),
00068       in_updated(false), out_updated(false), bavailable(false),
00069       frame_name(""), frame_id(0), outdir(""), color_space(tc),
00070       bload_image(false), pdetect(NULL) {
00071   }
00072 
00073   template <typename Tnet>
00074   fprop_thread<Tnet>::~fprop_thread() {
00075   }
00076 
00077   template <typename Tnet>
00078   void fprop_thread<Tnet>::set_out_updated() {
00079     // lock data
00080     mutex_out.lock();
00081     // set flag
00082     out_updated = true;
00083     // unlock data
00084     mutex_out.unlock();
00085   }
00086  
00087   template <typename Tnet>
00088   bool fprop_thread<Tnet>::get_data(idx<ubyte> &frame2,
00089                                     string &frame_name_,
00090                                     uint &id) {
00091     // lock data
00092     mutex_out.lock();
00093     // only read data if it has been updated
00094     if (!out_updated) {
00095       // unlock data
00096       mutex_out.unlock();
00097       return false;
00098     }
00099     // check frame is correctly allocated, if not, allocate.
00100     if (frame2.order() != uframe.order()) 
00101       frame2 = idx<ubyte>(uframe.get_idxdim());
00102     else if (frame2.get_idxdim() != uframe.get_idxdim())
00103       frame2.resize(uframe.get_idxdim());
00104     // copy frame
00105     idx_copy(uframe, frame2);    
00106     // set frame name
00107     frame_name_ = frame_name;
00108     // set frame id
00109     id = frame_id;
00110     // reset updated flag
00111     out_updated = false;
00112     // declare thread as available
00113     bavailable = true;
00114     // unlock data
00115     mutex_out.unlock();
00116     // confirm that we copied data.
00117     return true;
00118   }
00119 
00120   template <typename Tnet>
00121   bool fprop_thread<Tnet>::set_data(idx<ubyte> &frame2, string &name,
00122                                     uint id) {
00123     // lock data (non blocking)
00124     if (!mutex_in.trylock())
00125       return false;
00126     // check frame is correctly allocated, if not, allocate.
00127     if (frame2.order() != uframe.order())
00128       uframe = idx<ubyte>(frame2.get_idxdim());
00129     else if (frame2.get_idxdim() != uframe.get_idxdim())
00130       uframe.resize(frame2.get_idxdim());
00131     // do not load image, use passed frame instead
00132     bload_image = false;
00133     // copy frame
00134     idx_copy(frame2, uframe);
00135     // copy name
00136     frame_name = name;
00137     // copy frame_id
00138     frame_id = id;
00139     // reset updated flag
00140     in_updated = true;
00141     // unlock data
00142     mutex_in.unlock();
00143     // declare thread as not available
00144     bavailable = false;
00145     // confirm that we copied data.
00146     return true;
00147   }
00148 
00149   template <typename Tnet>
00150   bool fprop_thread<Tnet>::set_dump(string &frame_fname_,
00151                                     string &dump_fname) {
00152     // lock data (non blocking)
00153     if (!mutex_in.trylock())
00154       return false;
00155     // set the dump name in detector
00156     if (!pdetect)
00157       eblerror("pdetect shoud be allocated");
00158     pdetect->set_outputs_dumping(dump_fname.c_str());
00159     // image file to load and process
00160     frame_name = frame_fname_;
00161     bload_image = true;
00162     // reset updated flag
00163     in_updated = true;
00164     // unlock data
00165     mutex_in.unlock();
00166     // declare thread as not available
00167     bavailable = false;
00168     // confirm that we copied data.
00169     return true;
00170   }
00171 
00172   template <typename Tnet>
00173   bool fprop_thread<Tnet>::dumped() {
00174     // lock data
00175     mutex_out.lock();
00176     // only read data if it has been updated
00177     if (!out_updated) {
00178       // unlock data
00179       mutex_out.unlock();
00180       return false;
00181     }
00182     // reset updated flag
00183     out_updated = false;
00184     // declare thread as available
00185     bavailable = true;
00186     // unlock data
00187     mutex_out.unlock();
00188     // confirm that we copied data.
00189     return true;
00190   }
00191 
00192   template <typename Tnet>
00193   bool fprop_thread<Tnet>::available() {
00194     return bavailable;
00195   }
00196   
00197   template <typename Tnet>
00198   void fprop_thread<Tnet>::set_output_directory(string &out) {
00199     outdir = out;
00200   }
00201 
00202   template <typename Tnet>
00203   void fprop_thread<Tnet>::execute() { 
00204    try {
00205      // configuration
00206      bool       silent         = conf.exists_true("silent");
00207      Tnet       threshold      = (Tnet) conf.try_get_double("threshold", 0);
00208      bool       display        = false;
00209      bool       mindisplay     = conf.exists_true("minimal_display");
00210      bool       display_states = conf.exists_true("display_states");
00211      uint       display_sleep  = conf.try_get_uint("display_sleep", 0);
00212      uint       wid            = 0;     // window id
00213      uint       wid_states     = 0;     // window id
00214      display = conf.exists_true("display_threads");
00215      // load network and weights in a forward-only parameter
00216      parameter<FPROP_SFUNC(Tnet)> theparam;
00217      idx<ubyte> classes;
00218      vector<string> sclasses;
00219      answer_module<SFUNC2(Tnet)> *ans = NULL;
00220      uint noutputs = 1;
00221      intg thick = -1;
00222      if (conf.exists("classes")) {
00223        classes = load_matrix<ubyte>(conf.get_cstring("classes"));
00224        sclasses = ubyteidx_to_stringvector(classes);
00225        ans = create_answer<SFUNC2(Tnet)>(conf, classes.dim(0));
00226        noutputs = ans->get_nfeatures();
00227      }     
00228      module_1_1<FPROP_SFUNC(Tnet)> *net =
00229        create_network<FPROP_SFUNC(Tnet)>(theparam, conf, thick, noutputs);
00230      // loading weights
00231      if (!conf.exists("weights")) { // manual weights
00232        merr << "warning: \"weights\" variable not defined, loading manually "
00233             << "if manual_load defined" << endl;
00234        if (conf.exists_true("manual_load"))
00235          manually_load_network(*((layers<FPROP_SFUNC(Tnet)>*)net), conf);
00236      } else { // multiple-file weights
00237        // concatenate weights if multiple ones
00238        vector<string> w =
00239          string_to_stringvector(conf.get_string("weights"));
00240        mout << "Loading weights from: " << w << endl;
00241        theparam.load_x(w);
00242      }
00243      // detector
00244      detector<SFUNC(Tnet)> detect(*net, sclasses, ans, NULL, NULL,
00245                                         mout, merr);
00246      detection_thread<Tnet>::init_detector(detect, conf, outdir);
00247      pdetect = &detect;
00248      // gui
00249 #ifdef __GUI__
00250      Tnet display_min = -1.7, display_max = 1.7, display_in_min = 0,
00251        display_in_max = 255;
00252      if (conf.exists("display_min"))
00253        display_min = (Tnet) conf.get_double("display_min");
00254      if (conf.exists("display_max"))
00255        display_max = (Tnet) conf.get_double("display_max");
00256      if (conf.exists("display_in_max"))
00257        display_in_max = (Tnet) conf.get_double("display_in_max");
00258      if (conf.exists("display_in_min"))
00259        display_in_min = (Tnet) conf.get_double("display_in_min");
00260      module_1_1_gui     netgui;
00261      wid_states  = display_states ? new_window("network states"):0;
00262      night_mode();
00263      string title = "eblearn fprop: ";
00264      title += _name;
00265      if (display) {
00266        wid = new_window(title.c_str());
00267        mout << "displaying in window " << wid << endl;
00268        night_mode();
00269      }
00270      float              zoom = 1;
00271      if (conf.exists("display_zoom")) zoom = conf.get_float("display_zoom");
00272      detector_gui<FPROP_SFUNC(Tnet)> dgui;
00273 #endif  
00274      // timing variables
00275      timer tpass, toverall;
00276      long ms;
00277      // loop
00278      toverall.start();
00279      // we're ready
00280      bavailable = true;
00281      while(!this->_stop) {
00282        tpass.restart();
00283        // wait until a new image is made available
00284        while (!in_updated && !_stop) {
00285          millisleep(1);
00286        }
00287        if (_stop) break ;
00288        // we got a new frame, reset new frame flag
00289        in_updated = false; // no need to lock mutex
00290        if (!silent) mout << "processing " << frame_name;
00291        // prepare image
00292        if (bload_image) { // load image directly
00293          frame = load_image<Tnet>(frame_name);
00294        } else { // used passed image
00295          // check frame is correctly allocated, if not, allocate.
00296          if (frame.order() != uframe.order())
00297            frame = idx<Tnet>(uframe.get_idxdim());
00298          else if (frame.get_idxdim() != uframe.get_idxdim())
00299            frame.resize(uframe.get_idxdim());
00300          // copy frame
00301          idx_copy(uframe, frame);
00302        }
00303        if (!silent) mout << " (min: " << idx_min(frame)
00304                          << ", max: " << idx_max(frame) << ")" << endl;
00305 
00306        // run detector
00307        if (!display) { // fprop without display
00308          detect.fprop(frame, frame_name.c_str());
00309        }
00310 #ifdef __GUI__
00311        else { // fprop and display
00312          disable_window_updates();
00313          select_window(wid);
00314          clear_window();
00315          string title = _name;
00316          title << ": " << frame_name;
00317          set_window_title(title.c_str());
00318          //      clear_resize_window();
00319          if (mindisplay) {
00320            dgui.display(detect, frame, threshold, frame_name.c_str(),
00321                         0, 0, zoom, display_min, display_max,
00322                         wid, _name.c_str());
00323          } else {
00324            dgui.display_inputs_outputs(detect, frame, threshold,
00325                                        frame_name.c_str(), 0, 0, zoom,
00326                                        display_min, display_max, wid,
00327                                        _name.c_str(),
00328                                        display_in_min, display_in_max);
00329          }
00330          enable_window_updates();
00331        }
00332        if (display_states) {
00333          dgui.display_current(detect, frame, wid_states, NULL, zoom);
00334          select_window(wid);
00335        }
00336        // if (save_video && display) {
00337        //        string fname = viddir;
00338        //        fname += frame_name;
00339        //        save_window(fname.c_str());
00340        //        if (!silent) mout << "saved " << fname << endl;
00341        // }
00342 #endif
00343        ms = tpass.elapsed_milliseconds();
00344        if (!silent) {
00345          mout << "processing=" << ms << " ms ("
00346               << tpass.elapsed() << ")" << endl;
00347        }
00348 #ifdef __DEBUGMEM__
00349        pretty_memory();
00350 #endif
00351        // switch 'updated' flag on to warn we just added new data
00352        set_out_updated();
00353        // display sleep
00354        if (display_sleep > 0) {
00355          mout << "sleeping for " << display_sleep << "ms." << endl;
00356          millisleep(display_sleep);
00357        }
00358      }
00359      mout << "fprop finished. Execution time: " << toverall.elapsed()
00360           << endl;
00361      // free variables
00362      if (net) delete net;
00363    } catch(string &err) { eblerror(err.c_str()); }
00364   }
00365 
00366 } // end namespace ebl
00367 
00368 #endif /* FPROP_THREAD_HPP_ */