libeblearntools
/home/rex/ebltrunk/tools/libeblearntools/include/patch_dataset.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2010 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 PATCH_DATASET_HPP_
00034 #define PATCH_DATASET_HPP_
00035 
00036 #include <algorithm>
00037 
00038 #ifdef __BOOST__
00039 #define BOOST_FILESYSTEM_VERSION 2
00040 #include "boost/filesystem.hpp"
00041 #include "boost/regex.hpp"
00042 using namespace boost::filesystem;
00043 using namespace boost;
00044 #endif
00045 
00046 using namespace std;
00047 
00048 namespace ebl {
00049 
00051   // constructors & initializations
00052 
00053   template <class Tdata>
00054   patch_dataset<Tdata>::patch_dataset(const char *name_,
00055                                       const char *inroot_,
00056                                       const char *outdir_,
00057                                       uint max_folders_)
00058     : dataset<Tdata>(name_, inroot_) {
00059     outdir = outdir_;
00060     cout << "Output directory: " << outdir << endl;
00061     cout << "Saving " << max_folders_ << " patch per image "
00062          << "for each scale at random position. " << endl;
00063     max_folders = max_folders_;
00064     data_cnt = 0;
00065     save_mode = "mat";
00066   }
00067 
00068   template <class Tdata>
00069   patch_dataset<Tdata>::~patch_dataset() {
00070   }
00071 
00073   // data extraction
00074 
00075   template <class Tdata>
00076   bool patch_dataset<Tdata>::
00077   add_data(idx<Tdata> &img, const t_label label,
00078            const string *class_name, const char *filename, const rect<int> *r,
00079            pair<int,int> *center, const rect<int> *visr,
00080            const rect<int> *cropr, const vector<object*> *objs,
00081            const jitter *jittforce) {
00082     vector<rect<int> > patch_bboxes;
00083     vector<rect<int> >::iterator ibb;
00084     string cname = "patch";
00085     ostringstream fname;
00086     vector<idx<Tdata> > patches;
00087     
00088     // check for capacity
00089     if (this->full(label)) // reached full capacity
00090       return false;
00091     // for each scale, find patches and save them
00092     for (vector<double>::iterator i = scales.begin(); i != scales.end(); ++i) {
00093       patches.clear();
00094       patch_bboxes.clear();
00095       // rescale original bboxes
00096       uint outh = (uint) (outdims.dim(0) * *i);
00097       uint outw = (uint) (outdims.dim(1) * *i);
00098       float ratio = std::max(img.dim(0) / (float) outh, 
00099                              img.dim(1) / (float) outw);
00100       uint inh = (uint) (img.dim(0) / ratio);
00101       uint inw = (uint) (img.dim(1) / ratio);
00102       // do not upsample to avoid creating artefacts
00103       // and ignore sizes smaller than outdims
00104       if (inh > (uint) img.dim(0) || inw > (uint) img.dim(1)
00105           || inh < (uint) outdims.dim(0) || inw < (uint) outdims.dim(1)) {
00106         cerr << "warning: ignoring scale " << *i << " (" << inh << "x"
00107              << inw << ") to avoid upsampling original (" << img
00108              << ") or downsampling below target (" << outdims << ")." << endl;
00109         continue ; // do nothing for this scale
00110       }
00111       // preprocess image
00112       rect<int>  r(0, 0, img.dim(0), img.dim(1));
00113       rect<int>  outr;
00114       midx<Tdata> ims(1);
00115       ims.set(img, 0);
00116       ims = this->preprocess_data(ims, &cname, filename, &r, *i, &outr);
00117       if (ims.dim(0) > 1) eblerror("expected single layer patch");
00118       idx<Tdata> im = ims.get(0);
00119       ims.clear();
00120       // extract all non overlapping patches with dimensions outdims that
00121       // do not overlap with bounding boxes
00122       rect<int>  patch(0, 0, outdims.dim(0), outdims.dim(1));
00123       for (patch.h0 = outr.h0; patch.h0 + patch.height <= outr.h0 + outr.height;
00124            patch.h0 += patch.height) {
00125         for (patch.w0 = outr.w0; patch.w0 + patch.width <= outr.w0 + outr.width;
00126              patch.w0 += patch.width) {
00127           // add patch
00128           idx<Tdata> p = im.narrow(0, patch.height, patch.h0);
00129           p = p.narrow(1, patch.width, patch.w0);
00130           patches.push_back(p);
00131           patch_bboxes.push_back(patch);
00132         }
00133       }
00134 #ifdef __GUI__
00135       if (display_extraction) {
00136         uint h = 63, w = 0;
00137         //      disable_window_updates();
00138 //      // draw original image
00139 //      draw_matrix(im, h, w, 1.0, 1.0, (Tdata) -1, (Tdata) 1);
00140         // draw patches boxes
00141         for (ibb = patch_bboxes.begin(); ibb != patch_bboxes.end(); ++ibb)
00142           draw_box(h + ibb->h0, w + ibb->w0,
00143                    ibb->height, ibb->width, 0, 255, 0);
00144         //      enable_window_updates();
00145         if (sleep_display)
00146           millisleep((long) sleep_delay);
00147       }
00148 #endif
00149       save_patches(patches, outdir, max_folders, filename, *i, label);
00150     }
00151     return true;
00152   }
00153   
00155   // save patches
00156 
00157   template <class Tdata>
00158   void patch_dataset<Tdata>::save_patches(vector<idx<Tdata> > &patches,
00159                                           const string &outdir,
00160                                           uint max_folders,
00161                                           const string &filename,
00162                                           double scale, const t_label label) {
00163     ostringstream folder, fname;
00164     try {
00165       mkdir_full(outdir.c_str());
00166       uint i;
00167       // shuffle randomly vector of patches to avoid taking top left corner
00168       // as first patch every time
00169       random_shuffle(patches.begin(), patches.end());
00170       // loop on patches
00171       for (i = 0; (i < patches.size()) && (i < max_folders); ++i) {
00172         // create folder if doesn't exist
00173         folder.str("");
00174         folder << outdir << "/" << "bg" << i+1 << "/";
00175         mkdir_full(folder.str().c_str());
00176         // save patch in folder
00177         // switch saving behavior
00178         fname.str("");
00179         fname << folder.str() << "img_" << setw(5) << setfill('0') << data_cnt 
00180               << "_bg" << i+1 << "_scale" << scale;
00181         if (!strcmp(save_mode.c_str(), "mat")) { // lush matrix mode
00182           fname << MATRIX_EXTENSION;
00183           if (!save_matrix(patches[i], fname.str()))
00184             throw fname.str();
00185         } else { // image file mode
00186           fname << "." << save_mode;
00187           idx<Tdata> tmp = patches[i];
00188           // // scale image to 0 255 if preprocessed
00189           // if (strcmp(ppconv_type.c_str(), "RGB")) {
00190           //   idx_addc(tmp, (Tdata) 1.0, tmp);
00191           //   idx_dotc(tmp, (Tdata) 127.5, tmp);
00192           // }
00193           save_image(fname.str(), tmp, save_mode.c_str());
00194         }
00195         cout << data_cnt << ": saved " << fname.str().c_str()
00196              << "(" << patches[i] << ")" << endl;
00197         // increase global counter
00198         data_cnt++;
00199         // check for capacity
00200         if (this->full(label)) // reached full capacity
00201           break ;
00202       }
00203 //       if (i < patches.size()) // reached max_folders, fill-up last one
00204 //      for ( ; i < patches.size(); ++i) {
00205 //        // save patch in folder
00206 //        fname.str("");
00207 //        fname << folder.str() << filename << ".bg" << i+1 << ".mat";
00208 //        if (!save_matrix(patches[i], fname.str()))
00209 //          throw fname.str();
00210 //        cout << data_cnt++ << ": saved " << fname.str().c_str() << endl;
00211 //      }
00212     } catch (const string &err) {
00213       cerr << "error: failed to save patch in " << err << endl;
00214     }
00215   }
00216 
00217 } // end namespace ebl
00218 
00219 #endif /* PATCH_DATASET_HPP_ */