FeatureExtractor.C

Go to the documentation of this file.
00001 /*!@file TIGS/FeatureExtractor.C Base class for topdown feature extractors. */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/TIGS/FeatureExtractor.C $
00035 // $Id: FeatureExtractor.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 #ifndef TIGS_FEATUREEXTRACTOR_C_DEFINED
00039 #define TIGS_FEATUREEXTRACTOR_C_DEFINED
00040 
00041 #include "TIGS/FeatureExtractor.H"
00042 
00043 #include "Component/ModelOptionDef.H"
00044 #include "Image/CutPaste.H"
00045 #include "Image/MathOps.H"
00046 #include "Raster/Raster.H"
00047 #include "TIGS/TigsOpts.H"
00048 #include "Util/log.H"
00049 #include "rutz/error_context.h"
00050 #include "rutz/sfmt.h"
00051 #include "rutz/trace.h"
00052 
00053 // Used by: FeatureExtractor
00054 static const ModelOptionDef OPT_CacheSavePrefix =
00055   { MODOPT_ARG_STRING, "CacheSavePrefix", &MOC_TIGS, OPTEXP_CORE,
00056     "Filename stem name for feature-extractor caches",
00057     "cache-save-prefix", '\0', "<string>", "" };
00058 
00059 namespace
00060 {
00061   template <class T>
00062   Image<T> asRow(const Image<T>& in)
00063   {
00064   GVX_TRACE(__PRETTY_FUNCTION__);
00065     return Image<T>(in.getArrayPtr(), in.getSize(), 1);
00066   }
00067 }
00068 
00069 FeatureExtractor::FeatureExtractor(OptionManager& mgr,
00070                                    const std::string& name)
00071   :
00072   ModelComponent(mgr, name, name),
00073   itsCacheSavePrefix(&OPT_CacheSavePrefix, this),
00074   itsName(name),
00075   itsCache(),
00076   itsNumHits(0),
00077   itsCheckFrequency(100),
00078   itsPrevTime(SimTime::ZERO())
00079 {}
00080 
00081 FeatureExtractor::~FeatureExtractor() {}
00082 
00083 void FeatureExtractor::start2()
00084 {
00085   this->load(itsCacheSavePrefix.getVal().c_str());
00086 }
00087 
00088 void FeatureExtractor::stop1()
00089 {
00090   this->save(itsCacheSavePrefix.getVal().c_str());
00091 }
00092 
00093 Image<float> FeatureExtractor::extract(const TigsInputFrame& fin)
00094 {
00095   GVX_TRACE(__PRETTY_FUNCTION__);
00096 
00097   GVX_ERR_CONTEXT(rutz::sfmt("extracting features in FeatureExtractor %s",
00098                              itsName.c_str()));
00099 
00100   const bool isnewtime = (fin.t() > itsPrevTime);
00101   itsPrevTime = fin.t();
00102 
00103   if (!this->isCacheable())
00104     return doExtract(fin);
00105 
00106   const Digest<16> digest = fin.getHash();;
00107 
00108   typedef std::map<Digest<16>, Image<float> > CacheType;
00109 
00110   CacheType::iterator itr = itsCache.find(digest);
00111 
00112   if (itr != itsCache.end())
00113     {
00114       LINFO("cache hit in %s on md5 digest %s",
00115             itsName.c_str(), digest.asString().c_str());
00116 
00117       ++itsNumHits;
00118 
00119       // periodically check things to make sure the cache is valid:
00120       if (isnewtime
00121           &&
00122           !fin.isGhost()
00123           &&
00124           (itsNumHits == 1 ||
00125            (itsCheckFrequency > 0
00126             && itsNumHits % itsCheckFrequency == 0)))
00127         {
00128           const Image<float> f = doExtract(fin);
00129 
00130           const Image<float> actual = asRow(f);
00131           const Image<float> expected = asRow((*itr).second);
00132 
00133           if (!(actual == expected))
00134             {
00135               LINFO("RMSerr(actual,expected)=%g", RMSerr(actual,expected));
00136               LINFO("corrcoef(actual,expected)=%g", corrcoef(actual,expected));
00137 
00138               LFATAL("cache integrity check failed "
00139                      "in %s after %d hits",
00140                      itsName.c_str(), itsNumHits);
00141             }
00142           else
00143             LINFO("cache integrity check OK in %s after %d hits",
00144                   itsName.c_str(), itsNumHits);
00145         }
00146 
00147       return (*itr).second;
00148     }
00149 
00150   // else...
00151   const Image<float> f = doExtract(fin);
00152   itsCache.insert(CacheType::value_type(digest, f));
00153   return f;
00154 }
00155 
00156 void FeatureExtractor::save(const char* pfx) const
00157 {
00158   GVX_TRACE(__PRETTY_FUNCTION__);
00159   if (!this->isCacheable())
00160     {
00161       LINFO("%s not cacheable; save() skipped", itsName.c_str());
00162       return;
00163     }
00164 
00165   if (itsCache.size() == 0)
00166     {
00167       LINFO("%s has no cache entries; save() skipped", itsName.c_str());
00168       return;
00169     }
00170 
00171   const std::string dfile = sformat("%s-%s-digests.pgm",
00172                                     pfx, itsName.c_str());
00173   const std::string ffile = sformat("%s-%s-features.pfm",
00174                                     pfx, itsName.c_str());
00175 
00176   if (Raster::fileExists(dfile))
00177     {
00178       LINFO("%s cache file %s already exists; save() skipped",
00179             itsName.c_str(), dfile.c_str());
00180       return;
00181     }
00182 
00183   if (Raster::fileExists(ffile))
00184     {
00185       LINFO("%s cache file %s already exists; save() skipped",
00186             itsName.c_str(), ffile.c_str());
00187       return;
00188     }
00189 
00190   ASSERT(itsCache.size() > 0);
00191 
00192   Image<byte> digests(16, itsCache.size(), NO_INIT);
00193   Image<float> features((*(itsCache.begin())).second.getSize(),
00194                         itsCache.size(), NO_INIT);
00195 
00196   typedef std::map<Digest<16>, Image<float> > CacheType;
00197 
00198   int row = 0;
00199 
00200   for (CacheType::const_iterator
00201          itr = itsCache.begin(), stop = itsCache.end();
00202        itr != stop; ++itr)
00203     {
00204       inplacePaste(digests, (*itr).first.asImage(),
00205                    Point2D<int>(0, row));
00206 
00207       inplacePaste(features, asRow((*itr).second),
00208                    Point2D<int>(0, row));
00209 
00210       ++row;
00211     }
00212 
00213   ASSERT(size_t(row) == itsCache.size());
00214 
00215   Raster::WriteGray(digests, dfile, RASFMT_PNM);
00216   Raster::WriteFloat(features, FLOAT_NORM_PRESERVE, ffile, RASFMT_PFM);
00217 
00218   LINFO("saved %d cache entries to %s", row, dfile.c_str());
00219   LINFO("saved %d cache entries to %s", row, ffile.c_str());
00220 }
00221 
00222 void FeatureExtractor::load(const char* pfx)
00223 {
00224   GVX_TRACE(__PRETTY_FUNCTION__);
00225   if (!this->isCacheable())
00226     {
00227       LINFO("%s not cacheable; load() skipped", itsName.c_str());
00228       return;
00229     }
00230 
00231   const std::string dfile = sformat("%s-%s-digests.pgm",
00232                                     pfx, itsName.c_str());
00233   const std::string ffile = sformat("%s-%s-features.pfm",
00234                                     pfx, itsName.c_str());
00235 
00236   if (!Raster::fileExists(dfile))
00237     {
00238       LINFO("%s cache file %s not found; load() skipped",
00239             itsName.c_str(), dfile.c_str());
00240       return;
00241     }
00242 
00243   if (!Raster::fileExists(ffile))
00244     {
00245       LINFO("%s cache file %s not found; load() skipped",
00246             itsName.c_str(), ffile.c_str());
00247       return;
00248     }
00249 
00250   const Image<byte> digests = Raster::ReadGray(dfile, RASFMT_PNM);
00251   const Image<float> features = Raster::ReadFloat(ffile, RASFMT_PFM);
00252 
00253   ASSERT(digests.getHeight() == features.getHeight());
00254 
00255   const int nrows = digests.getHeight();
00256 
00257   typedef std::map<Digest<16>, Image<float> > CacheType;
00258 
00259   itsCache.clear();
00260 
00261   LINFO("digests=%dx%d", digests.getWidth(), digests.getHeight());
00262 
00263   for (int i = 0; i < nrows; ++i)
00264     {
00265       Digest<16> d = Digest<16>::asDigest(&digests[Point2D<int>(0, i)],
00266                                           digests.getWidth());
00267 
00268       Image<float> f(&features[Point2D<int>(0, i)],
00269                      features.getWidth(), 1);
00270 
00271       itsCache.insert(CacheType::value_type(d, f));
00272     }
00273 
00274   ASSERT(itsCache.size() == size_t(nrows));
00275 
00276   LINFO("loaded %d cache entries from %s", nrows, dfile.c_str());
00277   LINFO("loaded %d cache entries from %s", nrows, ffile.c_str());
00278 }
00279 
00280 // ######################################################################
00281 /* So things look consistent in everyone's emacs... */
00282 /* Local Variables: */
00283 /* mode: c++ */
00284 /* indent-tabs-mode: nil */
00285 /* End: */
00286 
00287 #endif // TIGS_FEATUREEXTRACTOR_C_DEFINED
Generated on Sun May 8 08:42:23 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3