IntegerSimpleChannel.C

Go to the documentation of this file.
00001 /*!@file Channels/IntegerSimpleChannel.C IntegerSimpleChannel is like SingleChannel, but avoids floating-point arithmetic */
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/Channels/IntegerSimpleChannel.C $
00035 // $Id: IntegerSimpleChannel.C 10983 2009-03-05 07:19:14Z itti $
00036 //
00037 
00038 #ifndef CHANNELS_INTEGERSIMPLECHANNEL_C_DEFINED
00039 #define CHANNELS_INTEGERSIMPLECHANNEL_C_DEFINED
00040 
00041 #include "Channels/IntegerSimpleChannel.H"
00042 
00043 #include "Channels/ChannelOpts.H"
00044 #include "Component/GlobalOpts.H"
00045 #include "Component/ModelOptionDef.H"
00046 #include "Image/Image.H"
00047 #include "Image/ImageSetOps.H"
00048 #include "Image/IntegerMathOps.H"
00049 #include "Image/MathOps.H"    // for binaryReverse()
00050 #include "Image/PyrBuilder.H"
00051 #include "Transport/FrameInfo.H"
00052 #include "Transport/FrameOstream.H"
00053 #include "Util/Assert.H"
00054 #include "Util/log.H"
00055 #include "Util/sformat.H"
00056 #include "rutz/trace.h"
00057 
00058 #include "Image/CutPaste.H"
00059 #include <cmath>
00060 #include <limits>
00061 
00062 const int INTMAXNORMMIN = 0;
00063 const int INTMAXNORMMAX = 32768;
00064 
00065 // ######################################################################
00066 IntegerSimpleChannel::
00067 IntegerSimpleChannel(OptionManager& mgr, const std::string& descrName,
00068                      const std::string& tag,
00069                      const VisualFeature vs,
00070                      rutz::shared_ptr<PyrBuilder<int> > pbuild,
00071                      nub::ref<IntegerMathEngine> eng) :
00072   IntegerChannel(mgr, descrName, tag, vs, eng),
00073   itsTakeAbs("IntegerSimpleChannelTakeAbs", this, false),
00074   itsNormalizeOutput("IntegerSimpleChannelNormalizeOutput", this, false),
00075   itsScaleNoiseToMax("IntegerSimpleChannelScaleNoiseToMax", this, false),
00076   itsLowThresh("IntegerSimpleChannelLowThresh", this, 0),
00077   itsRectifyPyramid("IntegerSimpleChannelRectifyPyramid", this, false),
00078   itsUseRandom(&OPT_UseRandom, this),  // see Component/ModelManager.{H,C}
00079   itsLevelSpec(&OPT_LevelSpec, this),    // see Channels/ChannelOpts.{H,C}
00080   itsNormType(&OPT_MaxNormType, this), // see Channels/ChannelOpts.{H,C}
00081   itsQlen(&OPT_SingleChannelQueueLen, this),       // see Channels/ChannelOpts.{H,C}
00082   itsUseOlderVersion(&OPT_UseOlderVersion, this), // see Channels/ChannelOpts.{H,C}
00083   itsSaveRawMaps(&OPT_SingleChannelSaveRawMaps, this),
00084   itsSaveFeatureMaps(&OPT_SingleChannelSaveFeatureMaps, this),
00085   itsSaveOutputMap(&OPT_SingleChannelSaveOutputMap, this),
00086   itsOutputRangeMin(&OPT_IntChannelOutputRangeMin, this),
00087   itsOutputRangeMax(&OPT_IntChannelOutputRangeMax, this),
00088   itsPyr(),
00089   itsT(SimTime::ZERO()),
00090   itsOutputCache(),
00091   itsSubmapCache(NULL),
00092   itsPyrBuilder(pbuild),
00093   itsClipPyr()
00094 {
00095 GVX_TRACE(__PRETTY_FUNCTION__);
00096 }
00097 
00098 // ######################################################################
00099 IntegerSimpleChannel::~IntegerSimpleChannel()
00100 {
00101 GVX_TRACE(__PRETTY_FUNCTION__);
00102 }
00103 
00104 // ######################################################################
00105 void IntegerSimpleChannel::start1()
00106 {
00107 GVX_TRACE(__PRETTY_FUNCTION__);
00108   const int maxind = itsLevelSpec.getVal().maxIndex();
00109   itsSubmapCache = new Image<int>[maxind];
00110 
00111   // in the new version, leave our output range open rather than
00112   // forcing it to a given range of values:
00113   if (itsUseOlderVersion.getVal() == false)
00114     {
00115       itsOutputRangeMin.setVal(0);
00116       itsOutputRangeMax.setVal(0);
00117     }
00118 
00119   // in the older version, we used to set the map range as we would
00120   // also apply spatial competition for salience to the output map,
00121   // only if using the MAXNORM type of competition, and otherwise we
00122   // would not touch the range:
00123   if (itsUseOlderVersion.getVal() && itsNormType.getVal() != VCXNORM_MAXNORM)
00124     {
00125       itsOutputRangeMin.setVal(0);
00126       itsOutputRangeMax.setVal(0);
00127     }
00128 
00129   if (itsPyrBuilder.get() == 0)
00130     LFATAL("Oops! I have no PyrBuilder!");
00131 }
00132 
00133 // ######################################################################
00134 void IntegerSimpleChannel::stop2()
00135 {
00136 GVX_TRACE(__PRETTY_FUNCTION__);
00137   delete [] itsSubmapCache; itsSubmapCache = 0;
00138 }
00139 
00140 // ######################################################################
00141 void IntegerSimpleChannel::reset1()
00142 {
00143 GVX_TRACE(__PRETTY_FUNCTION__);
00144   // reset some stuff for IntegerSimpleChannel
00145   itsPyrBuilder->reset();
00146   itsPyr.clear();
00147   itsClipPyr.clear();
00148   killCaches();
00149 
00150   // propagate to our base class:
00151   IntegerChannel::reset1();
00152 }
00153 
00154 // ######################################################################
00155 void IntegerSimpleChannel::readFrom(const ParamMap& pmap)
00156 {
00157 GVX_TRACE(__PRETTY_FUNCTION__);
00158 
00159   if (!this->started())
00160     CLFATAL("must be start()-ed before using readFrom()");
00161 
00162   IntegerChannel::readFrom(pmap);
00163   ChannelFacetMap::readFacetsFrom(pmap);
00164 }
00165 
00166 // ######################################################################
00167 void IntegerSimpleChannel::writeTo(ParamMap& pmap) const
00168 {
00169 GVX_TRACE(__PRETTY_FUNCTION__);
00170 
00171   if (!this->started())
00172     CLFATAL("must be start()-ed before using readFrom()");
00173 
00174   IntegerChannel::writeTo(pmap);
00175   ChannelFacetMap::writeFacetsTo(pmap);
00176 }
00177 
00178 // ######################################################################
00179 bool IntegerSimpleChannel::outputAvailable() const
00180 {
00181 GVX_TRACE(__PRETTY_FUNCTION__);
00182 
00183   return (itsPyr.isEmpty() == false) || itsOutputCache.initialized();
00184 }
00185 
00186 // ######################################################################
00187 Dims IntegerSimpleChannel::getMapDims() const
00188 {
00189 GVX_TRACE(__PRETTY_FUNCTION__);
00190   const int lev = itsLevelSpec.getVal().mapLevel();
00191 
00192   return Dims(this->getInputDims().w() / (1 << lev),
00193               this->getInputDims().h() / (1 << lev));
00194 }
00195 
00196 // ######################################################################
00197 uint IntegerSimpleChannel::numSubmaps() const
00198 {
00199 GVX_TRACE(__PRETTY_FUNCTION__);
00200   return itsLevelSpec.getVal().maxIndex();
00201 }
00202 
00203 // ######################################################################
00204 Image<int> IntegerSimpleChannel::getSubmapInt(const uint i) const
00205 {
00206 GVX_TRACE(__PRETTY_FUNCTION__);
00207   // cache the results for later use if we don't already have cached it:
00208   if (itsSubmapCache[i].initialized() == false)
00209     {
00210       itsSubmapCache[i] = this->getRawCSmapInt(i);
00211       uint clev = 0, slev = 0;
00212       itsLevelSpec.getVal().indexToCS(i, clev, slev);
00213 
00214 
00215       // resize itsSubmapCache[i] to fixed scale if necessary:
00216       if (itsSubmapCache[i].getWidth() > getMapDims().w())
00217         itsSubmapCache[i] = intgDownSize(itsSubmapCache[i], getMapDims(),
00218                                          9, this->getImath());
00219       else if (itsSubmapCache[i].getWidth() < getMapDims().w())
00220         itsSubmapCache[i] = intgRescale(itsSubmapCache[i], getMapDims());
00221 
00222       // add noise if wanted:
00223       if (itsUseRandom.getVal())
00224         {
00225           // check if we want to scale noise to maximum of image
00226           if (itsScaleNoiseToMax.getVal())
00227             {
00228               int fMin, fMax; getMinMax(itsSubmapCache[i], fMin, fMax);
00229               intgInplaceAddBGnoise(itsSubmapCache[i], fMax);
00230             }
00231           else
00232             intgInplaceAddBGnoise(itsSubmapCache[i],
00233                                   (1 << this->getImath()->nbits));
00234         }
00235 
00236       // if using the older version: first normalize the submap to a
00237       // fixed dynamic range and then apply spatial competition for
00238       // salience to the submap; otherwise, just apply competition:
00239       if (itsUseOlderVersion.getVal())
00240         {
00241           LDEBUG("%s(%d,%d): applying %s(%f .. %f)", tagName().c_str(), clev, slev,
00242                  maxNormTypeName(itsNormType.getVal()), MAXNORMMIN, MAXNORMMAX);
00243           itsSubmapCache[i] =
00244             intgMaxNormalize(itsSubmapCache[i], INTMAXNORMMIN, INTMAXNORMMAX,
00245                          itsNormType.getVal());
00246         }
00247       else
00248         {
00249           LDEBUG("%s(%d,%d): applying %s(0.0 .. 0.0)", tagName().c_str(),
00250                  clev, slev, maxNormTypeName(itsNormType.getVal()));
00251           itsSubmapCache[i] =
00252             intgMaxNormalize(itsSubmapCache[i], 0, 0,
00253                          itsNormType.getVal());
00254         }
00255 
00256       // print some debug info if in debug mode:
00257       if (MYLOGVERB >= LOG_DEBUG)
00258         {
00259           int mi, ma; getMinMax(itsSubmapCache[i], mi, ma);
00260           LDEBUG("%s(%d,%d): final range [%d .. %d]",
00261                  tagName().c_str(), clev, slev, mi, ma);
00262         }
00263     }
00264 
00265   return itsSubmapCache[i];
00266 }
00267 
00268 // ######################################################################
00269 Image<int> IntegerSimpleChannel::getRawCSmapInt(const uint idx) const
00270 {
00271 GVX_TRACE(__PRETTY_FUNCTION__);
00272   ASSERT(itsLevelSpec.getVal().indexOK(idx));
00273   if (itsPyr.isEmpty()) CLFATAL("I have no input pyramid yet!");
00274 
00275   // otherwise, compute center-surround map:
00276   uint clev = 0, slev = 0;
00277   itsLevelSpec.getVal().indexToCS(idx, clev, slev);
00278 
00279   // submap is computed from a center-surround difference:
00280   const Image<int> submap =
00281     intgCenterSurround(itsPyr, clev, slev, itsTakeAbs.getVal(), &itsClipPyr);
00282 
00283   // print some debug info if in debug mode:
00284   if (MYLOGVERB >= LOG_DEBUG)
00285     {
00286       int mi, ma; getMinMax(submap, mi, ma);
00287       LDEBUG("%s(%d,%d): raw range [%d .. %d]", tagName().c_str(),
00288              clev, slev, mi, ma);
00289     }
00290 
00291   return submap;
00292 }
00293 
00294 // ######################################################################
00295 std::string IntegerSimpleChannel::getSubmapName(const uint idx) const
00296 {
00297 GVX_TRACE(__PRETTY_FUNCTION__);
00298   ASSERT( itsLevelSpec.getVal().indexOK(idx) );
00299 
00300   uint clev = 0, slev = 0;
00301   itsLevelSpec.getVal().indexToCS(idx, clev, slev);
00302 
00303   return sformat("%s lev: %d delta: %d",
00304                  descriptiveName().c_str(), clev, slev-clev);
00305 }
00306 
00307 // ######################################################################
00308 std::string IntegerSimpleChannel::getSubmapNameShort(const uint idx) const
00309 {
00310 GVX_TRACE(__PRETTY_FUNCTION__);
00311   ASSERT( itsLevelSpec.getVal().indexOK(idx) );
00312 
00313   uint clev = 0, slev = 0;
00314   itsLevelSpec.getVal().indexToCS(idx, clev, slev);
00315 
00316   return sformat("%s(%d,%d)", tagName().c_str(), clev, slev);
00317 }
00318 
00319 // ######################################################################
00320 void IntegerSimpleChannel::getFeatures(const Point2D<int>& locn,
00321                                 std::vector<float>& mean) const
00322 {
00323   CLFATAL("not implemented");
00324 }
00325 
00326 // ######################################################################
00327 void IntegerSimpleChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn,
00328                                      std::vector<std::vector<float> > *mean,
00329                                      int *count) const
00330 {
00331   CLFATAL("not implemented");
00332 }
00333 
00334 // ######################################################################
00335 void IntegerSimpleChannel::killCaches()
00336 {
00337 GVX_TRACE(__PRETTY_FUNCTION__);
00338   IntegerChannel::killCaches(); // call our base class's implementation
00339 
00340   itsOutputCache.freeMem();
00341 
00342   // our caches exist only when we are in started() state:
00343   if (started())
00344     for (uint i = 0; i < itsLevelSpec.getVal().maxIndex(); ++i)
00345       itsSubmapCache[i] = Image<int>();
00346 }
00347 
00348 // ######################################################################
00349 void IntegerSimpleChannel::doInputInt(const IntegerInput& inp,
00350                                       const SimTime& t,
00351                                       PyramidCache<int>* cache,
00352                                       const Image<byte>& clipMask)
00353 {
00354   ASSERT(inp.grayInt().initialized());
00355 
00356   // if necessary create pyramid of clipping masks
00357   if (clipMask.initialized())
00358     {
00359       itsClipPyr = intgBuildPyrGaussian
00360         (intgScaleFromByte(&clipMask, this->getImath()->nbits),
00361          itsLevelSpec.getVal().maxDepth(), 9,
00362          this->getImath());
00363       intgDoLowThresh(itsClipPyr, 255, 0);
00364     }
00365   else
00366     itsClipPyr.clear();
00367 
00368   // Compute our pyramid:
00369   itsPyr = itsPyrBuilder->
00370     build(inp.grayInt(),
00371           this->getMinPyrLevel(), this->getMaxPyrLevel(), cache);
00372 
00373   // Eliminate small values if and/or rectify the pyramid desired:
00374   if (itsLowThresh.getVal() > 0)
00375     {
00376       if (itsRectifyPyramid.getVal())
00377         intgDoLowThresh(itsPyr, itsLowThresh.getVal());
00378       else
00379         intgDoLowThreshAbs(itsPyr, itsLowThresh.getVal());
00380     }
00381   else if (itsRectifyPyramid.getVal())
00382     intgDoRectify(itsPyr);
00383 
00384   itsT = t;
00385 
00386   // We only want dyadic pyramids here:
00387   ASSERT(isDyadic(itsPyr.subSet
00388                   (this->getMinPyrLevel(), this->getMaxPyrLevel())));
00389 }
00390 
00391 // ######################################################################
00392 LevelSpec IntegerSimpleChannel::getLevelSpec() const
00393 {
00394 GVX_TRACE(__PRETTY_FUNCTION__);
00395   return itsLevelSpec.getVal();
00396 }
00397 
00398 // ######################################################################
00399 Image<int> IntegerSimpleChannel::getOutputInt()
00400 {
00401 GVX_TRACE(__PRETTY_FUNCTION__);
00402 
00403   if (!this->hasInput())
00404     // if you think this LFATAL() has been triggered incorrectly, then
00405     // first make sure that somebody has called setInputDims()
00406     CLFATAL("Oops! can't get output -- I don't even have any input yet");
00407 
00408   if (!this->outputAvailable())
00409     {
00410       // it's possible that we have input but don't yet have output in
00411       // the case of a channel that requires several input frames
00412       // before it can start generating output (such as a flicker or
00413       // motion channel); in that case we just return an empty image
00414       // of the appropriate size
00415 
00416       LERROR("No %s channel yet! -- IGNORING.", this->tagName().c_str());
00417 
00418       return Image<int>(this->getMapDims(), ZEROS);
00419     }
00420 
00421   if (!itsOutputCache.initialized())
00422     {
00423       itsOutputCache = Image<int>(getMapDims(), ZEROS);
00424 
00425       // compute max-normalized weighted sum of center-surround at all levels:
00426       for (uint idx = 0; idx < itsLevelSpec.getVal().maxIndex(); ++idx)
00427         {
00428           const Image<int> submap = getSubmapInt(idx); // get the unweighted map
00429 
00430           // add submap to our sum
00431           itsOutputCache += (submap / int(itsLevelSpec.getVal().maxIndex()));
00432 
00433           if (MYLOGVERB >= LOG_DEBUG)
00434             {
00435               uint clev = 0, slev = 0;
00436               itsLevelSpec.getVal().indexToCS(idx, clev, slev);
00437               LDEBUG("%s(%d,%d): weight %f", tagName().c_str(), clev, slev, 1.0f);
00438             }
00439         }
00440 
00441 
00442       // apply max-normalization on the output as needed:
00443       if (itsNormalizeOutput.getVal())
00444         {
00445           LDEBUG("%s: Normalizing output: %s(%d .. %d)", tagName().c_str(),
00446                  maxNormTypeName(itsNormType.getVal()), itsOutputRangeMin.getVal(),
00447                  itsOutputRangeMax.getVal());
00448 
00449           itsOutputCache =
00450             intgMaxNormalize(itsOutputCache, itsOutputRangeMin.getVal(),
00451                          itsOutputRangeMax.getVal(), itsNormType.getVal());
00452         }
00453 
00454       // print some debug info if in debug mode:
00455       if (MYLOGVERB >= LOG_DEBUG)
00456         {
00457           int mi, ma; getMinMax(itsOutputCache, mi, ma);
00458           LDEBUG("%s: final range [%d .. %d]", tagName().c_str(), mi, ma);
00459         }
00460 
00461       LINFO("Computed %s Conspicuity Map", descriptiveName().c_str());
00462     }
00463 
00464   return itsOutputCache;
00465 }
00466 
00467 // ######################################################################
00468 uint IntegerSimpleChannel::csToIndex(const uint centerlev,
00469                               const uint surroundlev) const
00470 {
00471 GVX_TRACE(__PRETTY_FUNCTION__);
00472   return itsLevelSpec.getVal().csToIndex(centerlev, surroundlev);
00473 }
00474 
00475 // ######################################################################
00476 void IntegerSimpleChannel::saveResults(const nub::ref<FrameOstream>& ofs)
00477 {
00478 GVX_TRACE(__PRETTY_FUNCTION__);
00479 
00480   if (itsPyr.isEmpty() == false)
00481     {
00482       // save raw pyramid levels?
00483       if (itsSaveRawMaps.getVal()) {
00484         for (uint i = 0; i < itsPyr.size(); i ++)
00485           ofs->writeFloat(Image<float>(itsPyr[i]), FLOAT_NORM_0_255,
00486                           sformat("ISR%s-%d-", tagName().c_str(),i),
00487                           FrameInfo(sformat("%s IntegerSimpleChannel raw map (%u of %u)",
00488                                             this->descriptiveName().c_str(),
00489                                             i, itsPyr.size()),
00490                                     SRC_POS));
00491       }
00492 
00493       // save center-surround feature submaps?
00494       if (itsSaveFeatureMaps.getVal())
00495         for (uint i = 0; i < numSubmaps(); i ++) {
00496           uint clev = 0, slev = 0;
00497           itsLevelSpec.getVal().indexToCS(i, clev, slev);
00498           ofs->writeFloat(Image<float>(getSubmapInt(i)),
00499                           FLOAT_NORM_0_255,
00500                           sformat("ISF%s-%d-%d-", tagName().c_str(),clev, slev),
00501                           FrameInfo(sformat("%s IntegerSimpleChannel center-surround map (c=%u s=%u)",
00502                                             this->descriptiveName().c_str(),
00503                                             clev, slev),
00504                                     SRC_POS));
00505         }
00506     }
00507 
00508   // save output map?
00509   if (itsSaveOutputMap.getVal())
00510     ofs->writeFloat(getOutput(), FLOAT_NORM_0_255,
00511                     sformat("ISO%s-", tagName().c_str()),
00512                     FrameInfo(sformat("%s IntegerSimpleChannel output",
00513                                       this->descriptiveName().c_str()),
00514                               SRC_POS));
00515 }
00516 
00517 // ######################################################################
00518 void IntegerSimpleChannel::setPyrBuilder(rutz::shared_ptr<PyrBuilder<int> > pbuild)
00519 {
00520 GVX_TRACE(__PRETTY_FUNCTION__);
00521 
00522   ASSERT(pbuild.get() != 0);
00523   this->killCaches();
00524   itsPyrBuilder = pbuild;
00525 }
00526 
00527 // ######################################################################
00528 /* So things look consistent in everyone's emacs... */
00529 /* Local Variables: */
00530 /* mode: c++ */
00531 /* indent-tabs-mode: nil */
00532 /* End: */
00533 
00534 #endif // CHANNELS_INTEGERSIMPLECHANNEL_C_DEFINED
Generated on Sun May 8 08:40:21 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3