libeblearntools
/home/rex/ebltrunk/tools/libeblearntools/include/bootstrapping.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 BOOTSTRAPPING_HPP_
00034 #define BOOTSTRAPPING_HPP_
00035 
00036 namespace ebl {
00037 
00039   // bootstrapping
00040 
00041   template <typename T, class Tstate>
00042   bootstrapping<T,Tstate>::bootstrapping(configuration &conf_)
00043     : conf(conf_), silent(false) {
00044     gt_path = conf.try_get_string("gt_path", "");
00045     silent = conf.exists_true("silent");
00046     extract_pos = conf.exists_true("gt_extract_pos");
00047     extract_neg = conf.exists_true("gt_extract_neg");
00048     _activated = conf.exists_true("bootstrapping");
00049     _max_size = conf.try_get_intg("bootstrapping_max", limits<intg>::max());
00050     if (_max_size == 0) _max_size = limits<intg>::max();
00051     neg_gt_only = conf.exists_true("gt_neg_gt_only");
00052     neg_threshold = (T) conf.try_get_double("gt_neg_threshold", .0001);
00053     if (conf.exists("bbox_scalings"))
00054       bbox_scalings =string_to_fidxdimvector(conf.get_cstring("bbox_scalings"));
00055     mirror_pos = conf.exists_true("gt_mirror_pos");
00056   }
00057 
00058   template <typename T, class Tstate>
00059   bootstrapping<T,Tstate>::~bootstrapping() {
00060   }
00061 
00062   template <typename T, class Tstate>
00063   void bootstrapping<T,Tstate>::fprop(detector<T,Tstate> &detect,
00064                                       string &fname, bool reset, double scale) {
00065     if (reset) clear();
00066     try {
00067       try {
00068         // load groundtruth data
00069         gt_all = load_groundtruth(fname);
00070         gt_clean = load_clean_groundtruth(fname, conf, gt_rest);
00071         // negs do not need groundtruth data
00072         if (extract_neg)
00073           bbneg = get_negatives
00074             (detect.answers, gt_clean, gt_rest, detect.itl, detect.itr,
00075              detect.ibl, detect.ibr, conf.try_get_float("gt_neg_matching", .5),
00076              conf.try_get_uint("gt_neg_max", 5), detect.bgclass, neg_threshold);
00077         // get bootstrapping boxes
00078         if (extract_pos) {
00079           // scale groundtruth (for positives only)
00080           if (scale != 1.0) {
00081             gt_all.scale_centered(scale, scale);
00082             gt_clean.scale_centered(scale, scale);
00083           }       
00084           bbpos = get_positives
00085             (detect.outputs[0], gt_clean, detect.itl, detect.itr, detect.ibl,
00086              detect.ibr, conf.try_get_float("gt_pos_matching", .5),
00087              conf.try_get_float("gt_min_context", 1.0));
00088         }
00089       } catch (eblexception &e) { eblwarn(e); }
00090       // get preprocessed bootstrappings
00091       bboxes ppbout;
00092       spos = detect.get_preprocessed(bbpos, ppbout);
00093       sneg = detect.get_preprocessed(bbneg, ppbout);
00094       if (mirror_pos) add_mirrors(spos, bbpos);
00095       // fuse all results
00096       bball.push_back(bbpos);
00097       bball.push_back(bbneg);
00098       sall.push_back(spos);
00099       sall.push_back(sneg);
00100     } catch (eblexception &e) { eblwarn(e); }
00101   }
00102 
00103   template <typename T, class Tstate>
00104   void bootstrapping<T,Tstate>::clear() {
00105     sall.clear();
00106     sneg.clear();
00107     spos.clear();
00108     gt_rest.clear();
00109     gt_clean.clear();
00110     gt_all.clear();
00111     bball.clear();
00112     bbneg.clear();
00113     bbpos.clear();
00114   }
00115 
00116   // accessors /////////////////////////////////////////////////////////////////
00117 
00118   template <typename T, class Tstate>
00119   bboxes& bootstrapping<T,Tstate>::get_bbpos() {
00120     return bbpos;
00121   }
00122   
00123   template <typename T, class Tstate>
00124   bboxes& bootstrapping<T,Tstate>::get_bbneg() {
00125     return bbneg;
00126   }
00127   
00128   template <typename T, class Tstate>
00129   bboxes& bootstrapping<T,Tstate>::get_bball() {
00130     return bball;
00131   }
00132   
00133   template <typename T, class Tstate>
00134   bboxes& bootstrapping<T,Tstate>::get_gtall() {
00135     return gt_all;
00136   }
00137   
00138   template <typename T, class Tstate>
00139   bboxes& bootstrapping<T,Tstate>::get_gtclean() {
00140     return gt_clean;
00141   }
00142 
00143   template <typename T, class Tstate>
00144   bboxes& bootstrapping<T,Tstate>::get_gtrest() {
00145     return gt_rest;
00146   }
00147   
00148   template <typename T, class Tstate>
00149   svector<midx<T> >& bootstrapping<T,Tstate>::get_pos() {
00150     return spos;
00151   }
00152   
00153   template <typename T, class Tstate>
00154   svector<midx<T> >& bootstrapping<T,Tstate>::get_neg() {
00155     return sneg;
00156   }
00157 
00158   template <typename T, class Tstate>
00159   svector<midx<T> >& bootstrapping<T,Tstate>::get_all() {
00160     return sall;
00161   }
00162 
00163   template <typename T, class Tstate>
00164   bool bootstrapping<T,Tstate>::activated() {
00165     return _activated;
00166   }
00167   
00168   template <typename T, class Tstate>
00169   bool bootstrapping<T,Tstate>::extract_positives() {
00170     return extract_pos;
00171   }
00172   
00173   template <typename T, class Tstate>
00174   bool bootstrapping<T,Tstate>::groundtruth_found(string &frame_name) {
00175     string s = groundtruth_file(frame_name);
00176     return file_exists(s);
00177   }
00178   
00179   template <typename T, class Tstate>
00180   bool bootstrapping<T,Tstate>::skip_frame(string &frame_name) {
00181     if (!_activated) return false;
00182     bool gtfound = groundtruth_found(frame_name);
00183     if (_activated && !extract_neg && !gtfound) {
00184       return true;
00185     }
00186     if (extract_neg && neg_gt_only && !gtfound) {
00187       cout << "frame skipped because no groundtruth found" << endl;
00188       return true; // extract negatives but only in images with groundtruth
00189     }
00190     if (gtfound) {
00191       // groundtruth is found, let's check how many objects are filtered
00192       bboxes b, rest;
00193       b = load_clean_groundtruth(frame_name, conf, rest);
00194       if (b.size() == 0 && !extract_neg) {
00195         cout << "Skipping frame " << frame_name 
00196              << " because no clean objects were found." << endl;
00197         return true;
00198       }
00199     }
00200     return false;
00201   }
00202 
00203   template <typename T, class Tstate>
00204   intg bootstrapping<T,Tstate>::max_size() {
00205     return _max_size;
00206   }
00207 
00208   // dataset methods ///////////////////////////////////////////////////////////
00209 
00210   template <typename T, class Tstate>
00211   void bootstrapping<T,Tstate>::save_dataset(svector<midx<T> > &samples,
00212                                              bboxes &bb, string &outdir,
00213                                              idx<ubyte> &classes) {
00214     if (samples.size() != bb.size())
00215       eblerror("expected same number of samples and boxes but got "
00216                << samples.size() << " and " << bb.size());
00217     if (samples.size() == 0) eblerror("expected at least 1 sample");
00218     // find max number of submatrices
00219     intg order = samples[0].order(), dim = samples[0].dim(0);
00220     if (order != 1) eblerror("expected order 1");
00221     for (intg i = 0; i < (intg) samples.size(); ++i) {
00222       if (samples[i].order() != order)
00223         eblerror("expected same order for all samples but found "
00224                  << samples[i].order() << " and " << order);
00225       if (samples[i].dim(0) > dim) dim = samples[i].dim(0);
00226     }
00227     cout << "Max number of sub-matrices for each sample is: " << dim << endl;
00228     // create a single midx with all samples
00229     midx<T> all(samples.size(), dim);
00230     idx<intg> scales(samples.size()), labels(samples.size());
00231     all.clear();
00232     idx_clear(scales);
00233     // loop on samples
00234     for (intg i = 0; i < (intg) samples.size(); ++i) {
00235       midx<T> &sample = samples[i];
00236       bbox &b = bb[i];
00237       // loop on sample's submatrix
00238       for (intg j = 0; j < sample.dim(0); ++j) {
00239         idx<T> layer = sample.get(j);
00240         all.set(layer, i, j);
00241       }
00242       // set scale & label
00243       scales.set(b.oscale_index, i);
00244       labels.set(b.class_id, i);
00245     }
00246     // save files
00247     string name;
00248     name << "bootstrapping_" << conf.get_string("gt_name");
00249     string data_fname, scales_fname, labels_fname, classes_fname;
00250     cout << "saving dataset..." << endl;
00251     data_fname << outdir << "/" << name << "_" << DATA_NAME << MATRIX_EXTENSION;
00252     save_matrices(all, data_fname);
00253     cout << "saved " << data_fname << " (" << all << ")" << endl;
00254     scales_fname << outdir << "/" << name << "_" << SCALES_NAME
00255                  << MATRIX_EXTENSION;
00256     save_matrix(scales, scales_fname);
00257     cout << "saved " << scales_fname << " (" << scales << ")" << endl;
00258     labels_fname << outdir << "/" << name << "_" << LABELS_NAME
00259                  << MATRIX_EXTENSION;
00260     save_matrix(labels, labels_fname);
00261     cout << "saved " << labels_fname << " (" << labels << ")" << endl;
00262     classes_fname << outdir << "/" << name << "_" << CLASSES_NAME
00263                  << MATRIX_EXTENSION;
00264     save_matrix(classes, classes_fname);
00265     cout << "saved " << classes_fname << " (" << classes << ")" << endl;
00266   }
00267     
00268   // internal methods //////////////////////////////////////////////////////////
00269 
00270   template <typename T, class Tstate>
00271   string bootstrapping<T,Tstate>::groundtruth_file(string &frame_name) {
00272     string xml = "";
00273     xml << gt_path << "/" << noext_name(frame_name.c_str()) << ".xml";
00274     return xml;
00275   }
00276   
00277   template <typename T, class Tstate>
00278   bboxes bootstrapping<T,Tstate>::load_groundtruth(string &frame_name) {
00279     bboxes gt;
00280     // look for xml version
00281     xml_fullname = groundtruth_file(frame_name);
00282     if (file_exists(xml_fullname)) {
00283       if (!silent) cout << "Found groundtruth file: " << xml_fullname << endl;
00284       gt = pascal_xml::get_bboxes(xml_fullname);
00285       EDEBUG("groundtruth boxes: " << gt);
00286     } else eblthrow("groundtruth file not found " << xml_fullname);
00287     return gt;
00288   }
00289     
00290   template <typename T, class Tstate>
00291   bboxes bootstrapping<T,Tstate>::load_clean_groundtruth
00292   (string &frame_name, configuration &conf, bboxes &rest) {
00293     rest.clear();
00294     // load filtering settings
00295     float minvisibility = conf.try_get_float("gt_minvisibility", 0);
00296     float min_ar = conf.try_get_float("gt_min_aspect_ratio", 0);
00297     float max_ar = conf.try_get_float("gt_max_aspect_ratio", 1);
00298     idxdim mindims(1, 1), minborders;
00299     vector<string> included;
00300     if (conf.exists("gt_mindims"))
00301       mindims = string_to_idxdim(conf.get_cstring("gt_mindims"));
00302     if (conf.exists("gt_minborders"))
00303       minborders = string_to_idxdim(conf.get_cstring("gt_minborders"));
00304     if (conf.exists("gt_included"))
00305       included = string_to_stringvector(conf.get_string("gt_included"));    
00306     bboxes gt;
00307     // look for xml version
00308     xml_fullname = groundtruth_file(frame_name);
00309     if (file_exists(xml_fullname)) {
00310       if (!silent)
00311         cout << "Found groundtruth file: " << xml_fullname << endl
00312              << "Filtering based on min visibility " << minvisibility
00313              << ", aspect ratio min " << min_ar << " max " << max_ar
00314              << ", mindims " << mindims << ", minborders " << minborders
00315              << ", included classes: " << included << endl;
00316       gt = pascal_xml::get_filtered_bboxes(xml_fullname, minvisibility, min_ar,
00317                                            max_ar, mindims, minborders,
00318                                            included, rest);
00319       EDEBUG("clean groundtruth boxes: " << gt);
00320     } else eblthrow("groundtruth file not found " << xml_fullname);
00321     return gt;
00322   }  
00323   
00324   template <typename T, class Tstate>
00325   bboxes bootstrapping<T,Tstate>::get_positives
00326   (mstate<Tstate> &outputs, bboxes &groundtruth, mfidxdim &topleft,
00327    mfidxdim &topright, mfidxdim &bottomleft, mfidxdim &bottomright,
00328    float matching, float mincontext) {
00329     bboxes res;
00330     float min_overlap = .9;
00331     float closest_overlap = 0, closest_overlap2 = 0, closest_match = 0;
00332     uint closest_overlap_scale = 0, closest_overlap2_scale = 0, 
00333       closest_match_scale = 0;
00334     cout << "groundtruth: " << groundtruth << endl;
00335     // loop on groundtruth boxes
00336     for (bboxes::iterator i = groundtruth.begin(); i != groundtruth.end(); ++i){
00337       bbox &gtraw = *i;
00338       bboxes candidates;
00339       // loop on outputs maps
00340       for (uint o = 0; o < outputs.size(); ++o) {
00341         Tstate &out = outputs[o];
00342         // input space corners
00343         fidxdim &tl = topleft[o], &tr = topright[o], &bl = bottomleft[o];
00344         // steps in input space
00345         double hf = (bl.offset(1) - tl.offset(1)) / out.x.dim(1);
00346         double wf = (tr.offset(2) - tl.offset(2)) / out.x.dim(2);
00347         // box size for this map
00348         bbox b(0, 0, tl.dim(1), tl.dim(2));
00349         b.o.height = 1;
00350         b.o.width = 1;
00351         // normalize width of gt
00352         bbox gt = gtraw;
00353         gt.scale_width(b.width / b.height);
00354         bbox gtcontext = gt;
00355         gtcontext.scale_centered(mincontext, mincontext);
00356         if (gt.class_id >= out.x.dim(0))
00357           eblerror("expected dim 0 of " << out.x << " to be > than "
00358                    << gt.class_id);     
00359         // // box has to be able to include groundtruth entirely, otherwise skip
00360         // rect<float> gt2(0, 0, gt.height, gt.width);
00361         // float gt2_overlap = gt2.overlap_ratio(b);
00362         // if (gt2_overlap > closest_overlap) {
00363         //   closest_overlap = gt2_overlap;
00364         //   closest_overlap_scale = o;
00365         // }
00366         // if (gt2_overlap < 1.0) {
00367         //   EDEBUG("ruling out scale " << o << " because box " << b
00368         //   << " doesn't overlap completely with gt " << gt2);
00369         //   continue ;
00370         // }
00371         // apply scalings to box
00372         float hscale = 1, wscale = 1;
00373         if (o < bbox_scalings.size()) {
00374           fidxdim &scaling = bbox_scalings[o];
00375           hscale = scaling.dim(0);
00376           wscale = scaling.dim(1);
00377         }
00378         // loop on width
00379         int wmax = (int) ceil((gt.w0 + gt.width) / wf);
00380         int w = (int) std::max((double)0, floor((gt.w0 - b.width/2 - tl.offset(2)) / wf));
00381         // force minimum region to explore to at least 4 pixels
00382         int wadd = std::max(wmax - w, 2);
00383         w -= wadd;
00384         wmax += wadd;
00385         for ( ; w < wmax; ++w) {
00386           // loop on height
00387           int hmax = (int) ceil((gt.h0 + gt.height) / hf);
00388           int h = (int) std::max((double)0, floor((gt.h0 - b.height/2 - tl.offset(1)) / hf));
00389           // force minimum region to explore to at least 4 pixels
00390           int hadd = std::max(hmax - h, 2);
00391           h -= hadd;
00392           hmax += hadd;
00393           for ( ; h < hmax; ++h) {
00394             b.h0 = tl.offset(1) + h * hf;
00395             b.w0 = tl.offset(2) + w * wf;
00396             bbox b2 = b;
00397             b2.scale_centered(hscale, wscale);
00398             EDEBUG("scale " << o << " gt " << (rect<float>&)gt 
00399                   << "gtcontext " << (rect<float>&)gtcontext << " b " << (rect<float>&)b2
00400                   << " matching: " << b2.match(gtcontext));
00401             // skip this box if not matching gt more than minimum match
00402             float bmatch = b2.match(gt);
00403             if (bmatch > closest_match) {
00404               closest_match = bmatch;
00405               closest_match_scale = o;
00406             }
00407             if (o > 0 && o < outputs.size() -1
00408                 && bmatch < matching) continue ;
00409 
00410             // skip this box if not including gt entirely
00411             EDEBUG("overlap ratio " << gt.overlap_ratio(b));
00412             float gtoverlap = gtcontext.overlap_ratio(b);
00413             if (gtoverlap > closest_overlap2) {
00414               closest_overlap2 = gtoverlap;
00415               closest_overlap2_scale = o;
00416             }
00417             if (o < outputs.size() - 1 && gtoverlap < min_overlap) continue ;
00418             // bbox is a potential candidate, add it
00419             // // use output value as confidence
00420             // b.confidence = (float) out.x.get(gt.class_id, h, w);
00421             // use matching value as confidence
00422             b.confidence = bmatch;
00423             // b.iscale_index = scale_indices[a]; // scale index
00424             // b.oscale_index = a; // scale index
00425             // b.i.h0 = ptl.offset(1) + h * phf;
00426             // b.i.w0 = ptl.offset(2) + w * pwf;
00427             // b.i.height = ptl.dim(1);
00428             // b.i.width = ptl.dim(2);
00429             b.o.h0 = h; // answer height in output
00430             b.o.w0 = w; // answer height in output
00431             b.class_id = gt.class_id;
00432             b.iscale_index = o;
00433             b.oscale_index = o;
00434             EDEBUG("adding candidate " << (rect<float>&)b);
00435             candidates.push_back_new(b);
00436           }
00437         }
00438       }
00439       EDEBUG("candidates: " << candidates);
00440       // pick highest score candidates
00441       bboxes highests = candidates.get_most_confidents();
00442       // out of all highest, pick one with closest center to groundtruth
00443       float dist = limits<float>::max();
00444       int best = -1;
00445       for (uint i = 0; i < highests.size(); ++i) {
00446         if (highests[i].center_distance(gtraw) < dist) {
00447           best = (int) i;
00448           dist = highests[i].center_distance(gtraw);
00449         }
00450       }
00451       if (best >= 0) res.push_back_new(highests[best]);
00452 #ifdef __DEBUG__
00453       cerr << "candidate with strongest confidence for grountruth " << gtraw
00454            << " is: ";  
00455       if (best >= 0) cerr << highests[best] << endl;
00456       else cerr << "none" << endl;
00457 #endif
00458       if (best < 0) 
00459         eblwarn("no positive sample found for groundtruth bbox " << gtraw 
00460                 << " in file " << xml_fullname 
00461                 << ", highest overlap " << closest_overlap 
00462                 << " with scale " << closest_overlap_scale
00463                 << ", highest overlap2 " << closest_overlap2 
00464                 << " with scale " << closest_overlap2_scale
00465                 << " (min overlap " << min_overlap << ")"
00466                 << ", closest matching " << closest_match
00467                 << " with scale " << closest_match_scale
00468                 << " (min match " << matching << ")");
00469       cout << "best: " << best << " gt " << gtraw << endl;
00470     }
00471     EDEBUG("positive bootstraps: " << res);
00472     return res;
00473   }
00474     
00475   template <typename T, class Tstate>
00476   bboxes bootstrapping<T,Tstate>::get_negatives
00477   (mstate<Tstate> &answers, bboxes &filtered, bboxes &nonfiltered,
00478    mfidxdim &topleft, mfidxdim &topright, mfidxdim &bottomleft,
00479    mfidxdim &bottomright, float matching, uint nmax, int neg_id, T threshold) {
00480     bboxes res;
00481     // extract all non-negative windows
00482     // loop on outputs maps
00483     for (uint o = 0; o < answers.size(); ++o) {
00484       bboxes pos2, res2;
00485       Tstate &ans = answers[o];
00486       // input space corners
00487       fidxdim &tl = topleft[o], &tr = topright[o], &bl = bottomleft[o];
00488       // steps in input space
00489       double hf = (bl.offset(1) - tl.offset(1)) / ans.x.dim(1);
00490       double wf = (tr.offset(2) - tl.offset(2)) / ans.x.dim(2);
00491       // box size for this map
00492       bbox b(0, 0, tl.dim(1), tl.dim(2));
00493       b.o.height = 1;
00494       b.o.width = 1;
00495       // apply scalings to box
00496       float hscale = 1, wscale = 1;
00497       if (o < bbox_scalings.size()) {
00498         fidxdim &scaling = bbox_scalings[o];
00499         hscale = scaling.dim(0);
00500         wscale = scaling.dim(1);
00501       }
00502       // loop on width
00503       for (uint w = 0; w < ans.x.dim(2); ++w) {
00504         // loop on height
00505         for (uint h = 0; h < ans.x.dim(1); ++h) {
00506           b.class_id = (int) ans.x.get(0, h, w);
00507           // ignore negative answers
00508           if (b.class_id == neg_id) continue ;
00509           b.confidence = (float) ans.x.get(1, h, w);
00510           // confidence is below threshold, ignore
00511           if (b.confidence < threshold) continue ;
00512           // not negative, enqueue
00513           b.h0 = tl.offset(1) + h * hf;
00514           b.w0 = tl.offset(2) + w * wf;
00515           b.o.h0 = h; // answer height in output
00516           b.o.w0 = w; // answer height in output
00517           b.oscale_index = o;
00518           pos2.push_back_new(b);
00519         }
00520       }
00521       // sort positives by confidence
00522       pos2.sort_by_confidence();
00523       // extract nmax most confident
00524       for (uint i = 0; i < pos2.size() && res2.size() < nmax; ++i) {
00525         bbox &b = pos2[i];
00526         bbox b2 = b;
00527         b2.scale_centered(hscale, wscale);
00528         bool accept = true;
00529         // check that b doesn't overlap more than matching with filtered gt
00530         for (bboxes::iterator j = filtered.begin();j != filtered.end();++j){
00531           if (b.class_id == j->class_id && b2.match(*j) > matching) {
00532             accept = false;
00533             break ;
00534           }
00535         }
00536         if (!accept) continue ;
00537         // check that b doesn't overlap at all with non-filtered gt
00538         for (bboxes::iterator j = nonfiltered.begin();
00539              j != nonfiltered.end(); ++j) {
00540           if (b.overlap(*j)) {
00541             accept = false;
00542             break ;
00543           }
00544         }
00545         if (!accept) continue ;
00546         // check that b doesn't overlap at all with other accepted positives
00547         for (bboxes::iterator j = res2.begin();j != res2.end();++j){
00548           if (b.overlap(*j)) {
00549             accept = false;
00550             break ;
00551           }
00552         }
00553         if (!accept) continue ;
00554         // all checks passed, keep this box
00555         if (accept) res2.push_back(b);
00556       }
00557       res.push_back(res2);
00558       if (res2.size() == 0) eblwarn("no negatives found for scale " << o);
00559     }
00560     // set all boxes to negative id
00561     for (bboxes::iterator j = res.begin(); j != res.end(); ++j)
00562       j->class_id = neg_id;
00563     EDEBUG("negative bootstraps: " << res);
00564     return res;
00565   }
00566 
00567   template <typename T, class Tstate>
00568   void bootstrapping<T,Tstate>::add_mirrors(svector<midx<T> > &samples,
00569                                             bboxes &boxes) {
00570     svector<midx<T> > mirrors;
00571     bboxes bmirrors;
00572     for (uint i = 0; i < samples.size(); ++i) {
00573       bbox &b = boxes[i];
00574       midx<T> &s = samples[i];
00575       midx<T> flipped = idx_flip(s, 2);
00576       mirrors.push_back_new(flipped);
00577       bmirrors.push_back_new(b);
00578     }
00579     samples.push_back(mirrors);
00580     boxes.push_back(bmirrors);
00581   }
00582     
00583 } // end namespace ebl
00584 
00585 #endif /* BOOTSTRAPPING_HPP_ */