libeblearntools
/home/rex/ebltrunk/tools/libeblearntools/include/detection_thread.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2012 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 DETECTION_THREAD_HPP_
00034 #define DETECTION_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 #include "pascal_xml.h"
00049 
00050 #ifdef __GUI__
00051 #include "libeblearngui.h"
00052 #endif
00053 
00054 using namespace std;
00055 
00056 namespace ebl {
00057 
00059   // detection thread
00060 
00061   template <typename Tnet>
00062   detection_thread<Tnet>::
00063   detection_thread(configuration &conf_, mutex *om, const char *name_,
00064                    const char *arg2_, bool sync, t_chans tc)
00065     : thread(om, name_, sync), conf(conf_), arg2(arg2_), frame(120, 160, 1),
00066       mutex_in(), mutex_out(),
00067       in_updated(false), out_updated(false), bavailable(false), bfed(false),
00068       frame_name(""), frame_id(0), outdir(""), total_saved(0), color_space(tc),
00069       silent(false), boot(conf), frame_skipped(false),
00070       frame_loaded(false), pdetect(NULL) {
00071     silent = conf.exists_true("silent");
00072     outdir = get_output_directory(conf);
00073     mout << "Saving outputs to " << outdir << endl;
00074   }
00075 
00076   template <typename Tnet>
00077   detection_thread<Tnet>::~detection_thread() {
00078   }
00079 
00080   template <typename Tnet>
00081   void detection_thread<Tnet>::execute() {
00082    try {
00083      //bool     color          = conf.exists_true("color");
00084      uint       norm_size      = conf.get_uint("normalization_size");
00085      idxdim     dnorm          = idxdim(norm_size, norm_size);
00086      Tnet       threshold      = (Tnet) conf.get_double("threshold");
00087      bool       display        = false;
00088 #ifdef __GUI__
00089      display = conf.exists_true("display")
00090        && conf.exists_true("display_threads");
00091      bool       mindisplay     = conf.exists_true("minimal_display");
00092      bool       save_video     = conf.exists_true("save_video");
00093      bool       display_states = conf.exists_true("display_states");
00094      uint       wid            = 0;     // window id
00095      uint       wid_states     = 0;     // window id
00096 #endif
00097      uint       display_sleep  = conf.get_uint("display_sleep");
00098 //      if (!display && save_video) {
00099 //        // we still want to output images but not show them
00100 //        display = true;
00101 // #ifdef __GUI__
00102 //        set_gui_silent();
00103 // #endif
00104 //      }
00105      // load network and weights in a forward-only parameter
00106      parameter<SFUNC(Tnet)> theparam;
00107      idx<ubyte> classes(1,1);
00108      //try { // try loading classes names but do not stop upon failure
00109      load_matrix<ubyte>(classes, conf.get_cstring("classes"));
00110      // } catch(string &err) {
00111      //   merr << "warning: " << err;
00112      //   merr << endl;
00113      // }
00114      vector<string> sclasses = ubyteidx_to_stringvector(classes);
00115      answer_module<SFUNC2(Tnet)> *ans =
00116        create_answer<SFUNC2(Tnet)>(conf, classes.dim(0));
00117      uint noutputs = ans->get_nfeatures();
00118      intg thick = -1;
00119      module_1_1<SFUNC(Tnet)> *net =
00120        create_network<SFUNC(Tnet)>(theparam, conf, thick, noutputs);
00121      // loading weights
00122      if (conf.exists("weights")) { // manual weights
00123        // concatenate weights if multiple ones
00124        vector<string> w =
00125          string_to_stringvector(conf.get_string("weights"));
00126        mout << "Loading weights from: " << w << endl;
00127        theparam.load_x(w);
00128      } else {
00129        if (conf.exists_true("manual_load")) { // manual load
00130          eblwarn("\"weights\" variable not defined, loading manually "
00131                  << "if manual_load defined");
00132          manually_load_network(*((layers<SFUNC(Tnet)>*)net), conf);
00133        } else { // random weights
00134          eblwarn("No weights to load, randomizing weights");
00135          forget_param_linear fgp(1, 0.5);
00136          net->forget(fgp);
00137        }
00138      }
00139      DEBUGMEM_PRETTY("before detection");
00140      // detector
00141      detector<SFUNC(Tnet)> detect(*net, sclasses, ans, NULL, NULL, mout, merr);
00142      init_detector(detect, conf, outdir);
00143      // keep pointer to detector
00144      pdetect = &detect;
00145      bootstrapping<SFUNC(Tnet)> boot(conf);
00146 
00147      // when a bbox file is given, ignore the processing, load the pre-computed
00148      // bboxes and feed them to the nms (non-maximum suppression).
00149      bboxes boxes(bbox_all, NULL, mout, merr);
00150      boxes.print_saving_type(); // inform user how we save boxes
00151      bool precomputed_boxes = false;
00152      if (conf.exists("bbox_file")) {
00153        precomputed_boxes = true;
00154        string bbfile = conf.get_string("bbox_file");
00155        boxes.load_eblearn(bbfile);
00156      }
00157      bool bmask_class = false;
00158      if (conf.exists("mask_class"))
00159        bmask_class = detect.set_mask_class(conf.get_cstring("mask_class"));
00160 
00161      string viddir = outdir;
00162      viddir += "video/";
00163      mkdir_full(viddir);
00164      // gui
00165 #ifdef __GUI__
00166      Tnet display_min = -1.7, display_max = 1.7, display_in_min = 0,
00167        display_in_max = 255;
00168      uint display_wmax = conf.try_get_uint("display_max_width", 3000);
00169      if (conf.exists("display_min"))
00170        display_min = (Tnet) conf.get_double("display_min");
00171      if (conf.exists("display_max"))
00172        display_max = (Tnet) conf.get_double("display_max");
00173      if (conf.exists("display_in_max"))
00174        display_in_max = (Tnet) conf.get_double("display_in_max");
00175      if (conf.exists("display_in_min"))
00176        display_in_min = (Tnet) conf.get_double("display_in_min");
00177      float display_transp = 0.0;
00178      if (conf.exists("display_bb_transparency"))
00179        display_transp = conf.get_float("display_bb_transparency");
00180      uint qstep1 = 0, qheight1 = 0, qwidth1 = 0,
00181        qheight2 = 0, qwidth2 = 0, qstep2 = 0;
00182      if (conf.exists_bool("queue1")) {
00183        qstep1 = conf.get_uint("qstep1");
00184        qheight1 = conf.get_uint("qheight1");
00185        qwidth1 = conf.get_uint("qwidth1");
00186      }
00187      if (conf.exists_bool("queue2")) {
00188        qstep2 = conf.get_uint("qstep2");
00189        qheight2 = conf.get_uint("qheight2");
00190        qwidth2 = conf.get_uint("qwidth2");
00191      }
00192      module_1_1_gui     netgui;
00193      wid_states  = display_states ? new_window("network states"):0;
00194      night_mode();
00195      string title = "eblearn object recognition: ";
00196      title += _name;
00197      if (display) {
00198        wid = new_window(title.c_str());
00199        mout << "displaying in window " << wid << endl;
00200        night_mode();
00201      }
00202      float              zoom = 1;
00203      if (conf.exists("display_zoom")) zoom = conf.get_float("display_zoom");
00204      bool bbox_show_conf = !conf.exists_false("bbox_show_conf");
00205      bool bbox_show_class = !conf.exists_false("bbox_show_class");
00206      detector_gui<SFUNC(Tnet)>
00207        dgui((conf.exists("show_extracted") ? conf.get_uint("show_extracted"):0),
00208             conf.exists_bool("queue1"), qstep1, qheight1,
00209             qwidth1, conf.exists_bool("queue2"), qstep2, qheight2, qwidth2,
00210             bbox_show_class, bbox_show_conf);
00211      if (bmask_class)
00212        dgui.set_mask_class(conf.get_cstring("mask_class"),
00213                            (Tnet) conf.get_double("mask_threshold"));
00214 #endif
00215      // timing variables
00216      timer tpass, toverall;
00217      long ms;
00218      // loop
00219      toverall.start();
00220      // we're ready
00221      bavailable = true;
00222      while(!this->_stop) {
00223        // wait until a new image is made available
00224        while (!in_updated && !_stop) {
00225          millisleep(1);
00226        }
00227        tpass.restart();
00228        if (_stop) break ;
00229        // we got a new frame, reset new frame flag
00230        in_updated = false; // no need to lock mutex
00231        // check if this frame should be skipped
00232        if (boot.skip_frame(frame_name)) {
00233          skip_frame();
00234          continue ;
00235        } else if (!frame_loaded) {
00236          uframe = load_image<ubyte>(frame_fullname);
00237          mout << "loaded image " << frame_fullname << endl;
00238        }
00239        if (!silent) mout << "processing " << frame_name << endl;
00240        // check frame is correctly allocated, if not, allocate.
00241        if (frame.order() != uframe.order())
00242          frame = idx<Tnet>(uframe.get_idxdim());
00243        else if (frame.get_idxdim() != uframe.get_idxdim())
00244          frame.resize(uframe.get_idxdim());
00245        // copy frame
00246        idx_copy(uframe, frame);
00247        // run detector
00248        if (!display) { // fprop without display
00249          if (precomputed_boxes) {
00250            try {
00251              bboxes *bb = boxes.get_group(frame_name);
00252              idxdim d = boxes.get_group_dims(frame_name);
00253              d.insert_dim(0, 1);
00254              bboxes pruned;
00255              detect.init(d);
00256              detect.fprop_nms(*bb, pruned);
00257              copy_bboxes(pruned); // make a copy of bounding boxes
00258              // resize frame so that caller knows the size of the frame
00259              idxdim framedim = frame.get_idxdim();
00260              if (d.dim(1) == -1 || d.dim(2) == -1)
00261                eblerror("pre-computed boxes must contain full image size, "
00262                         << "but found: " << d);
00263              framedim.setdim(0, d.dim(1));
00264              framedim.setdim(1, d.dim(2));
00265              frame.resize(framedim);
00266            } catch(eblexception &e) {
00267              merr << e << endl;
00268            }
00269          } else {
00270            try {
00271              mout << "starting processing of frame " << frame_name << endl;
00272              bboxes &bb = detect.fprop(frame, frame_name.c_str());
00273              copy_bboxes(bb); // make a copy of bounding boxes
00274            } catch(ebl::eblexception &e) { // detection failed
00275              eblwarn("detection failed: " << e);
00276              clear_bboxes();
00277            }
00278          }
00279        }
00280 #ifdef __GUI__
00281        else { // fprop and display
00282          if (precomputed_boxes) eblerror("not implemented for nms only (TODO)");
00283          disable_window_updates();
00284          select_window(wid);
00285          clear_window();
00286          string title = _name;
00287          title << ": " << frame_name;
00288          set_window_title(title.c_str());
00289          //      clear_resize_window();
00290          try {
00291            if (mindisplay) {
00292              bboxes &bb =
00293                dgui.display(detect, frame, threshold, frame_name.c_str(),
00294                             0, 0, zoom, display_min, display_max,
00295                             wid, _name.c_str(), display_transp);
00296              copy_bboxes(bb); // make a copy of bounding boxes
00297            } else {
00298              // extract & display boxes
00299              bboxes &bb =
00300                dgui.display_inputs_outputs(detect, frame, threshold,
00301                                            frame_name.c_str(), 0, 0, zoom,
00302                                            display_min, display_max, wid,
00303                                            _name.c_str(),
00304                                            display_in_min, display_in_max,
00305                                            display_transp, display_wmax);
00306              // make a copy of bounding boxes
00307              copy_bboxes(bb);
00308            }
00309          } catch(ebl::eblexception &e) { // detection failed
00310            eblwarn("detection failed: " << e);
00311            clear_bboxes();
00312          }
00313          enable_window_updates();
00314        }
00315        if (display_states) {
00316          dgui.display_current(detect, frame, wid_states, NULL, zoom);
00317          select_window(wid);
00318        }
00319        if (save_video && display) {
00320          string fname = viddir;
00321          fname += frame_name;
00322          save_window(fname.c_str());
00323          if (!silent) mout << "saved " << fname << endl;
00324        }
00325 #endif
00326        mout << "processing done for frame " << frame_name << endl;
00327        // bootstrapping
00328        if (conf.exists_true("bootstrapping")) {  
00329          boot.fprop(detect, frame_name);
00330          // add multiple scales if positives and scales are defined
00331          if (conf.exists("gt_scales") && boot.extract_positives()) {
00332            vector<double> scales =
00333              string_to_doublevector(conf.get_cstring("gt_scales"));
00334            for (uint s = 0; s < scales.size(); ++s) {
00335              double f = scales[s];
00336              // downsample input by f
00337              detect.set_resolution(f);
00338              detect.init(frame.get_idxdim(), frame_name.c_str());
00339              detect.fprop(frame, frame_name.c_str());
00340              boot.fprop(detect, frame_name, false, f);
00341            }
00342            detect.set_scaling_original();
00343            detect.init(frame.get_idxdim(), frame_name.c_str());
00344          }
00345          copy_bootstrapping(boot.get_all(), boot.get_bball());
00346 #ifdef __GUI__
00347          // display groundtruth
00348          if (conf.exists_true("display_bootstrapping"))
00349            dgui.display_groundtruth(detect, frame, boot.get_gtall(),
00350                                     boot.get_gtclean(), boot.get_gtrest(),
00351                                     boot.get_bbpos(), boot.get_bbneg(),
00352                                     boot.get_pos(), boot.get_neg(), 0, 0, zoom,
00353                                     display_min, display_max);
00354 #endif
00355        }
00356        total_saved = detect.get_total_saved();
00357        ms = tpass.elapsed_milliseconds();
00358        if (!silent) {
00359          mout << bbs.pretty_short(detect.get_labels());
00360          mout << "processing=" << ms << " ms ("
00361               << tpass.elapsed() << ")" << endl;
00362        }
00363        DEBUGMEM_PRETTY("after detection");
00364        // switch 'updated' flag on to warn we just added new data
00365        set_out_updated();
00366        // display sleep
00367        if (display_sleep > 0) {
00368          mout << "sleeping for " << display_sleep << "ms." << endl;
00369          millisleep(display_sleep);
00370        }
00371        if (conf.exists("save_max") &&
00372            detect.get_total_saved() > conf.get_uint("save_max"))
00373          break ; // limit number of detection saves
00374      }
00375      mout << "detection finished. Execution time: " << toverall.elapsed()<<endl;
00376      // free variables
00377      if (net) delete net;
00378    } catch(string &err) { eblerror(err.c_str()); }
00379   }
00380 
00381   // thread communication //////////////////////////////////////////////////////
00382 
00383   template <typename Tnet>
00384   void detection_thread<Tnet>::init_detector(detector<SFUNC(Tnet)> &detect,
00385                                              configuration &conf,
00386                                              string &odir) {
00387     // multi-scaling parameters
00388     double maxs = conf.exists("max_scale")?conf.get_double("max_scale") : 1.0;
00389     double mins = conf.exists("min_scale")?conf.get_double("min_scale") : 1.0;
00390     t_scaling scaling_type =
00391       (t_scaling) conf.try_get_uint("scaling_type", ORIGINAL);
00392     midxdim scales;    
00393     switch (scaling_type) {
00394     case MANUAL:
00395       if (!conf.exists("scales"))
00396         eblerror("expected \"scales\" variable to be defined in manual mode");
00397       scales = string_to_idxdimvector(conf.get_cstring("scales"));
00398       detect.set_resolutions(scales);
00399       break ;
00400     case ORIGINAL: detect.set_scaling_original(); break ;
00401     case SCALES_STEP:
00402       detect.set_resolutions(conf.get_double("scaling"), maxs, mins);
00403       break ;
00404     case SCALES_STEP_UP:
00405       detect.set_resolutions(conf.get_double("scaling"), maxs, mins);
00406       detect.set_scaling_type(scaling_type);
00407       break ;
00408     default:
00409       detect.set_scaling_type(scaling_type);
00410     }
00411 
00412     // optimize memory usage by using only 2 buffers for entire flow
00413     SBUF<Tnet> input(1, 1, 1), output(1, 1, 1);
00414     if (!conf.exists_false("mem_optimization"))
00415       detect.set_mem_optimization(input, output, true);
00416     // TODO: always keep inputs, otherwise detection doesnt work. fix this.
00417     //                             conf.exists_true("save_detections") ||
00418     //                             (display && !mindisplay));
00419     // zero padding
00420     float hzpad = 0, wzpad = 0;
00421     if (conf.exists("hzpad")) hzpad = conf.get_float("hzpad");
00422     if (conf.exists("wzpad")) wzpad = conf.get_float("wzpad");
00423     detect.set_zpads(hzpad, wzpad);
00424     if (conf.exists("input_min")) // limit inputs size
00425       detect.set_min_resolution(conf.get_uint("input_min"));
00426     if (conf.exists("input_max")) // limit inputs size
00427       detect.set_max_resolution(conf.get_uint("input_max"));
00428     detect.set_silent();
00429     if (conf.exists_bool("save_detections")) {
00430       string detdir = odir;
00431       detdir += "detections";
00432       uint nsave = 0;
00433       if (conf.exists("save_max_per_frame"))
00434         nsave = conf.get_uint("save_max_per_frame");
00435       bool diverse = conf.exists_true("save_diverse");
00436       detdir = detect.set_save(detdir, nsave, diverse);
00437     }
00438     detect.set_scaler_mode(conf.exists_true("scaler_mode"));
00439     if (conf.exists("bbox_decision"))
00440       detect.set_bbox_decision(conf.get_uint("bbox_decision"));
00441     if (conf.exists("bbox_scalings")) {
00442       mfidxdim scalings =
00443         string_to_fidxdimvector(conf.get_cstring("bbox_scalings"));
00444       detect.set_bbox_scalings(scalings);
00445     }
00446 
00447     // nms configuration //////////////////////////////////////////////////////
00448     t_nms nms_type = (t_nms) conf.try_get_uint("nms", 0);
00449     float pre_threshold = conf.try_get_float("pre_threshold", 0.0);
00450     float post_threshold = conf.try_get_float("post_threshold", 0.0);
00451     float pre_hfact = conf.try_get_float("pre_hfact", 1.0);
00452     float pre_wfact = conf.try_get_float("pre_wfact", 1.0);
00453     float post_hfact = conf.try_get_float("post_hfact", 1.0);
00454     float post_wfact = conf.try_get_float("post_wfact", 1.0);
00455     float woverh = conf.try_get_float("woverh", 1.0);
00456     float max_overlap = conf.try_get_float("max_overlap", 1.0);
00457     float max_hcenter_dist = conf.try_get_float("max_hcenter_dist", 0.0);
00458     float max_wcenter_dist = conf.try_get_float("max_wcenter_dist", 0.0);
00459     float vote_max_overlap = conf.try_get_float("vote_max_overlap", 1.0);
00460     float vote_mhd = conf.try_get_float("vote_max_hcenter_dist", 0.0);
00461     float vote_mwd = conf.try_get_float("vote_max_wcenter_dist", 0.0);
00462     detect.set_nms(nms_type, pre_threshold, post_threshold, pre_hfact,
00463                    pre_wfact, post_hfact, post_wfact, woverh, max_overlap,
00464                    max_hcenter_dist, max_wcenter_dist, vote_max_overlap,
00465                    vote_mhd, vote_mwd);
00466     if (conf.exists("raw_thresholds")) {
00467       string srt = conf.get_string("raw_thresholds");
00468       vector<float> rt = string_to_floatvector(srt.c_str());
00469       detect.set_raw_thresholds(rt);
00470     }
00472     if (conf.exists("netdims")) {
00473       idxdim d = string_to_idxdim(conf.get_string("netdims"));
00474       detect.set_netdim(d);
00475     }
00476     if (conf.exists("smoothing"))
00477       detect.set_smoothing(conf.get_uint("smoothing"));
00478     if (conf.exists("background_name"))
00479       detect.set_bgclass(conf.get_cstring("background_name"));
00480     if (conf.exists_true("bbox_ignore_outsiders"))
00481       detect.set_ignore_outsiders();
00482     if (conf.exists("corners_inference"))
00483       detect.set_corners_inference(conf.get_uint("corners_inference"));
00484   }
00485 
00486   template <typename Tnet>
00487   bool detection_thread<Tnet>::get_data(bboxes &bboxes2, idx<ubyte> &frame2,
00488                                         uint &total_saved_, string &frame_name_,
00489                                         uint &id, svector<midx<Tnet> > &samples,
00490                                         bboxes &bbsamples, bool &skipped) {
00491     // lock data
00492     mutex_out.lock();
00493     // only read data if it has been updated
00494     if (!out_updated) {
00495       // unlock data
00496       mutex_out.unlock();
00497       return false;
00498     }
00499     // data is updated, but just to tell we skipped the frame
00500     if (frame_skipped) {
00501       skipped = true;
00502       frame_skipped = false;
00503       // reset updated flag
00504       out_updated = false;
00505       // declare thread as available
00506       bavailable = true;
00507       // unlock data
00508       mutex_out.unlock();
00509       return false;
00510     }
00511     skipped = false;
00512     // clear bboxes
00513     bboxes2.clear();
00514     bboxes2.push_back_new(bbs);
00515     bbs.clear(); // no use for local bounding boxes anymore, clear them
00516     // check frame is correctly allocated, if not, allocate.
00517     if (frame2.order() != uframe.order())
00518       frame2 = idx<ubyte>(uframe.get_idxdim());
00519     else if (frame2.get_idxdim() != uframe.get_idxdim())
00520       frame2.resize(uframe.get_idxdim());
00521     // copy frame
00522     idx_copy(uframe, frame2);
00523     // set total of boxes saved
00524     total_saved_ = total_saved;
00525     // set frame name
00526     frame_name_ = frame_name;
00527     // set frame id
00528     id = frame_id;
00529     // overwrite samples
00530     samples.clear();
00531     bbsamples.clear();
00532     samples.push_back_new(returned_samples);
00533     bbsamples.push_back_new(returned_samples_bboxes);
00534     returned_samples.clear();
00535     returned_samples_bboxes.clear();
00536     // reset updated flag
00537     out_updated = false;
00538     // declare thread as available
00539     bavailable = true;
00540     // unlock data
00541     mutex_out.unlock();
00542     // confirm that we copied data.
00543     return true;
00544   }
00545 
00546   template <typename Tnet>
00547   bool detection_thread<Tnet>::set_data(idx<ubyte> &frame2, string &fullname,
00548                                         string &name, uint id) {
00549     // lock data (non blocking)
00550     if (!mutex_in.trylock())
00551       return false;
00552     // check frame is correctly allocated, if not, allocate.
00553     if (frame2.order() != uframe.order())
00554       uframe = idx<ubyte>(frame2.get_idxdim());
00555     else if (frame2.get_idxdim() != uframe.get_idxdim())
00556       uframe.resize(frame2.get_idxdim());
00557     idx_copy(frame2, uframe);   // copy frame
00558     frame_loaded = true;        // frame is loaded
00559     frame_fullname = fullname;
00560     frame_name = name;          // copy name
00561     frame_id   = id;            // copy frame_id
00562     in_updated = true;          // reset updated flag
00563     bavailable = false;         // declare thread as not available
00564     bfed       = true;          // data has been fed at least once
00565     mutex_in.unlock();          // unlock data
00566     return true;                // confirm that we copied data.
00567   }
00568 
00569   template <typename Tnet>
00570   bool detection_thread<Tnet>::set_data(string &fullname, string &name,uint id){
00571     // lock data (non blocking)
00572     if (!mutex_in.trylock())
00573       return false;
00574     // load image
00575     frame_fullname = fullname;
00576     frame_name = name;          // copy name
00577     frame_id = id;              // copy frame_id
00578     in_updated = true;          // reset updated flag
00579     frame_loaded = false;       // let it be loaded later
00580     bavailable = false;         // declare thread as not available
00581     bfed       = true;          // data has been fed at least once
00582     mutex_in.unlock();          // unlock data
00583     return true;
00584   }
00585 
00586   template <typename Tnet>
00587   bool detection_thread<Tnet>::available() {
00588     return bavailable;
00589   }
00590 
00591   template <typename Tnet>
00592   bool detection_thread<Tnet>::fed() {
00593     return bfed;
00594   }
00595 
00596   template <typename Tnet>
00597   string detection_thread<Tnet>::get_output_directory(configuration &conf) {
00598     string s;
00599     if (conf.exists("output_dir")) s << conf.get_string("output_dir");
00600     s << "/detections";
00601     if (conf.exists_true("nms")) s << "_" << tstamp();
00602     s << "/";
00603     mkdir_full(s);
00604     return s;
00605   }
00606 
00607   // protected methods /////////////////////////////////////////////////////////
00608 
00609   template <typename Tnet>
00610   void detection_thread<Tnet>::clear_bboxes() {
00611     // lock data
00612     mutex_out.lock();
00613     // clear bboxes
00614     bbs.clear();
00615     // unlock data
00616     mutex_out.unlock();
00617   }
00618 
00619   template <typename Tnet>
00620   void detection_thread<Tnet>::copy_bboxes(bboxes &bb) {
00621     // lock data
00622     mutex_out.lock();
00623     bbs = bb;
00624     // unlock data
00625     mutex_out.unlock();
00626   }
00627 
00628   template <typename Tnet>
00629   void detection_thread<Tnet>::copy_bootstrapping(svector<midx<Tnet> > &samples,
00630                                                   bboxes &bb) {
00631     // lock data
00632     mutex_out.lock();
00633     returned_samples = samples;
00634     returned_samples_bboxes = bb;
00635     cout << "samples: " << samples << endl;
00636     cout << "boxes: " << bb << endl;
00637     // unlock data
00638     mutex_out.unlock();
00639   }
00640 
00641   template <typename Tnet>
00642   void detection_thread<Tnet>::set_out_updated() {
00643     // lock data
00644     mutex_out.lock();
00645     // set flag
00646     out_updated = true;
00647     // unlock data
00648     mutex_out.unlock();
00649   }
00650 
00651   template <typename Tnet>
00652   void detection_thread<Tnet>::skip_frame() {
00653     // lock data
00654     mutex_out.lock();
00655     mutex_in.lock();
00656     mout << "frame skipping requested for " << frame_fullname << endl;
00657     // set flag
00658     out_updated = true;
00659     frame_skipped = true;
00660     // unlock data
00661     mutex_in.unlock();
00662     mutex_out.unlock();
00663   }
00664 
00665 } // end namespace ebl
00666 
00667 #endif /* DETECTION_THREAD_HPP_ */