libeblearntools
/home/rex/ebltrunk/tools/libeblearntools/include/dataset.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2009 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 DATASET_HPP_
00034 #define DATASET_HPP_
00035 
00036 #include <algorithm>
00037 #include <sys/stat.h>
00038 #include <sys/types.h>
00039 #include <limits>
00040 #include <typeinfo>
00041 
00042 #ifdef __GUI__
00043 #include "libidxgui.h"
00044 #endif
00045 
00046 #include "defines_tools.h"
00047 #include "sort.h"
00048 #include "tools_utils.h"
00049 
00050 #ifdef __BOOST__
00051 #define BOOST_FILESYSTEM_VERSION 2
00052 #include "boost/filesystem.hpp"
00053 #include "boost/regex.hpp"
00054 using namespace boost::filesystem;
00055 using namespace boost;
00056 #endif
00057 
00058 using namespace std;
00059 
00060 namespace ebl {
00061 
00063   // jitter methods
00064 
00065   template <typename T>
00066   rect<T> jitter::get_rect(const rect<T> &r, float ratio) {
00067     rect<T> j = r; // jittered box
00068     j.scale_centered(s, s); // apply scale jitter
00069     j.h0 += (T) (h * ratio); // apply height offset jitter
00070     j.w0 += (T) (w * ratio); // apply width offset jitter
00071     // EDEBUG("jittering rect " << r << " with spatial jitter " << h << "x" << w
00072     //    << " and spatial jitter ratio " << ratio << ": " << j);
00073     return j;
00074   }
00075   
00077   // constructors & initializations
00078 
00079   template <class Tdata>
00080   dataset<Tdata>::dataset(const char *name_, const char *inroot_) {
00081     // initialize members
00082     allocated = false;
00083     string bname = ebl::basename(name_);
00084     set_name(bname);
00085     if (inroot_) {
00086       inroot = inroot_;
00087       inroot += "/";
00088     } else inroot = ebl::dirname(name_);
00089     no_outdims = true;
00090     outdims = idxdim(96, 96, 1);
00091     height = outdims.dim(0);
00092     width = outdims.dim(1);
00093     mindims = idxdim(1, 1);
00094     maxdims = idxdim(1, 1);
00095     maxdims_set = false;
00096     max_data = 0;
00097     max_data_set = false;
00098     total_samples = 0;
00099     display_extraction = false;
00100     display_result = false;
00101     bsave_display = false;
00102     // preprocessing
00103     extension = IMAGE_PATTERN_MAT;
00104     sleep_display = false;
00105     sleep_delay = 0;
00106     // assuming already processed data, but the user can still require
00107     // processing via the set_preprocessing method.
00108     do_preprocessing = false;
00109     scale_mode = false;
00110     scales.push_back(1); // initialize with scale 1
00111     data_cnt = 0;
00112     interleaved_input = true;
00113     load_planar = false;
00114     max_per_class_set = false;
00115     mpc = (numeric_limits<intg>::max)();
00116     dynamic_init_drand(); // initialize random seed
00117     usepose = false;
00118     useparts = false;
00119     usepartsonly = false;
00120     save_mode = DYNSET_SAVE;
00121     individual_save = true; // save individual files by default.
00122     separate_layers_save = false; // save layers in separate files or not.
00123     bbox_woverh = 0.0; // 0.0 means not set
00124     force_label = "";
00125     nclasses = 0;
00126     add_errors = 0;
00127     nopadded = false;
00128     wmirror = false;
00129     // jitter
00130     tjitter_step = 0;
00131     tjitter_hmin = 0;
00132     tjitter_hmax = 0;
00133     tjitter_wmin = 0;
00134     tjitter_wmax = 0;
00135     sjitter_steps = 0;
00136     sjitter_min = 0;
00137     sjitter_max = 0;
00138     rjitter_steps = 0;
00139     rjitter = 0;
00140     njitter = 0;
00141     minvisibility = 0;
00142     bjitter = false;
00143     nlayers = 1;
00144     //videobox
00145     do_videobox = false;
00146     videobox_nframes = 0;
00147     videobox_stride = 0;
00148     load_img = midx<Tdata>(1);
00149 #ifndef __BOOST__
00150     eblerror(BOOST_LIB_ERROR);
00151 #endif
00152   }
00153 
00154   template <class Tdata>
00155   dataset<Tdata>::~dataset() {
00156     for (uint i = 0; i < ppmods.size(); ++i)
00157       delete ppmods[i];
00158   }
00159 
00160   template <class Tdata>
00161   bool dataset<Tdata>::alloc(intg max) {
00162     // save maximum number of samples if specified
00163     if (max > 0) {
00164       max_data = max;
00165       max_data_set = true;
00166       cout << "Limiting dataset to " << max << " samples." << endl;
00167     }
00168     if (classes.size() == 0)
00169       eblerror("found 0 class");
00170     cout << "Found: "; print_classes(); cout << "." << endl;
00171     // (re)init max per class, knowing number of classes
00172     intg m = (numeric_limits<intg>::max)();
00173     if (max_per_class_set) { // mpc has already been set
00174       m = mpc;
00175       set_max_per_class(m);
00176     }
00177     // allocate 
00178     if (!allocate(total_samples, outdims))
00179       eblerror("allocation failed");
00180     // alloc tallies
00181     add_tally = idx<intg>(classes.size());
00182     idx_clear(add_tally);
00183     return true;
00184   }
00185   
00187   // data extraction
00188 
00189   template <class Tdata>
00190   bool dataset<Tdata>::extract() {
00191     // extract
00192 #ifdef __BOOST__
00193     if (!allocated && !scale_mode && !strcmp(save_mode.c_str(), DATASET_SAVE))
00194       return false;
00195     cmatch what;
00196     regex hidden_dir(".svn");    
00197     bool found = false;
00198     xtimer.start(); // start timing extraction
00199     processed_cnt = 0;
00200     directory_iterator end_itr; // default construction yields past-the-end
00201     for (directory_iterator itr(inroot); itr != end_itr; itr++) {
00202 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
00203       if (is_directory(itr->status())
00204           && !regex_match(itr->leaf().c_str(), what, hidden_dir)) {
00205         process_dir(itr->path().string(), extension, itr->leaf());
00206 #else
00207       if (is_directory(itr->status())
00208           && !regex_match(itr->path().filename().c_str(), what, hidden_dir)) {
00209         process_dir(itr->path().string(), extension, itr->path().filename());
00210 #endif
00211         found = true;
00212       }}
00213     if (found) {
00214       cerr << "Samples adding failures: " << add_errors << endl;
00215     } else {
00216       cerr << "No class found in " << inroot
00217            << ", extracting images in local directory with name \"unknown\""
00218            << endl;
00219       process_dir(inroot, extension, "unknown");
00220       return true;
00221     }
00222     cout << "Extraction time: " << xtimer.elapsed() << endl;
00223 #endif /* __BOOST__ */
00224     return true;
00225   }
00226   
00227   template <class Tdata>
00228   void dataset<Tdata>::extract_statistics() {
00229     eblerror("not implemented");
00230   }
00231   
00233   // data
00234 
00235   template <class Tdata>
00236   bool dataset<Tdata>::split_max_and_save(const char *name1, const char *name2,
00237                                           intg max, const string &outroot) {
00238     dataset<Tdata> ds1(name1);
00239     dataset<Tdata> ds2(name2);
00240     ds1.set_outdims(outdims);
00241     ds2.set_outdims(outdims);
00242     // if excluded classes exist, set them in ds1 and ds2
00243     if (exclude.size() > 0) {
00244       ds1.set_exclude(exclude);
00245       ds2.set_exclude(exclude);
00246     }
00247     split_max(ds1, ds2, max);
00248     bool ret1 = ds1.save(outroot);
00249     bool ret2 = ds2.save(outroot);
00250     return ret1 || ret2;
00251   }
00252   
00253   template <class Tdata>
00254   void dataset<Tdata>::split_max(dataset<Tdata> &ds1, dataset<Tdata> &ds2,
00255                                  intg max) {
00256     cout << "Splitting \"" << name << "\" into datasets \"";
00257     cout << ds1.name << "\" and \"" << ds2.name << "\", limiting dataset \"";
00258     cout << ds1.name << "\" to " << max << " samples per class, the rest ";
00259     cout << "going to \"" << ds2.name << "\"." << endl;
00260 
00261     // copy classes strings
00262     if (classes.size() > 0) {
00263       idx<ubyte> classidx = build_classes_idx(classes);
00264       ds1.set_classes(classidx);
00265       ds2.set_classes(classidx);
00266     }
00267     ds1.nclasses = nclasses;
00268     ds2.nclasses = nclasses;
00269     // set max samples per class for dataset 1 (ds2 takes whatever is left)
00270     ds1.set_max_per_class(max);
00271     // split
00272     split(ds1, ds2);
00273   }
00274 
00275   template <class Tdata>
00276   void dataset<Tdata>::shuffle() {
00277     cout << "Shuffling dataset \"" << name << "\"." << endl;
00278     dynamic_init_drand(); // initialize random seed
00279     idx_shuffle_together(data, labels, 0);
00280   }
00281   
00283   // data preprocessing
00284 
00285   template <class Tdata>
00286   void dataset<Tdata>::set_planar_loading() {
00287     cout << "Inputs are loaded as planar." << endl;
00288     load_planar = true;
00289   }
00290 
00292   // accessors
00293     
00294   template <class Tdata>
00295   const idxdim& dataset<Tdata>::get_sample_outdim() {
00296     return outdims;
00297   }
00298 
00299   template <class Tdata>
00300   intg dataset<Tdata>::size() {
00301     return data_cnt;
00302   }
00303 
00304   template <class Tdata>
00305   t_label dataset<Tdata>::get_label_from_class(const string &class_name) {
00306     t_label label = 0;
00307     vector<string>::iterator res;
00308     res = find(classes.begin(), classes.end(), class_name);
00309     if (res == classes.end()) { // not found
00310       return -42; // excluded class
00311     }
00312     // found
00313     label = res - classes.begin();
00314     return label;
00315   }
00316   
00317   template <class Tdata>
00318   void dataset<Tdata>::set_display(bool display_) {
00319 #ifdef __GUI__
00320     if (display_) {
00321       cout << "Enabling display." << endl;
00322       new_window("Dataset compiler");
00323       display_extraction = display_;
00324     }
00325 #endif /* __GUI__ */
00326   }
00327     
00328   template <class Tdata>
00329   void dataset<Tdata>::set_sleepdisplay(uint delay) {
00330     if (delay > 0) {
00331       cout << "Enabling sleeping display for " << delay << "ms." << endl;
00332       sleep_display = true;
00333       sleep_delay = delay;
00334     }
00335   }
00336     
00337   template <class Tdata>
00338   void dataset<Tdata>::
00339   set_preprocessing(vector<resizepp_module<fs(Tdata)>*> &p){
00340     if (p.size() == 0) {
00341       cout << "No preprocessing." << endl;
00342       return ;
00343     }
00344     pp_names = "";
00345     nlayers = 0;
00346     for (uint i = 0; i < p.size(); ++i) {
00347       ppmods.push_back(p[i]);
00348       pp_names << p[i]->name();
00349       if (i + 1 != p.size()) pp_names << ",";
00350       nlayers += p[i]->nlayers();
00351       if (p[i]->nlayers() == 0)
00352         eblerror("expected at least 1 layer in output of preprocessing module "
00353                  << p[i]->name());
00354     }
00355     cout << "Setting preprocessing to: " << pp_names << endl;
00356     cout << "Preprocessing produces " << nlayers << " layers per sample."
00357          << endl;
00358     cout << "Preprocessing modules:" << endl;
00359     for (uint i = 0; i < p.size(); ++i)
00360       cout << i << ": " << ppmods[i]->describe() << endl;
00361     do_preprocessing = true;
00362   }
00363     
00364   template <class Tdata>
00365   bool dataset<Tdata>::full(t_label label) {
00366     if (!total_samples) // we did not count samples, no opinion
00367       return false;
00368     if ((max_data_set && (data_cnt >= max_data)) ||
00369         ((data.order() > 0) && (data_cnt >= data.dim(0))))
00370       return true;
00371     if (!scale_mode) {
00372       if (label == -42) // excluded class
00373         return true;
00374       if (max_per_class_set && (label >= 0) &&
00375           (add_tally.get(label) >= max_per_class.get(label)))
00376         return true;
00377     }
00378     return false;
00379   }
00380 
00382   // print methods
00383   
00384   template <class Tdata>
00385   void dataset<Tdata>::print_classes() {
00386     cout << nclasses << " classe";
00387     if (nclasses > 1) cout << "s";
00388     if (classes.size() > 0) {
00389       cout << " (";
00390       uint i;
00391       for (i = 0; i < classes.size() - 1; ++i)
00392         cout << classes[i] << ", ";
00393       cout << classes[i] << ")";
00394     }
00395   }
00396 
00397   template <class Tdata>
00398   void dataset<Tdata>::print_stats() {
00399     compute_stats();
00400     // print stats
00401     cout << "Dataset \"" << name << "\" contains " << data_cnt;
00402     cout << " samples (of dimensions " << outdims << " and ";
00403     cout << typeid(Tdata).name() << " precision)";
00404     cout << ", distributed in " << nclasses << " classes";
00405     if (classes.size() > 0) {
00406       uint i;
00407       cout << ": ";
00408       for (i = 0; i < classes.size() - 1; ++i)
00409         cout << class_tally.get(i) << " \"" << classes[i] << "\", ";
00410       cout << class_tally.get(i) << " " << classes[i] << "\".";
00411     }
00412     cout << endl;
00413   }
00414   
00416   // I/O
00417     
00418   template <class Tdata>
00419   bool dataset<Tdata>::load(const string &root) {
00420     string fname;
00421     string root1 = root;
00422     root1 += "/";
00423     cout << "Loading dataset " << name << " from " << root1;
00424     cout << name << "_*" << MATRIX_EXTENSION << endl;
00425     // load data
00426     data = midx<Tdata>(1,1);
00427     fname = root1; fname += data_fname;
00428     loading_error(data, fname);
00429     // load labels
00430     labels = idx<t_label>(1);
00431     fname = root1; fname += labels_fname;
00432     loading_error(labels, fname);
00433     // load ids
00434     ids = idx<intg>(1);
00435     fname = ""; fname << root1 << "/" << ids_fname;
00436     loading_warning<intg>(ids, fname);
00437     // load jitter
00438     fname = root1; fname += jitters_fname;
00439     loading_warning<t_jitter>(jitters, fname);
00440     // load classes
00441     idx<ubyte> classidx;
00442     classidx = idx<ubyte>(1,1);
00443     fname = root1; fname += classes_fname;
00444     if (loading_warning(classidx, fname))
00445       set_classes(classidx);
00446     else
00447       nclasses = idx_max(labels) + 1;
00448     // load classpairs
00449     classpairs = idx<t_label>(1,1);
00450     fname = root1; fname += classpairs_fname;
00451     loading_nowarning(classpairs, fname);
00452     // load deformation pairs
00453     deformpairs = idx<t_label>(1,1);
00454     fname = root1; fname += deformpairs_fname;
00455     loading_nowarning(deformpairs, fname);
00456     // initialize some members
00457     data_cnt = data.dim(0);
00458     allocated = true;
00459     idx<Tdata> sample;
00460     if (data.order() == 2)
00461       sample = data.get(0, 0);
00462     else
00463       sample = data.get(0);
00464     outdims = sample.get_idxdim();
00465     print_stats();
00466     return true;
00467   }
00468   
00469   template <class Tdata>
00470   bool dataset<Tdata>::save(const string &root, bool save_data) {
00471     if (!allocated && !strcmp(save_mode.c_str(), DATASET_SAVE))
00472       return false;
00473     string root1 = root;
00474     root1 += "/";
00475     cout << "Saving " << name << " in " << save_mode << " mode." << endl;
00476     // if force label is on, replace labels by force_label
00477     if (strcmp(force_label.c_str(), "")) {
00478       cout << "Forcing all labels to: " << force_label << endl;
00479       classes.clear();
00480       add_class(force_label);
00481       idx_clear(labels); // setting all labels to 0
00482       idx_clear(ids);
00483     }
00484     // return false if no samples
00485     if (data_cnt <= 0) {
00486       cerr << "Warning: No samples were added to the dataset, nothing to save.";
00487       cerr << endl;
00488       return false;
00489     }
00490     // creating directory
00491     mkdir_full(root1);
00492     // remove for empty slots
00493     midx<Tdata> dat = data;
00494     idx<t_label> labs = labels;
00495     idx<intg> scals = ids;
00496     midx<t_jitter> jitts = jitters;
00497     bool bjitts = (jitters.order() >= 1 && idx_max(jitters) > 0);
00498     if (data_cnt < total_samples) {
00499       cerr << "Warning: not all samples were added to dataset (";
00500       cerr << total_samples - data_cnt << " missing out of " << total_samples;
00501       cerr << ")" << endl;
00502       cout << "Downsizing dataset to igore missing samples." << endl;
00503       if (!strcmp(save_mode.c_str(), DATASET_SAVE))
00504         dat = dat.narrow(0, data_cnt, 0);
00505       labs = labs.narrow(0, data_cnt, 0);
00506       scals = scals.narrow(0, data_cnt, 0);
00507       if (bjitts)
00508         jitts = jitts.narrow(0, data_cnt, 0);
00509     }
00510     // switch between saving modes
00511     if (!strcmp(save_mode.c_str(), DATASET_SAVE) ||
00512         !strcmp(save_mode.c_str(), DYNSET_SAVE)) { // dataset mode
00513       cout << "Saving dataset " << name << " in " << root << "/";
00514       cout << name << "_*" << MATRIX_EXTENSION << endl;
00515       // save data
00516       string fname;
00517       if (save_data) {
00518         fname = ""; fname << root1 << data_fname;
00519         cout << "Saving " << fname << " (" << dat << ")" << endl;
00520         if (!strcmp(save_mode.c_str(), DATASET_SAVE)) { // save data matrix
00521           //    // make sure dat can be transformed into a single idx
00522           //    idx<Tdata> single = dat.pack();
00523           //    if (!save_matrix(single, fname)) {
00524           if (!save_matrix<Tdata>(images_list, fname)) {
00525             cerr << "error: failed to save " << fname << endl;
00526             return false;
00527           } else cout << "Saved " << fname << endl;
00528         } else if (!strcmp(save_mode.c_str(), DYNSET_SAVE)) { // compile data file from existing files
00529           if (images_list.size() > 0) {
00530             cout << "Saving dynamic dataset from a list of "
00531                  << images_list.size() << " samples." << endl;
00532             if (!save_matrices<Tdata>(images_list, fname)) {
00533               cerr << "error: failed to save " << fname << endl;
00534               return false;
00535             }
00536           } else {
00537             cout << "Saving dynamic dataset from internal data matrix "
00538                  << data << endl;
00539             if (!save_matrices<Tdata>(data, fname)) {
00540               cerr << "error: failed to save " << fname << endl;
00541               return false;
00542             }
00543           }
00544           cout << "Saved " << fname << endl;
00545         }
00546       }
00547       // save labels
00548       fname = ""; fname << root1 << labels_fname;
00549       cout << "Saving " << fname << " (" << labs << ")"  << endl;
00550       if (!save_matrix(labs, fname)) {
00551         cerr << "error: failed to save labels into " << fname << endl;
00552         return false;
00553       } else cout << "Saved " << fname << endl;
00554       // save jitters
00555       if (bjitts) {
00556         fname = ""; fname << root1 << jitters_fname;
00557         cout << "Saving " << fname << " (" << jitts << ")"  << endl;
00558         if (!save_matrices(jitts, fname)) {
00559           cerr << "error: failed to save labels into " << fname << endl;
00560           return false;
00561         } else cout << "Saved " << fname << endl;
00562       }
00563       // save ids
00564       fname = ""; fname << root1 << ids_fname;
00565       cout << "Saving " << fname << " (" << scals << ")"  << endl;
00566       if (!save_matrix(scals, fname)) {
00567         cerr << "error: failed to save ids into " << fname << endl;
00568         return false;
00569       } else cout << "Saved " << fname << endl;
00570       // save classes
00571       if (classes.size() > 0) {
00572         fname = ""; fname << root1 << classes_fname;
00573         idx<ubyte> classes_idx = build_classes_idx(classes);
00574         cout << "Saving " << fname << " (" << classes_idx << ")"  << endl;
00575         if (!save_matrix(classes_idx, fname)) {
00576           cerr << "error: failed to save classes into " << fname << endl;
00577           return false;
00578         } else cout << "Saved " << fname << endl;
00579       }
00580     } else { // single file mode, use save as image extensions
00581 //       root1 += name; root1 += "/";
00582 //       mkdir_full(root1);
00583 //       // save all images
00584 //       ostringstream fname;
00585 //       intg id = 0;
00586 //       idx<Tdata> tmp;
00587 //       idx_bloop2(dat, data, Tdata, lab, labs, t_label) {
00588 //      // make class directory if necessary
00589 //      fname.str("");
00590 //      fname << root1 << "/" << get_class_string(lab.get()) << "/";
00591 //      mkdir_full(fname.str().c_str());
00592 //      // save image
00593 //      fname << get_class_string(lab.get()) << "_" << id++ << "." << save_mode;
00594 //      tmp = dat.shift_dim(0, 2); // shift from planar to interleaved
00595 //      // scale image to 0 255 if preprocessed
00596 //      if (strcmp(ppconv_type.c_str(), "RGB")) {
00597 //        idx_addc(tmp, (Tdata) 1.0, tmp);
00598 //        idx_dotc(tmp, (Tdata) 127.5, tmp);
00599 //      }
00600 //      if (save_image(fname.str(), tmp, save_mode.c_str()))
00601 //        cout << id << ": saved " << fname.str() << endl;
00602 //      }
00603     }
00604     return true;
00605   }
00606 
00608   // allocation
00609 
00610   template <class Tdata>
00611   bool dataset<Tdata>::allocate(intg n, idxdim &d) {
00612     // allocate only once
00613     //if (allocated)
00614     //  return false;
00615     // initialize members
00616     outdims = d;
00617     data_cnt = 0;
00618     // if max_data has been set, max n with max_data
00619     if (max_data_set)
00620       n = MIN(n, max_data);
00621     cout << "Dataset \"" << name << "\" will have " << n;
00622     cout << " samples of size " << d << endl;
00623     // max with max_per_class
00624     if (max_per_class_set)
00625       n = (std::max)((intg) 0, MIN(n, idx_sum(max_per_class)));
00626     if (n <= 0) {
00627       cerr << "Cannot allocate " << n << " samples." << endl;
00628       return false;
00629     }
00630     // allocate data buffer (only in dataset_save mode)
00631     if (!strcmp(save_mode.c_str(), DATASET_SAVE)) {
00632       cout << "Allocating dataset \"" << name << "\" with " << n;
00633       cout << " samples of size " << d << " (" 
00634            << (n * d.nelements() * sizeof (Tdata)) / (1024 * 1024)
00635            << " Mb) ..." << endl;
00636       // uint c = 0, h = 1, w = 2;
00637       // if (interleaved_input) {
00638       //        c = 2; h = 0; w = 1;
00639       // }
00640       // idxdim datadims(outdims.dim(c), outdims.dim(h), outdims.dim(w));
00641       data = midx<Tdata>(n, nlayers);
00642       datadims = data.get_idxdim();
00643     }
00644     // allocate labels buffer
00645     labels = idx<t_label>(n);
00646     ids = idx<intg>(n);
00647     // allocate jitter buffer
00648     if (bjitter)
00649       jitters = midx<t_jitter>(n);
00650     allocated = true;
00651     // alloc tally
00652     if (nclasses > 0) {
00653       add_tally = idx<intg>(nclasses);
00654       idx_clear(add_tally);
00655     }
00656     cout << "data matrix is " << data << endl;
00657     total_samples = n;
00658     return true;
00659   }
00660   
00662   // data
00663     
00664   template <class Tdata>
00665   bool dataset<Tdata>::add_data(midx<Tdata> &original_sample,
00666                                 const t_label label,
00667                                 const string *class_name,
00668                                 const char *filename, const rect<int> *r,
00669                                 pair<int,int> *center, 
00670                                 const rect<int> *visr,
00671                                 const rect<int> *cropr,
00672                                 const vector<object*> *objs,
00673                                 const jitter *jittforce) {
00674     idx<Tdata> dat = original_sample.get(0);
00675 #ifdef __DEBUG__
00676     cout << "Adding image " << dat << " with label " << label;
00677     if (class_name) cout << ", class name " << *class_name;
00678     if (r) cout << ", ROI " << *r;
00679     if (center) cout << ", center " << center->first << "," << center->second;
00680     cout << " from " << (filename?filename:"") << endl;
00681 #endif
00682     try {
00683       // check for errors
00684       if (!allocated && !strcmp(save_mode.c_str(), DATASET_SAVE))
00685         eblthrow("dataset has not been allocated, cannot add data.");
00686       // check that input is bigger than minimum dimensions allowed
00687       if ((dat.dim(0) < mindims.dim(0))
00688           || (r && (r->height < mindims.dim(0)))
00689           || (dat.dim(1) < mindims.dim(1))
00690           || (r && (r->width < mindims.dim(1)))) {
00691         string err;
00692         err << "not adding " << *class_name << " from " 
00693             << (filename?filename:"")
00694             << ": smaller than minimum dimensions (" << dat;
00695         if (r)
00696           err << " or " << *r;
00697         err << " is smaller than " << mindims << ")";
00698         eblthrow(err);
00699       }
00700       // check that input is smaller than maximum dimensions allowed
00701       if (maxdims_set && r && (r->height > maxdims.dim(0)
00702                                || r->width > maxdims.dim(1))) {
00703         string err;
00704         err << "not adding " << *class_name << " from " 
00705             << (filename?filename:"")
00706             << ": bigger than maximum dimensions (" << *r
00707             << " is bigger than " << maxdims << ")";
00708         eblthrow(err);
00709       }
00710       // check that class exists (may not exist if excluded)
00711       if (classes.size() > 0 && 
00712           find(classes.begin(), classes.end(), *class_name) == classes.end())
00713         eblthrow("not adding " << *class_name << " from " 
00714                  << (filename?filename:"") << ", this class is excluded.");
00715       // check that this class is included
00716       if (class_name && !included(*class_name))
00717         eblthrow("not adding " << *class_name << " from " 
00718                  << (filename?filename:"") << ", this class is excluded.");
00719 
00720       // do cropr if preprocessing is enabled.
00721       // you have to do this outside the jitter loop.
00722       if(do_preprocessing){
00723         // crop it if cropr is defined
00724         if (cropr) {
00725           // input region
00726           idx<Tdata> dat_cropped = dat;
00727           dat_cropped = dat_cropped.narrow(0, cropr->height, cropr->h0);
00728           dat_cropped = dat_cropped.narrow(1, cropr->width, cropr->w0);
00729           dat = dat_cropped;
00730           original_sample.set(dat,0);
00731         }
00732       }
00733       // draw random jitter
00734       vector<jitter> jitt;
00735       if (njitter > 0 && !jittforce) {
00736         // draw last n random pairs
00737         for (uint i = 0; i < njitter; ++i) {
00738           if (random_jitter.size() == 0) // refill vector of random jitters
00739             this->compute_random_jitter();
00740           if (random_jitter.size() == 0) // no jitter possible in this image
00741             break ;
00742           jitt.push_back(random_jitter.back());
00743           random_jitter.pop_back();
00744         }
00745       } else // no jitter
00746         //      if (jitt.size() == 0)
00747         jitt.push_back(jitter(0,0,1.0,0.0)); // no jitter
00748       // add all jittered samples
00749       vector<jitter>::iterator ijit;
00750       for (ijit = jitt.begin(); ijit != jitt.end(); ++ijit) {
00751         // check for capacity
00752         if (full(label))
00753           //    if (!strcmp(save_mode.c_str(), DATASET_SAVE) && full(label))
00754           // reached full capacity
00755           eblthrow("not adding " << *class_name << " from " 
00756                    << (filename?filename:"")
00757                    << ", reached full capacity for this class.");
00758         // copy data into target type
00759         idxdim d(dat);
00760         rect<int> inr;
00761         //
00762         // do preprocessing
00763         midx<Tdata> sample;
00764         if (do_preprocessing)
00765           sample = preprocess_data(original_sample, class_name, filename, r, 0,
00766                                    NULL, center, &(*ijit), visr, cropr, &inr);
00767         else sample = original_sample;
00768         dat = original_sample.get(0);
00769         // ignore this sample if it is not visibile enough
00770         if (r && r->overlap_ratio(inr) < minvisibility)
00771           continue ;
00772         // remember all overlapping objects with current region
00773         idx<t_jitter> *js = NULL;
00774         rect<float> finr(inr.h0, inr.w0, inr.height, inr.width);
00775         finr = finr * (height / (float) inr.height);
00776         for (uint i = 0; objs && i < objs->size(); ++i) {
00777           const object &o = *(*objs)[i];
00778           if (o.min_overlap(inr) >= minvisibility) { // overlaps, add box
00779             // scale box into sample's scale
00780             rect<float> fo(o.h0, o.w0, o.height, o.width);
00781             fo = fo * (height / (float) inr.height);
00782             // convert box to jitter in sample's coordinate system
00783             jitter jj(finr, fo, height);
00784             const idx<t_jitter> &tjj = jj.get_jitter_vector();
00785             // add jitter
00786             if (!js) // allocate first time
00787               js = new idx<t_jitter>(1, tjj.dim(0));
00788             else // increase size by 1
00789               js->resize1(0, js->dim(0) + 1);
00790             idx<t_jitter> e = js->select(0, js->dim(0) - 1);
00791             idx_copy(tjj, e);
00792           }
00793         }
00794         // add mirrors
00795         if (wmirror) {
00796           // flip data using vertical axis
00797           midx<Tdata> flipped = idx_flip(sample, 1);
00798           // flip horizontal jitter
00799           ijit->w = -ijit->w;
00800           idx<t_jitter> *jsmirr = NULL;   
00801           if (js) {
00802             jsmirr = new idx<t_jitter>(js->get_idxdim());
00803             idx_copy(*js, *jsmirr);
00804             idx<t_jitter> wj = jsmirr->select(1, 2); // select width component
00805             idx_minus(wj, wj); // negate all width components
00806           }
00807           cout << "(vertical-axis mirror) ";
00808           add_data2(flipped, label, class_name, filename,
00809                     jittforce ? jittforce : &(*ijit), jsmirr);
00810           // display
00811           if (do_preprocessing)
00812             display_added(flipped, dat, class_name, filename, &inr, r,
00813                           true, center, visr, cropr, objs,
00814                           jittforce ? jittforce : &(*ijit), jsmirr);
00815           // put horizontal jitter back
00816           ijit->w = -ijit->w;
00817           // TEMPORARY MEMORY LEAK FIX (use smart srg pointer to clear
00818           // automatically on object deletion)
00819           flipped.clear();
00820         }
00821         // add/save sample
00822         add_data2(sample, label, class_name, filename,
00823                   jittforce ? jittforce : &(*ijit), js);
00824         // display
00825         if (do_preprocessing)
00826           display_added(sample, dat, class_name, filename, &inr, r,
00827                         true, center, visr, cropr, objs,
00828                         jittforce ? jittforce : &(*ijit), js);
00829         // delete temp objs
00830         if (js) delete js;
00831         // TEMPORARY MEMORY LEAK FIX (use smart srg pointer to clear
00832         // automatically on object deletion)
00833         sample.clear();
00834       }
00835       return true;
00836     } catch(eblexception &e) {
00837       cerr << "warning: " << e << endl;
00838       return false;
00839     }
00840   }
00841 
00842   template <class Tdata>
00843   void dataset<Tdata>::add_data2(midx<Tdata> &sample, t_label label,
00844                                  const string *class_name,
00845                                  const char *filename, const jitter *jitt,
00846                                  idx<t_jitter> *js) {
00847     add_label(label, class_name, filename, jitt, js);
00848     cout << endl;
00849     // check for dimensions
00850     idx<Tdata> sample0 = sample.get(0);
00851     if (!sample0.same_dim(outdims) && !no_outdims) {
00852       idxdim d2(sample0);
00853       d2.setdim(2, outdims.dim(2)); // try with same # of channels
00854       if (d2 == outdims) {
00855         // same size except for the channel dimension, replicate it
00856         cout << "duplicating image channel (" << sample0;
00857         cout << ") to fit target (" << outdims << ")." << endl;
00858         idx<Tdata> sample2(d2);
00859         idx_bloop2(samp2, sample2, Tdata, samp, sample0, Tdata) {
00860           idx_bloop2(s2, samp2, Tdata, s, samp, Tdata) {
00861             for (intg i = 0, j = 0; i < sample2.dim(2); ++i, ++j) {
00862               if (j >= sample0.dim(2))
00863                 j = 0;
00864               s2.set(s.get(j), i);
00865             }
00866           }
00867         }
00868         sample.set(sample2, 0);
00869         // TODO: apply replication to all layers of sample, not just 0
00870       }
00871 //       else
00872 //      eblthrow("expected data with dimensions " << outdims << " but found "
00873 //               << sample0.get_idxdim() << " in " << filename);
00874     }
00875     // put sample's channels dimensions first, if interleaved.
00876     if (interleaved_input)
00877       sample.shift_dim_internal(2, 0);
00878     // if save_mode is dataset, cpy to dataset, otherwise save individual file
00879 //     if (!strcmp(save_mode.c_str(), DATASET_SAVE)) { // dataset mode
00880 //       // assign sample to big matrix
00881 //       midx<Tdata> tgt = data.select(0, data_cnt);
00882 //       for (uint i = 0; i < sample.dim(0); ++i) {
00883 //      idx<Tdata> tmp = sample.get(i);
00884 //      tgt.set(tmp, i);
00885 //       }
00886 //       // copy label
00887 //       labels.set(label, data_cnt);
00888 //       // copy jitt if present
00889 //       if (jitters.order() > 0 && js)
00890 //      jitters.set(*js, data_cnt);
00891 //     } else {
00892       string format = save_mode;
00893       if (!strcmp(save_mode.c_str(), DYNSET_SAVE)
00894           || !strcmp(save_mode.c_str(), DATASET_SAVE))
00895         format = "mat"; // force mat format for dynamic set
00896       string fname_tmp, fname;
00897       fname_tmp << outtmp << "/" << get_class_string(label) << "/";
00898       if (individual_save) mkdir_full(fname_tmp.c_str());
00899       // save image
00900       fname_tmp << get_class_string(label) << "_" << data_cnt;
00901       fname << fname_tmp << "." << format;
00902       //       // scale image to 0 255 if preprocessed
00903       //       if (strcmp(ppconv_type.c_str(), "RGB")) {
00904       //        idx_addc(tmp, (Tdata) 1.0, tmp);
00905       //        idx_dotc(tmp, (Tdata) 127.5, tmp);
00906       //       }
00907       if (individual_save) {
00908         if (separate_layers_save && sample.dim(0) > 1) {
00909           for (uint i = 0; i < sample.dim(0); ++i) {
00910             string fname2;
00911             idx<Tdata> sample2 = sample.get(i);
00912             fname2 << fname_tmp << "_" << i << "." << format;
00913             save_image(fname2, sample2, format.c_str());
00914             cout << "  saved " << fname2 << " (" << sample2 << ")" << endl;
00915           }
00916         } else if (sample.dim(0) == 1) {
00917           idx<Tdata> tmp = sample.get(0);
00918           if (!strcmp(format.c_str(), "mat"))
00919             save_matrix(tmp, fname);
00920           else {
00921             tmp = tmp.shift_dim(0, 2);
00922             save_image(fname, tmp, format.c_str());
00923           }
00924           cout << "  saved " << fname << " (" << sample << ")" << endl;
00925         } else {
00926           if (!strcmp(format.c_str(), "mat")) {
00927             save_matrices(sample, fname);
00928             cout << "  saved " << fname << " (" << sample << ")" << endl;
00929           } else
00930             eblerror("cannot save multi-layer image into format " << format);
00931         }
00932       }
00933       //      if (!strcmp(save_mode.c_str(), DYNSET_SAVE)) {
00934       if (individual_save) // keep new path
00935         images_list.push_back(fname); // add image to files list
00936       else // keep original path
00937         images_list.push_back(filename); // add image to files list
00938       //  }
00939       //}
00940   }
00941 
00942   template <class Tdata>
00943   void dataset<Tdata>::add_label(t_label label, const string *class_name,
00944                                  const char *filename, const jitter *jitt,
00945                                  idx<t_jitter> *js) {
00946     string err;
00947     err << "not adding " << (class_name?*class_name:"sample")
00948         << " from " << (filename?filename:"");
00949     // check for capacity
00950     //    if (!strcmp(save_mode.c_str(), DATASET_SAVE) && full(label))
00951     if (full(label))
00952       eblthrow(err << ", reached full capacity for this class.");
00953     if (!included(label))
00954       eblthrow(err << ", class not included");
00955     // increase counter for that class
00956     add_tally.set(add_tally.get(label) + 1, label);
00957     // print info
00958     cout << data_cnt+1 << " / " << total_samples << ": add ";
00959     cout << (filename ? filename : "sample" );
00960     if (class_name)
00961       cout << " as " << *class_name;
00962     cout << " (" << label << ")";
00963     //    cout << " eta: " << xtimer.eta(processed_cnt, total_samples);
00964     cout << " eta: " << xtimer.eta(data_cnt+1, total_samples);
00965     cout << " elapsed: " << xtimer.elapsed();
00966     if (jitt)
00967       cout << " (jitter " << jitt->h << "," << jitt->w << "," << jitt->s << ","
00968            << jitt->r << ")";
00969     // copy label
00970     if (labels.dim(0) > data_cnt)
00971       labels.set(label, data_cnt);
00972     // increment data count
00973     data_cnt++;
00974   }
00975 
00976   template <class Tdata>
00977   void dataset<Tdata>::display_added(midx<Tdata> &added, idx<Tdata> &original, 
00978                                      const string *class_name,
00979                                      const char *filename, 
00980                                      const rect<int> *inr,
00981                                      const rect<int> *origr,
00982                                      bool active_sleepd,
00983                                      pair<int,int> *center, 
00984                                      const rect<int> *visr,
00985                                      const rect<int> *cropr,
00986                                      const vector<object*> *objs,
00987                                      const jitter *jitt,
00988                                      idx<t_jitter> *js,
00989                                      uint *woriginal) {
00990     // display each step
00991 #ifdef __GUI__
00992     if (display_extraction) {
00993       disable_window_updates();
00994       clear_window();
00995       uint h = 0, w = 0;
00996       uint dh = 0, dw = 1;
00997       ostringstream oss;
00998       // display resized
00999       oss.str("");
01000       h = 16;
01001       gui << gui_only() << black_on_white();
01002 //       // print output sizes
01003 //       string ssizes;
01004 //       for (uint i = 0; i < added.dim(0); ++i) {
01005 //      idx<Tdata> tmp = added.get(i);
01006 //      ssizes << tmp << " ";
01007 //       }
01008 //       gui << at(h, w) << ssizes;
01009 //       h += 16;
01010 //       // draw original output before channel formatting in RGB
01011 //       oss.str("");
01012 //       oss << "RGB";
01013 //       draw_matrix(original, oss.str().c_str(), h, w);
01014 //       h += original.dim(dh) + 5;
01015       Tdata minval, maxval;
01016       ppmods[0]->get_display_range(minval, maxval);
01017       // draw output in RGB
01018       //      gui << at(h, w) << pp_names; h += 15;
01019       idx<Tdata> added0 = added.get(0);
01020       if ((added0.dim(0) == 3 || added0.dim(0) == 1) && fovea.size() == 0) {
01021         idx<Tdata> tmp = added0.shift_dim(0, 2);
01022         draw_matrix(tmp, h, w, 1, 1, minval, maxval);
01023         // draw crossing arrows at center
01024         draw_cross(h + tmp.dim(dh)/(float)2, w + tmp.dim(dw)/(float)2,10,0,0,0);
01025         // draw jitter boxes
01026         if (js) {
01027           idx_bloop1(jj, *js, t_jitter) {
01028             rect<float> jr(h + jj.get(1) * height, w + jj.get(2) * height,
01029                            height, width);
01030             float scale = jj.get(0);
01031             scale = 1 / scale;
01032             jr.scale_centered(scale, scale);
01033             draw_box(jr.h0, jr.w0, jr.height, jr.width, 0, 0, 255);
01034           }
01035         }
01036         h += tmp.dim(dh) + 5;
01037       }
01038       // display all channels
01039       uint wtmp = w, maxw = 0, layers = 0, ppi = 0;
01040       for (uint i = 0; i < added.dim(0); ++i, layers++) {
01041         w = wtmp;
01042         string name;
01043         if (layers == ppmods[ppi]->nlayers()) {
01044           if (ppi < ppmods.size() - 1)
01045             ppi++;
01046           layers = 0;
01047         }
01048         if (layers == 0) {
01049           gui << at(h, w) << ppmods[ppi]->name();
01050           h += 16;
01051           ppmods[ppi]->get_display_range(minval, maxval);
01052         }
01053         idx<Tdata> addedi = added.get(i);
01054         gui << at(h, w) << addedi;
01055         idx<Tdata> tmp = addedi.shift_dim(0, 2);
01056         w += 100;
01057         draw_matrix(tmp, h, w, 1, 1, minval, maxval);
01058         idx_bloop1(chan, addedi, Tdata) {
01059           w += addedi.dim(dw + 1) + 5;
01060           draw_matrix(chan, h, w, 1, 1, minval, maxval);
01061           //    // display channel's center
01062           // draw_box(h + chan.dim(0) / 2 - 5, w + chan.dim(1) / 2 - 5, 10, 10,
01063           //             0, 0, 255);
01064         }
01065         w += addedi.dim(dw + 1) + 5;
01066         h += addedi.dim(dh + 1) + 5;
01067         maxw = std::max(maxw, w);
01068       }
01069       h = 0;
01070       w = maxw + 5;
01071       if (woriginal)
01072         *woriginal = w;
01073       // display original
01074       gui << gui_only() << black_on_white();
01075       oss.str("");
01076       if (filename) {
01077         oss << "file: " << filename;
01078         gui << gui_only() << black_on_white();
01079         gui << at(h, w) << oss.str();
01080       }
01081       h += 16;
01082       oss.str("");
01083       oss << "adding sample #" << data_cnt+1 << " / " << total_samples;
01084       gui << at(h, w) << oss.str(); h += 16;
01085       string desc;
01086       desc << "input: " << original;
01087       if (jitt)
01088         desc << " jitter: spatial " << jitt->h << "x" << jitt->w
01089              << " scale " << jitt->s << " rot " << jitt->r;
01090       gui << at(h, w) << desc; h += 16;
01091       // if image was cropped, shift everything by cropping offsets
01092       if (cropr) {
01093         h += cropr->h0;
01094         w += cropr->w0;
01095       }
01096       // draw image
01097       draw_matrix(original, h, w);
01098       // draw object's center
01099       if (center)
01100         draw_cross(h + center->second, w + center->first, 10, 0, 0, 255);
01101       // draw all objects in picture
01102       if (objs) {
01103         for (uint i = 0; i < objs->size(); ++i) {
01104           const object &o = *(*objs)[i];
01105           if (o.ignored) // ignored object
01106             draw_box(h + o.h0, w + o.w0, o.height, o.width, 255, 255, 0);
01107           else // used object
01108             draw_box(h + o.h0, w + o.w0, o.height, o.width, 0, 255, 255);
01109         }
01110       }
01111       // draw object's original box
01112       if (origr) {
01113         draw_box(h + origr->h0, w + origr->w0, origr->height, origr->width,
01114                  255, 0, 0);
01115         draw_cross(h + origr->hcenter(), w + origr->wcenter(), 20, 255, 0, 0);
01116       }
01117       // draw object's factored box if factor != 1.0
01118       if (inr) {
01119         draw_box(h + inr->h0, w + inr->w0, inr->height, inr->width, 0, 255, 0);
01120         draw_cross(h + inr->hcenter(), w + inr->wcenter(), 20, 0, 255, 0);
01121       }
01122         // draw all 
01123       for (uint i = 0; i < ppmods.size(); ++i) {
01124         resizepp_module<fs(Tdata)> *resizepp = ppmods[i];
01125         const vector<rect<int> > &boxes = resizepp->get_input_bboxes();
01126         for (uint i = 0; i < boxes.size(); ++i) {
01127           const rect<int> &b = boxes[i];
01128           draw_box(h + b.h0, w + b.w0, b.height, b.width, 255, 0, 255);
01129         }
01130       }
01131        // draw object's label
01132       if (class_name && inr)
01133         gui << white_on_transparent() << at(h + inr->h0, w + inr->w0)
01134             << *class_name;
01135       // draw object's visible area if presnet
01136       if (visr)
01137         draw_box(h + visr->h0, w + visr->w0, visr->height, visr->width, 
01138                  0, 0, 255);
01139       //h += dat.dim(dh) + 5;
01140       w += original.dim(dw) + 5;
01141       oss.str("");
01142       // display object
01143       if (inr) {
01144         idx<Tdata> obj = original;
01145         int offh = std::max((int)0, inr->h0);
01146         int offw = std::max((int)0, inr->w0);
01147         obj = obj.narrow(dh, std::min((int)obj.dim(0) - offh, inr->height), offh);
01148         obj = obj.narrow(dw, std::min((int)obj.dim(1) - offw, inr->width), offw);
01149         // display object
01150         if (class_name)
01151           oss << *class_name << " ";
01152         oss << obj;
01153         draw_matrix(obj, oss.str().c_str(), h, w);
01154       // draw crossing arrows at center
01155 //       draw_box(h + inr.height/2, w + inr.width/2, inr.height/2,
01156 //             inr.width/2, 0,0,0);
01157 //       gui << black_on_white() << at(h + inr.height, w) << oss.str();
01158       }
01159       // paint
01160       enable_window_updates();
01161       if (sleep_display && active_sleepd)
01162         millisleep((long) sleep_delay);
01163       if (bsave_display) {
01164         ostringstream oss("");
01165         oss << save_display_dir << "frame" << setw(6) << setfill('0') 
01166             << data_cnt;
01167         save_window(oss.str().c_str());
01168       }
01169     }
01170 #endif
01171   }
01172 
01173   template <class Tdata>
01174   void dataset<Tdata>::set_unique_label(const string &class_name) {
01175     // allocate labels matrix based on images list size
01176     if (labels.order() != 1 && images_list.size() > 0)
01177       labels = idx<t_label>(images_list.size());
01178     idx_clear(labels);
01179     clear_classes();
01180     add_class(class_name);
01181   }
01182   
01183   template <class Tdata>
01184   void dataset<Tdata>::clear_classes() {
01185     nclasses = 0;
01186     classes.clear();
01187   }
01188 
01189   template <class Tdata>
01190   bool dataset<Tdata>::add_class(const string &class_name) {
01191     vector<string>::iterator res;
01192     string name = class_name;
01193     res = find(classes.begin(), classes.end(), name);
01194     if (res == classes.end()) {// not found
01195       classes.push_back(name);
01196       nclasses++;
01197     } else { // found
01198       //t_label i = res - classes.begin();
01199       //      cout << "found class " << name << " at index " << i << endl;
01200     }
01201     // sort all classes
01202     std::sort(classes.begin(), classes.end(), natural_compare_less);
01203     return true;
01204   }
01205 
01206   template <class Tdata>
01207   void dataset<Tdata>::set_classes(idx<ubyte> &classidx) {    
01208     // add classes to each dataset
01209     string s;
01210     idx_bloop1(classe, classidx, ubyte) {
01211       s = (const char *) classe.idx_ptr();
01212       add_class(s);
01213     }
01214     // init max_per_class
01215     max_per_class = idx<intg>(classes.size());
01216     max_per_class_set = false;
01217     idx_fill(max_per_class, (numeric_limits<intg>::max)());    
01218   }
01219 
01220   template <class Tdata>
01221   void dataset<Tdata>::set_outdims(const idxdim &d) {
01222     no_outdims = false;
01223     outdims = d;
01224     uint featdims = 0;
01225     if (interleaved_input || (outdims.order() == 2)) {
01226       height = outdims.dim(0);
01227       width = outdims.dim(1);
01228       featdims = 2;
01229     } else {
01230       height = outdims.dim(1);
01231       width = outdims.dim(2);
01232       featdims = 0;
01233     }
01234     // update outdims' feature size with fovea factor
01235     if (outdims.order() > 0 && fovea.size() > 0)
01236       outdims.setdim(featdims, outdims.dim(featdims) * fovea.size());
01237     cout << "Setting target dimensions to " << outdims << endl;
01238   }
01239 
01240   template <class Tdata>
01241   void dataset<Tdata>::set_outdir(const char *s, const char *tmp) {
01242     outdir = s;
01243     if (tmp)
01244       outtmp = tmp;
01245     if (outtmp.empty())
01246       outtmp = outdir;
01247     cout << "Setting output directory to " << outdir << endl;
01248     cout << "Setting temporary output directory to " << outtmp << endl;
01249   }
01250 
01251   template <class Tdata>
01252   void dataset<Tdata>::set_mindims(const idxdim &d) {
01253     cout << "Setting minimum input dimensions to " << d << endl;
01254     mindims = d;
01255   }
01256 
01257   template <class Tdata>
01258   void dataset<Tdata>::set_maxdims(const idxdim &d) {
01259     cout << "Setting maximum input dimensions to " << d << endl;
01260     maxdims = d;
01261     maxdims_set = true;
01262   }
01263 
01264   template <class Tdata>
01265   void dataset<Tdata>::set_scales(const vector<double> &sc, const string &od) {
01266     scales = sc;
01267     scale_mode = true;
01268     outtmp = od;
01269     cout << "Enabling scaling mode. Scales: ";
01270     for (vector<double>::iterator i = scales.begin(); i != scales.end(); ++i)
01271       cout << *i << " ";
01272     cout << endl;
01273   }
01274 
01275   template <class Tdata>
01276   void dataset<Tdata>::set_fovea(const vector<double> &sc) {
01277     fovea = sc;
01278     cout << "Enabling fovea mode with scales: " << fovea << endl;
01279     // set the number of layers the pyramid will produce
01280     //HERE
01281     nlayers = fovea.size();
01282     // update outdims' feature size
01283     set_outdims(outdims);
01284   }
01285 
01286   template <class Tdata>
01287   void dataset<Tdata>::set_max_per_class(intg max) {
01288     if (max < 0)
01289       eblerror("cannot set max_per_class to < 0");
01290     if (max > 0) {
01291       mpc = max;
01292       max_per_class_set = true;
01293       max_per_class = idx<intg>(nclasses);
01294       idx_fill(max_per_class, mpc);
01295       cout << "Max number of samples per class: " << max << endl;
01296     }
01297   }
01298   
01299   template <class Tdata>
01300   void dataset<Tdata>::set_max_data(intg max) {
01301     if (max < 0)
01302       eblerror("cannot set max_data to < 0");
01303     if (max > 0) {
01304       max_data = max;
01305       max_data_set = true;
01306       cout << "Max number of samples: " << max << endl;
01307     }
01308   }
01309   
01310   template <class Tdata>
01311   void dataset<Tdata>::set_image_pattern(const string &p) {
01312     extension = p;
01313     cout << "Setting image pattern to " << extension << endl;
01314   }
01315   
01316   template <class Tdata>
01317   void dataset<Tdata>::set_exclude(const vector<string> &ex) {
01318     if (ex.size()) {
01319       cout << "Excluded class(es): ";
01320       for (vector<string>::const_iterator i = ex.begin(); i != ex.end(); ++i) {
01321         exclude.push_back(*i);
01322         if (i != ex.begin()) cout << ",";
01323         cout << " " << *i;
01324       }
01325       cout << endl;
01326     }
01327   }
01328   
01329   template <class Tdata>
01330   void dataset<Tdata>::set_include(const vector<string> &inc) {
01331     if (inc.size()) {
01332       cout << "Included class(es): ";
01333       for (vector<string>::const_iterator i = inc.begin(); i != inc.end(); ++i){
01334         include.push_back(*i);
01335         if (i != inc.begin()) cout << ",";
01336         cout << " " << *i;
01337       }
01338       cout << endl;
01339     }
01340   }
01341   
01342   template <class Tdata>
01343   void dataset<Tdata>::set_save(const string &s) {
01344     save_mode = s;
01345     cout << "Setting saving mode to: " << save_mode << endl;
01346   }
01347     
01348   template <class Tdata>
01349   void dataset<Tdata>::set_individual_save(bool b) {
01350     individual_save = b;
01351     cout << (individual_save ? "Enabling" : "Disabling")
01352          << " individual sample saving." << endl;
01353   }
01354     
01355   template <class Tdata>
01356   void dataset<Tdata>::set_separate_layers_save(bool b) {
01357     separate_layers_save = b;
01358     cout << (separate_layers_save ? "Enabling" : "Disabling")
01359          << " saving sample layers separately." << endl;
01360   }
01361     
01362   template <class Tdata>
01363   void dataset<Tdata>::set_name(const string &s) {
01364     name = s;
01365     build_fname(name, DATA_NAME, data_fname);
01366     build_fname(name, LABELS_NAME, labels_fname);
01367     build_fname(name, SCALES_NAME, ids_fname);
01368     build_fname(name, JITTERS_NAME, jitters_fname);
01369     build_fname(name, CLASSES_NAME, classes_fname);
01370     build_fname(name, CLASSPAIRS_NAME, classpairs_fname);
01371     build_fname(name, DEFORMPAIRS_NAME, deformpairs_fname);
01372     cout << "Setting dataset name to: " << name << endl;
01373   }
01374     
01375   template <class Tdata>
01376   void dataset<Tdata>::set_label(const string &s) {
01377     force_label = s;
01378     //add_class(force_label);
01379     cout << "Forcing label for all samples to: " << s << endl;
01380   }
01381 
01382   template <class Tdata>
01383   void dataset<Tdata>::set_bbox_woverh(float factor) {
01384     bbox_woverh = factor;
01385     cout << "Forcing width to be h * " << bbox_woverh << endl;
01386   }
01387     
01388   template <class Tdata>
01389   void dataset<Tdata>::set_nopadded(bool nopadded_) {
01390     nopadded = nopadded_;
01391     if (nopadded)
01392       cout << "Ignoring samples that have padding areas, i.e. too"
01393            << " small for target size." << endl;
01394   }
01395  template <class Tdata>
01396  void dataset<Tdata>::set_videobox(uint nframes, uint stride) {
01397    do_videobox = true;
01398    videobox_nframes = nframes;
01399    videobox_stride = stride;
01400  }
01401   
01402   template <class Tdata>
01403   void dataset<Tdata>::
01404   set_jitter(uint tjitter_step_, uint tjitter_hmin_, uint tjitter_hmax_,
01405              uint tjitter_wmin_, uint tjitter_wmax_, uint scale_steps,
01406              float scale_min, float scale_max, uint rotation_steps,
01407              float rotation_range, uint n) {
01408     bjitter = true;
01409     tjitter_step = (int) tjitter_step_;
01410     tjitter_hmin = (int) tjitter_hmin_;
01411     tjitter_hmax = (int) tjitter_hmax_;
01412     tjitter_wmin = (int) tjitter_wmin_;
01413     tjitter_wmax = (int) tjitter_wmax_;
01414     sjitter_steps = (int) scale_steps;
01415     sjitter_min = scale_min;
01416     sjitter_max = scale_max;
01417     if (sjitter_min > sjitter_max)
01418       eblerror("expected max > min but got " << sjitter_max << " < "
01419                << sjitter_min);
01420     rjitter_steps = (int) rotation_steps;
01421     rjitter = rotation_range;
01422     njitter = n;
01423     cout << "Adding " << n << " samples randomly jittered in a neighborhood "
01424          << " with height range (" << tjitter_hmin
01425          << "," << tjitter_hmax << "), width range (" << tjitter_wmin
01426          << "," << tjitter_wmax << ") and step " << tjitter_step << ", over "
01427          << scale_steps << " scales"
01428          << " within a [" << scale_min << "," << scale_max
01429          << "] scale range and "
01430          << rjitter_steps << " rotations within a " << rjitter
01431          << " degrees rotation range around original location"
01432          << "/scale/orientation" << endl;
01433   }
01434   
01435   template <class Tdata>
01436   void dataset<Tdata>::set_minvisibility(float minvis) {
01437     cout << "Setting minimum visibility ratio (visible bbox overlap with "
01438          << "original bbox) to " << minvis << endl;
01439     minvisibility = minvis;
01440   }
01441 
01442   template <class Tdata>
01443   void dataset<Tdata>::set_wmirror() {
01444     wmirror = true;
01445     cout << "Adding vertical-axis mirror." << endl;
01446   }
01447 
01448   template <class Tdata>
01449   void dataset<Tdata>::save_display(const string &dir, uint h, uint w) {
01450 #ifdef __GUI__
01451     bsave_display = true;
01452     save_display_dir = dir;
01453     save_display_dir << "/";
01454     mkdir_full(dir.c_str());
01455     cout << "Saving display frames ";
01456     if (h != 0 && w != 0) {
01457       freeze_window_size(h, w);
01458       cout << "(fixed size: " << h << "x" << w << ") ";
01459     }
01460     cout << "to " << dir << endl;
01461 #endif
01462   }
01463       
01464   template <class Tdata>
01465   void dataset<Tdata>::use_pose() {
01466     usepose = true;
01467     cout << "Using pose to separate classes." << endl;
01468   }
01469   
01470   template <class Tdata>
01471   void dataset<Tdata>::use_parts() {
01472     useparts = true;
01473     cout << "Extracting parts." << endl;
01474   }
01475   
01476   template <class Tdata>
01477   void dataset<Tdata>::use_parts_only() {
01478     usepartsonly = true;
01479     cout << "Extracting parts only." << endl;
01480   }
01481   
01482   template <class Tdata>
01483   intg dataset<Tdata>::count_total() {
01484     // count samples
01485     this->count_samples();
01486     cout << "Found: " << total_samples << " total samples." << endl;
01487     if (!total_samples) eblerror("no samples found");
01488     if (njitter > 0) {
01489       total_samples *= njitter;
01490       cout << "Jitter is on with " << njitter << " jitters per sample, "
01491            << "bringing total samples to " << total_samples << endl;
01492     }
01493     if (wmirror) {
01494       total_samples *= 2;
01495       cout << "Vertical-axis mirroring is on, "
01496            << "bringing total samples to " << total_samples << endl;
01497     }
01498     return total_samples;
01499   }
01500   
01501   template <class Tdata>
01502   intg dataset<Tdata>::count_samples() {
01503 #ifdef __BOOST__
01504     cout << "Counting number of samples in " << inroot << " ..." << endl;
01505     total_samples = 0;
01506     regex hidden_dir(".svn");    
01507     cmatch what;
01508     directory_iterator end_itr; // default construction yields past-the-end
01509     path p(inroot);
01510     if (!exists(p)) eblthrow("path " << inroot << " does not exist.");
01511     // loop over all directories
01512     std::vector<std::string> dirs;
01513     for (directory_iterator itr(inroot); itr != end_itr; itr++) {
01514 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
01515       if (is_directory(itr->status())
01516           && !regex_match(itr->leaf().c_str(), what, hidden_dir)) {
01517         // ignore excluded classes and use included if defined
01518         if (included(itr->leaf())) {
01519           dirs.push_back(itr->leaf());
01520 #else
01521       if (is_directory(itr->status())
01522           && !regex_match(itr->path().filename().c_str(), what, hidden_dir)) {
01523         // ignore excluded classes and use included if defined
01524         if (included(itr->path().filename())) {
01525           dirs.push_back(itr->path().filename().c_str());
01526 #endif
01527           // recursively search each directory
01528           total_samples += count_matches(itr->path().string(), extension);
01529         }
01530       }
01531     }
01532     // sort directories
01533     std::sort(dirs.begin(), dirs.end(), natural_compare_less);
01534     // process subdirs to extract images into the single image idx
01535     for (uint i = 0; i < dirs.size(); ++i) {
01536       // add directory as new class
01537       add_class(dirs[i]);
01538     }
01539 #endif /* __BOOST__ */
01540     return total_samples;
01541   }
01542   
01543   template <class Tdata>
01544   void dataset<Tdata>::split(dataset<Tdata> &ds1, dataset<Tdata> &ds2) {
01545     // data already preprocessed
01546     ds1.do_preprocessing = false;
01547     ds2.do_preprocessing = false;
01548     ds1.interleaved_input = false;
01549     ds2.interleaved_input = false;
01550     // enable jitter in target if present here
01551     bjitter = (jitters.order() > 0);
01552     if (bjitter) {
01553       ds1.bjitter = true;
01554       ds2.bjitter = true;
01555     }
01556     cout << "Input data samples: " << data << endl;
01557     // alloc each dataset
01558     if (!ds1.allocate(data.dim(0), outdims) ||
01559         !ds2.allocate(data.dim(0), outdims))
01560       eblerror("Failed to allocate new datasets");
01561     // add samples 1st dataset, if not add to 2nd.
01562     // if 1st has reached max per class, it will return false upon addition
01563     cout << "Adding data to \"" << ds1.name << "\" and \"" << ds2.name << "\".";
01564     cout << endl;
01565     // using the shuffle() method is a problem with big datasets because
01566     // it requires allocation of an extra dataset.
01567     // instead, we use a random list of indices to assign the first random
01568     // samples to dataset 1 and the remaining to dataset 2.
01569     vector<intg> ids;
01570     idx<t_jitter> jitt;
01571     t_label label;
01572     // prepare offset matrices
01573     idx<int64> offsets = data.get_offsets();
01574     idx<int64> off1(offsets.get_idxdim()), off2(offsets.get_idxdim());
01575     idx_clear(off1);
01576     idx_clear(off2);
01577     // init timers
01578     ds1.xtimer.start();
01579     ds2.xtimer.start();
01580     // loop on all samples
01581     for (intg i = 0; i < data.dim(0); ++i) ids.push_back(i);
01582     random_shuffle(ids.begin(), ids.end());
01583     for (vector<intg>::iterator i = ids.begin(); i != ids.end(); ++i) {
01584       label = labels.get(*i);
01585       string &class_name = classes[(size_t)label];
01586       cout << "(original index " << *i << ") ";
01587       // adding to ds1
01588       try {
01589         intg cnt = ds1.data_cnt;
01590         ds1.add_label(label, &class_name, NULL, NULL, NULL);
01591         cout << " (dataset 1)" << endl;
01592         // copy offsets
01593         idx<int64> offs = offsets[*i];
01594         idx<int64> offss = off1[cnt];
01595         idx_copy(offs, offss);
01596         if (bjitter && jitters.exists(*i)) {
01597           jitt = jitters.get(*i);
01598           ds1.jitters.set(jitt, cnt);
01599         }
01600       } catch(eblexception &e) { // adding to ds2
01601         try {
01602           intg cnt = ds2.data_cnt;
01603           ds2.add_label(label, &class_name, NULL, NULL, NULL);
01604           cout << " (dataset 2), not 1:" << e << endl;
01605           // copy offsets
01606           idx<int64> offs = offsets[*i];
01607           idx<int64> offss = off2[cnt];
01608           idx_copy(offs, offss);
01609           if (bjitter && jitters.exists(*i)) {
01610             jitt = jitters.get(*i);
01611             ds2.jitters.set(jitt, cnt);
01612           }
01613         } catch(eblexception &e) {
01614           cerr << "failed adding sample: " << e << endl;
01615         }
01616       }
01617     }
01618     // set data matrices from original data and offset matrices
01619     // ds1.data_cnt = idx_sum(ds1.add_tally);
01620     // ds2.data_cnt = idx_sum(ds2.add_tally);
01621     if (off1.order() == 1) {
01622       off1.resize(ds1.data_cnt);
01623       off2.resize(ds2.data_cnt);
01624     }
01625     else {
01626       off1.resize(ds1.data_cnt, off1.dim(1));
01627       off2.resize(ds2.data_cnt, off2.dim(1));
01628     }
01629     ds1.data = midx<Tdata>(off1.get_idxdim(), data.get_file_pointer(), &off1);
01630     ds2.data = midx<Tdata>(off2.get_idxdim(), data.get_file_pointer(), &off2);
01631     
01632     print_stats();
01633     ds1.print_stats();
01634     ds2.print_stats();
01635   }
01636 
01637   template <class Tdata>
01638   void dataset<Tdata>::merge_and_save(const char *name1, const char *name2,
01639                                       const string &outroot) {
01640     dataset<Tdata> ds1(name1), ds2(name2);
01641     string inroot1 = ebl::dirname(name1);
01642     string inroot2 = ebl::dirname(name2);
01643     // load 2 datasets
01644     ds1.load(inroot1);
01645     ds2.load(inroot2);
01646     if (ds1.jitters.order() > 0 || ds2.jitters.order() > 0) {
01647       njitter = 1; // enable jitter allocation/saving
01648       bjitter = true;
01649     }
01650     interleaved_input = false;
01651     intg newsz = ds1.size() + ds2.size();
01652     idxdim d1 = ds1.get_sample_outdim(), d2 = ds2.get_sample_outdim();
01653     if (!(d1 == d2))
01654       eblwarn("sample sizes for dataset 1 and 2 are different: "
01655               << d1 << " and " << d2);
01656     // allocate new dataset
01657     allocate(newsz, d1);
01658     idx<t_label> labelsnew;
01659     idx<intg> idsnew;
01660     midx<t_jitter> jittnew;
01661     // clear jitters, in case a dataset doesn't have any
01662     idx_clear(jitters);
01663     // update classes
01664     idx<ubyte> classidx = ds1.build_classes_idx(ds1.classes);
01665     set_classes(classidx); // initialize with ds1's class names
01666     cout << "Added all classes to new dataset from " << ds1.name << endl;
01667     // for each ds2 class name, push on new class names vector if not found
01668     vector<string>::iterator res, i;
01669     for (i = ds2.classes.begin(); i != ds2.classes.end(); ++i){
01670       res = find(classes.begin(), classes.end(), *i);
01671       if (res == classes.end()) { // not found
01672         classes.push_back(*i); // add new class name
01673         nclasses++;
01674         cout << "Adding class " << *i << " from dataset " << ds2.name << endl;
01675       }
01676     }
01677     // update each ds2 label based on new class numbering
01678     idx_bloop1(lab, ds2.labels, t_label) {
01679       string s = ds2.get_class_string(lab.get());
01680       lab.set(get_class_id(s));
01681     }
01682     // copy data 1 into new dataset
01683     labelsnew = labels.narrow(0, ds1.size(), 0);
01684     idx_copy(ds1.labels, labelsnew);
01685     idsnew = ids.narrow(0, ds1.size(), 0);
01686     idx_copy(ds1.ids, idsnew);
01687     if (bjitter)
01688       jittnew = jitters.narrow(0, ds1.size(), 0);
01689     if (ds1.jitters.order() > 0)
01690       for (uint i = 0; i < ds1.jitters.dim(0); ++i) {
01691         if (ds1.jitters.exists(i)) {
01692           idx<t_jitter> tmp = ds1.jitters.get(i); 
01693           jittnew.set(tmp, i);
01694         }
01695       }
01696     // copy data 2 into new dataset
01697     labelsnew = labels.narrow(0, ds2.size(), ds1.size());
01698     idx_copy(ds2.labels, labelsnew);
01699     idsnew = ids.narrow(0, ds2.size(), ds1.size());
01700     idx_copy(ds2.ids, idsnew);
01701     if (bjitter)
01702       jittnew = jitters.narrow(0, ds2.size(), ds1.size());
01703     if (ds2.jitters.order() > 0)
01704       for (uint i = 0; i < ds2.jitters.dim(0); ++i) {
01705         if (ds2.jitters.exists(i)) {
01706           idx<t_jitter> tmp = ds2.jitters.get(i); 
01707           jittnew.set(tmp, i);
01708         }
01709       }
01710     // update counter
01711     data_cnt = newsz;
01712     cout << "Copied data from " << ds1.name << " and " << ds2.name;
01713     cout << " into new dataset." << endl;
01714     // print info
01715     print_stats();
01716     // save data
01717     string fname, fname_tmp;
01718     fname << outroot << "/" << data_fname;
01719     fname_tmp << fname << "_tmp";
01720     mkdir_full(outroot.c_str());
01721     cout << "Saving " << fname << endl;
01722     save_matrices(ds1.data, ds2.data, fname_tmp);
01723     if (!mv_file(fname_tmp.c_str(), fname.c_str()))
01724       eblerror("failed to move " << fname_tmp << " to " << fname);
01725     // move from tmp to target name
01726     cout << "Saving dataset in " << outroot << endl;
01727     // save rest
01728     save(outroot, false);
01729   }
01730     
01731   template <class Tdata> template <class Toriginal>
01732   bool dataset<Tdata>::save_scales(idx<Toriginal> &dat, const string &filename){
01733     // copy data into target type
01734     idxdim d(dat);
01735     idx<Tdata> sample(d);
01736     idx_copy(dat, sample);
01737     // do preprocessing for each scale, then save image
01738     ostringstream base_name, ofname;
01739     base_name << outtmp << "/" << filename << "_scale";
01740     string class_name = "noclass";
01741     for (vector<double>::iterator i = scales.begin(); i != scales.end(); ++i) {
01742       idx<Tdata> s = preprocess_data(sample, &class_name,
01743                                      filename.c_str(), NULL, *i);
01744       // put sample's channels dimensions first, if defined.
01745       //s = s.shift_dim(2, 0);
01746       // save image
01747       ofname.str(""); ofname << base_name.str() << *i << ".mat";
01748       if (save_matrix(s, ofname.str())) {
01749         cout << data_cnt++ << ": saved " << ofname.str();
01750         cout << "(" << s << ")" << endl;
01751       }
01752     }
01753     return true;
01754   }
01755 
01756   template <class Tdata>
01757   bool dataset<Tdata>::included(t_label &lab) {
01758     if (classes.size() == 0) return false;
01759     if ((size_t) lab >= classes.size()) return false;
01760     string &class_name = classes[(size_t)lab];
01761     if (!included(class_name)) return false;
01762     return true;
01763   }
01764     
01765   template <class Tdata>
01766   bool dataset<Tdata>::included(const string &class_name) {
01767     return // is not excluded
01768       find(exclude.begin(), exclude.end(), class_name) == exclude.end()
01769       // and is included
01770       && ((find(include.begin(), include.end(), class_name) != include.end())
01771           // or everything is included
01772           || (include.size() == 0));
01773   }
01774   
01776   // data preprocessing
01777 
01778   template <class Tdata>
01779   midx<Tdata> dataset<Tdata>::
01780   preprocess_data(midx<Tdata> &dat, const string *class_name,
01781                   const char *filename, const rect<int> *r, double scale,
01782                   rect<int> *outr,
01783                   pair<int,int> *center, jitter *jitt,
01784                   const rect<int> *visr,
01785                   const rect<int> *cropr,
01786                   rect<int> *inr_out) {
01787     // input region
01788     idx<Tdata> dat0 = dat.get(0);
01789 
01790     rect<int> inr(0, 0, dat0.dim(0), dat0.dim(1));
01791     if (r) inr = *r;
01792     // force width to be h * bbox_woverh
01793     if (bbox_woverh > 0)
01794       inr.scale_width(bbox_woverh);
01795     // resize image to target dims
01796     rect<int> out_region, cropped;
01797     idxdim d(outdims);
01798     // input data
01799     idx<Tdata> tmp = dat0.shift_dim(2, 0);
01800     fstate_idx<Tdata> in(tmp.get_idxdim());
01801     // allocate sample with videobox options in mind
01802     midx<Tdata> sample(nlayers * (1 + videobox_nframes));
01803     uint nadded = 0;
01804     string next_file = filename;
01805     for(uint i = 0; i < videobox_nframes + 1; ++i) {
01806       //copy the current image into in.x
01807       idx_copy(tmp, in.x);
01808       // loop on all preprocessing modules
01809       for (uint i = 0; i < ppmods.size(); ++i) {
01810         resizepp_module<fs(Tdata)> *resizepp = ppmods[i];
01811         midx<Tdata> sampletmp(resizepp->nlayers());
01812         // add jitter
01813         if (jitt)
01814           resizepp->set_jitter((int)jitt->h, (int)jitt->w, jitt->s, jitt->r);
01815         if (scale > 0) // resize entire image at specific scale
01816           resizepp->set_dimensions((uint) (outdims.dim(0) * scale), 
01817                                    (uint) (outdims.dim(1) * scale));
01818         resizepp->set_input_region(inr);
01819         // actual preprocessing
01820         resizepp->fprop(in, sampletmp);
01821         // remember bbox of original image in resized image
01822         original_bbox = resizepp->get_original_bbox(); 
01823         if (outr)
01824           *outr = original_bbox;
01825         if (inr_out)
01826           *inr_out = resizepp->get_input_bbox();
01827         for (uint j = 0; j < sampletmp.dim(0); ++j) {
01828           idx<Tdata> stmp = sampletmp.get(j);
01829           sample.set(stmp, j + nadded);
01830         }
01831         nadded += resizepp->nlayers();
01832       }
01833       if (do_videobox) {
01834         // Load the next image into tmp
01835         load_img.clear();
01836         // if file doesn't exist, load_data automatically throws exception
01837         // which makes the sample to be not added
01838         next_file = ebl::increment_filename(next_file.c_str(), videobox_stride);
01839         load_data(next_file);
01840         dat0 = load_img.get(0);
01841         if (cropr) {
01842           dat0 = dat0.narrow(0, cropr->height, cropr->h0);
01843           dat0 = dat0.narrow(1, cropr->width, cropr->w0);
01844         }
01845         dat0.shift_dim(2, 0);
01846         tmp = dat0.shift_dim(2, 0);
01847       }
01848     }
01849     sample.shift_dim_internal(0, 2);
01850     // return preprocessed image
01851     return sample;
01852   }
01853 
01855   // Helper functions
01856     
01857   template <class Tdata>
01858   void dataset<Tdata>::compute_stats() {
01859     // collect stats
01860     if (nclasses > 0) {
01861       class_tally = idx<intg>(nclasses);
01862       idx_clear(class_tally);
01863       for (intg i = 0; i < data_cnt && i < labels.dim(0); ++i) {
01864         class_tally.set(class_tally.get(labels.get(i)) + 1,
01865                         (intg) labels.get(i));
01866       }
01867     }
01868   }
01869 
01870   template <class Tdata>
01871   idx<ubyte> dataset<Tdata>::build_classes_idx(vector<string> &classes) {
01872     // determine max length of strings
01873     uint max = 0;
01874     vector<string>::iterator i = classes.begin();
01875     for ( ; i != classes.end(); ++i)
01876       max = (std::max)((size_t) max, i->length());
01877     // allocate classes idx
01878     idx<ubyte> classes_idx(classes.size(), max + 1);
01879     // copy classes strings
01880     idx_clear(classes_idx);
01881     idx<ubyte> tmp;
01882     for (i = classes.begin(); i != classes.end(); ++i) {
01883       tmp = classes_idx.select(0, i - classes.begin());
01884       memcpy(tmp.idx_ptr(), i->c_str(), i->length() * sizeof (ubyte));
01885     }
01886     return classes_idx;
01887   }
01888 
01889   template <class Tdata>
01890   string& dataset<Tdata>::get_class_string(t_label id) {
01891     if (((int) id < 0) || ((uint) id >= classes.size()))
01892       eblerror("trying to access a class with wrong id.");
01893     return classes[id];
01894   }
01895 
01896   template <class Tdata>
01897   t_label dataset<Tdata>::get_class_id(const string &name) {
01898     vector<string>::iterator res;
01899     res = find(classes.begin(), classes.end(), name);
01900     if (res == classes.end()) // not found
01901       eblerror("class not found");
01902     return (t_label) (res - classes.begin());
01903   }      
01904 
01905   // Recursively goes through dir, looking for files matching extension ext.
01906   template <class Tdata>
01907   uint dataset<Tdata>::count_matches(const string &dir, const string &pattern) {
01908     uint total = 0;
01909 #ifdef __BOOST__
01910     regex eExt(pattern);
01911     cmatch what;
01912     path p(dir);
01913     if (!exists(p))
01914       return 0;
01915     directory_iterator end_itr; // default construction yields past-the-end
01916     for (directory_iterator itr(p); itr != end_itr; ++itr) {
01917       if (is_directory(itr->status()))
01918         total += count_matches(itr->path().string(), pattern);
01919 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
01920       else if (regex_match(itr->leaf().c_str(), what, eExt))
01921 #else
01922       else if (regex_match(itr->path().filename().c_str(), what, eExt))
01923 #endif
01924         total++;
01925     }
01926 #endif /* __BOOST__ */
01927     return total;
01928   }
01929    
01930   template <class Tdata>
01931   void dataset<Tdata>::process_dir(const string &dir, const string &ext,
01932                                    const string &class_name_) {
01933 #ifdef __BOOST__
01934     string class_name = class_name_;
01935     t_label label = get_label_from_class(class_name);
01936     cmatch what;
01937     regex r(ext);
01938     path p(dir);
01939     if (!exists(p))
01940       return ;
01941     directory_iterator end_itr; // default construction yields past-the-end
01942     for (directory_iterator itr(p); itr != end_itr; ++itr) {
01943       if (is_directory(itr->status()))
01944         process_dir(itr->path().string(), ext, class_name);
01945 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
01946       else if (regex_match(itr->leaf().c_str(), what, r)) {
01947 #else
01948       else if (regex_match(itr->path().filename().c_str(), what, r)) {
01949 #endif
01950         try {
01951           processed_cnt++;
01952           // if full for this class, skip this directory
01953           if ((full(get_label_from_class(class_name)) || !included(class_name)))
01954             break ;
01955           // load data
01956           load_data(itr->path().string());
01957           // add sample data
01958 //        if (scale_mode) // saving image at different scales
01959 //          save_scales(load_img, itr->leaf());
01960 //        else // adding data to dataset
01961           this->add_data(load_img, label, &class_name,
01962                          itr->path().string().c_str());
01963           load_img.clear();
01964         } catch(const char *err) {
01965           cerr << "error: failed to add " << itr->path().string();
01966           cerr << ": " << endl << err << endl;
01967           add_errors++;
01968         } catch(string &err) {
01969           cerr << "error: failed to add " << itr->path().string();
01970           cerr << ": " << endl << err << endl;
01971           add_errors++;
01972         }
01973       }}
01974 #endif /* __BOOST__ */
01975   }
01976 
01977   template <class Tdata>
01978   void dataset<Tdata>::load_data(const string &fname) {
01979     load_img.clear();
01980     if (has_multiple_matrices(fname.c_str())) {
01981       load_img = load_matrices<Tdata>(fname.c_str());
01982     } else {
01983       load_img.clear();      
01984       idx<Tdata> tmp = load_image<Tdata>(fname.c_str());
01985       load_img.set(tmp, 0);
01986     }
01987     if (load_planar)
01988       load_img.shift_dim_internal(0, 2);
01989   }  
01990 
01991   template <class Tdata>
01992   void dataset<Tdata>::compute_random_jitter() {
01993     // compute all possible jitters
01994     random_jitter.clear();
01995     // scale step
01996     float sstep = (sjitter_max - sjitter_min)
01997       / std::max((int) 0, (int) sjitter_steps - 1);
01998     // min/max rotation jitter
01999     float min_rjitt = 0.0 - rjitter / 2;
02000     float max_rjitt = 0.0 + rjitter / 2;
02001     // rotation step
02002     float rstep = rjitter / std::max((int) 0, (int) rjitter_steps - 1);
02003     // loop over possible rotations
02004     for (float rj = min_rjitt; rj <= max_rjitt; rj += rstep) {
02005       // loop over possible scales
02006       for (float sj = sjitter_min; sj <= sjitter_max; sj += sstep) {
02007         // loop over possible heights
02008         for (int hj = -tjitter_hmax; hj <= tjitter_hmax; hj += tjitter_step) {    
02009           // loop over possible width
02010           for (int wj = -tjitter_wmax; wj <= tjitter_wmax; wj +=tjitter_step){
02011             if (abs(hj) >= tjitter_hmin || abs(wj) >= tjitter_wmin) {
02012               // add jitter
02013               // multiply by scale when > 1, to compensate for object being
02014               // smaller and thus not reaching the same extent.
02015               random_jitter.push_back(jitter(hj * std::max((float)1.0, sj),
02016                                                wj * std::max((float)1.0, sj),
02017                                              sj, rj, height));
02018             }
02019           }
02020         }
02021       }
02022     }
02023     // randomize possibilities
02024     random_shuffle(random_jitter.begin(), random_jitter.end());
02025     EDEBUG("computed " << random_jitter.size() << " random jitters");
02026   }
02027 
02029   // loading errors
02030 
02032   template <typename T>
02033   bool loading_error(idx<T> &mat, string &fname) {
02034     try {
02035       mat = load_matrix<T>(fname);
02036     } catch (const string &err) {
02037       cerr << "error: " << err << endl;
02038       cerr << "error: failed to load dataset file " << fname << endl;
02039       eblerror("failed to load dataset file");
02040       return false;
02041     }
02042     cout << "Loaded " << fname << " (" << mat << ")" << endl;
02043     return true;
02044   }
02045 
02047   template <typename T>
02048   bool loading_error(midx<T> &mat, string &fname) {
02049     try {
02050       mat = load_matrices<T>(fname);
02051     } catch (const string &err) {
02052       cerr << "error: " << err << endl;
02053       cerr << "error: failed to load dataset file " << fname << endl;
02054       eblerror("failed to load dataset file");
02055       return false;
02056     }
02057     cout << "Loaded " << fname << " (" << mat << ")" << endl;
02058     return true;
02059   }
02060 
02062   template <typename T>
02063   bool loading_warning(idx<T> &mat, string &fname) {
02064     try {
02065       mat = load_matrix<T>(fname);
02066     } catch (const string &err) {
02067       cerr << "warning: failed to load dataset file " << fname << endl;
02068       return false;
02069     }
02070     cout << "Loaded " << fname << " (" << mat << ")" << endl;
02071     return true;
02072   }
02073   
02075   template <typename T>
02076   bool loading_warning(midx<T> &mat, string &fname) {
02077     try {
02078       mat = load_matrices<T>(fname);
02079     } catch (const string &err) {
02080       cerr << "warning: failed to load dataset file " << fname << endl;
02081       return false;
02082     }
02083     cout << "Loaded " << fname << " (" << mat << ")" << endl;
02084     return true;
02085   }
02086   
02088   template <typename T>
02089   bool loading_nowarning(idx<T> &mat, string &fname) {
02090     try {
02091       mat = load_matrix<T>(fname);
02092     } catch (const string &err) {
02093       return false;
02094     }
02095     cout << "Loaded " << fname << " (" << mat << ")" << endl;
02096     return true;
02097   }
02098   
02099 } // end namespace ebl
02100 
02101 #endif /* DATASET_HPP_ */