00001 /*!@file Neuro/SaliencyMapStdOptim.C */ 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/Neuro/SaliencyMapStdOptim.C $ 00035 // $Id: SaliencyMapStdOptim.C 13377 2010-05-09 15:55:07Z itti $ 00036 // 00037 00038 #ifndef NEURO_SALIENCYMAPSTDOPTIM_C_DEFINED 00039 #define NEURO_SALIENCYMAPSTDOPTIM_C_DEFINED 00040 00041 #include "Neuro/SaliencyMapStdOptim.H" 00042 00043 #include "Image/MathOps.H" 00044 #include "Neuro/NeuroOpts.H" 00045 #include "Simulation/SimEventQueue.H" 00046 #include "Util/JobWithSemaphore.H" 00047 #include "Util/MainJobServer.H" 00048 #include "Util/MathFunctions.H" 00049 #include "rutz/shared_ptr.h" 00050 #include "rutz/trace.h" 00051 00052 #include <vector> 00053 00054 namespace 00055 { 00056 //! Helper function to compute inhibition of return 00057 double iorHelper(const double d, const double ampl, const double sdev) 00058 { 00059 double d_dev = d / sdev; d_dev = -0.5 * d_dev * d_dev; 00060 if (d_dev < -20.0) return 0.0; 00061 return ampl * exp(d_dev); 00062 } 00063 00064 //! Helper function to compute inhibition of return 00065 double iorHelper(const Point2D<int>& p1, const Point2D<int>& p2, 00066 const double pampl, const double mampl, 00067 const double psdev, const double msdev) 00068 { 00069 double dx = double(p1.i - p2.i); 00070 double dy = double(p1.j - p2.j); 00071 double d = sqrt(squareOf(dx) + squareOf(dy)); 00072 return iorHelper(d, pampl, psdev) - iorHelper(d, mampl, msdev); 00073 } 00074 } 00075 00076 struct SaliencyMapStdOptim::UpdateJob : public JobWithSemaphore 00077 { 00078 UpdateJob(Image<float>::iterator vitr_, 00079 Image<float>::iterator vstop_, 00080 Image<float>::const_iterator iitr_, 00081 Image<float>::iterator ginhitr_, 00082 const float decay_, const float dt_c_, 00083 const float gleak_, 00084 const SimTime start_tm_, const SimTime end_tm_, 00085 const SimTime dt_) 00086 : 00087 vitr(vitr_), 00088 vstop(vstop_), 00089 iitr(iitr_), 00090 ginhitr(ginhitr_), 00091 decay(decay_), 00092 dt_c(dt_c_), 00093 gleak(gleak_), 00094 start_tm(start_tm_), 00095 end_tm(end_tm_), 00096 dt(dt_) 00097 {} 00098 00099 virtual ~UpdateJob() 00100 {} 00101 00102 virtual void run() 00103 { 00104 while (vitr != vstop) 00105 { 00106 for (SimTime tt = start_tm; tt < end_tm; tt += dt) 00107 { 00108 (*vitr) += dt_c * ( (*iitr) - ( gleak + (*ginhitr) ) * (*vitr) ); 00109 if (*vitr < 0.0F) *vitr = 0.0F; 00110 (*ginhitr) *= decay; // progressively loose inhibitory influences 00111 } 00112 00113 ++vitr; 00114 ++ginhitr; 00115 ++iitr; 00116 } 00117 00118 this->markFinished(); 00119 } 00120 00121 virtual const char* jobType() const 00122 { return "SaliencyMapStdOptimUpdateJob"; } 00123 00124 Image<float>::iterator vitr; 00125 Image<float>::iterator vstop; 00126 Image<float>::const_iterator iitr; 00127 Image<float>::iterator ginhitr; 00128 const float decay; 00129 const float dt_c; 00130 const float gleak; 00131 const SimTime start_tm; 00132 const SimTime end_tm; 00133 const SimTime dt; 00134 }; 00135 00136 // ###################################################################### 00137 // ###################################################################### 00138 // ########## SaliencyMapStdOptim implementation 00139 // ###################################################################### 00140 // ###################################################################### 00141 00142 // ###################################################################### 00143 SaliencyMapStdOptim::SaliencyMapStdOptim(OptionManager& mgr, 00144 const std::string& descrName, 00145 const std::string& tagName) : 00146 SaliencyMapAdapter(mgr, descrName, tagName), 00147 SIMCALLBACK_INIT(SimEventClockTick), 00148 itsTimeStep(SimTime::SECS(0.0001)), 00149 itsT(SimTime::ZERO()), 00150 itsC(5.0E-8F), 00151 itsGleak(1.0E-7F), 00152 itsV(), 00153 itsGinhDecay(&OPT_SMginhDecay, this) 00154 { 00155 GVX_TRACE(__PRETTY_FUNCTION__); 00156 } 00157 00158 // ###################################################################### 00159 SaliencyMapStdOptim::~SaliencyMapStdOptim() 00160 { 00161 GVX_TRACE(__PRETTY_FUNCTION__); 00162 } 00163 00164 // ###################################################################### 00165 void SaliencyMapStdOptim::reset() 00166 { 00167 GVX_TRACE(__PRETTY_FUNCTION__); 00168 itsV.freeMem(); 00169 } 00170 00171 // ###################################################################### 00172 void SaliencyMapStdOptim::input(SimEventQueue& q, const Image<float>& current) 00173 { 00174 GVX_TRACE(__PRETTY_FUNCTION__); 00175 if (itsV.initialized() == false) 00176 { 00177 itsGinh.resize(current.getDims(), true); 00178 itsV.resize(current.getDims(), true); 00179 } 00180 itsI = current; 00181 } 00182 00183 // ###################################################################### 00184 void SaliencyMapStdOptim::depress(SimEventQueue& q, const Point2D<int>& winner, 00185 const double& pampl, const double& mampl, 00186 const double& psdev, const double& msdev) 00187 { 00188 GVX_TRACE(__PRETTY_FUNCTION__); 00189 Point2D<int> p; 00190 const int ww = itsV.getWidth(); 00191 const int hh = itsV.getHeight(); 00192 Image<float>::iterator src = itsGinh.beginw(); 00193 00194 // open inhibitory conductances: 00195 for (p.j = 0; p.j < hh; ++p.j) 00196 for (p.i = 0; p.i < ww; ++p.i) 00197 (*src++) += float(iorHelper(winner, p, pampl, mampl, psdev, msdev)); 00198 00199 LDEBUG("Peak IOR conductance: %fmS", 00200 float(iorHelper(winner, winner, pampl, mampl, psdev, msdev)) * 1000.0F); 00201 } 00202 00203 // ###################################################################### 00204 void SaliencyMapStdOptim::depress(SimEventQueue& q, const Point2D<int>& winner, const double& ampl, 00205 const Image<byte>& objectMask) 00206 { 00207 GVX_TRACE(__PRETTY_FUNCTION__); 00208 Point2D<int> p; 00209 const int ww = itsV.getWidth(); 00210 const int hh = itsV.getHeight(); 00211 Image<float>::iterator src = itsGinh.beginw(); 00212 00213 // open inhibitory conductances: 00214 for (p.j = 0; p.j < hh; ++p.j) 00215 for (p.i = 0; p.i < ww; ++p.i) 00216 (*src++) += 0.1F / 255.F * ampl * float(objectMask.getVal(p)); 00217 00218 LDEBUG("Peak IOR conductance: %fmS", 00219 0.1F / 255.F * ampl * float(objectMask.getVal(winner)) * 1000.0F); 00220 } 00221 00222 // ###################################################################### 00223 void SaliencyMapStdOptim:: 00224 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& e) 00225 { 00226 GVX_TRACE(__PRETTY_FUNCTION__); 00227 const SimTime t = q.now(); 00228 00229 // we run our difference equations with a time step of itsTimeStep; 00230 // let's here figure out how many iterations we will need to go from 00231 // itsT to t. We will iterate for a number of equal steps, with each 00232 // step as close to itsTimeStep as possible to that we end up at 00233 // time t after iterating for an integer number of time steps: 00234 const SimTime dt = SimTime::computeDeltaT((t - itsT), itsTimeStep); 00235 const float dtsc = float(dt.secs()) / itsC; 00236 00237 JobServer& srv = getMainJobServer(); 00238 00239 const unsigned int ntiles = srv.getParallelismHint(); 00240 00241 std::vector<rutz::shared_ptr<UpdateJob> > jobs; 00242 00243 for (unsigned int i = 0; i < ntiles; ++i) 00244 { 00245 const int start = (i*itsV.getSize()) / ntiles; 00246 const int end = ((i+1)*itsV.getSize()) / ntiles; 00247 00248 jobs.push_back 00249 (rutz::make_shared(new UpdateJob 00250 (itsV.beginw() + start, 00251 itsV.beginw() + end, 00252 itsI.begin() + start, 00253 itsGinh.beginw() + start, 00254 itsGinhDecay.getVal(), 00255 dtsc, 00256 itsGleak, 00257 itsT, t, dt))); 00258 00259 srv.enqueueJob(jobs.back()); 00260 } 00261 00262 // barrier: 00263 for (size_t i = 0; i < jobs.size(); ++i) jobs[i]->wait(); 00264 00265 // post our map for everyone to enjoy: 00266 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsV, itsLevelSpec.getVal().mapLevel()))); 00267 00268 // we are done, just keep track of new current time: 00269 itsT = t; 00270 } 00271 00272 // ###################################################################### 00273 void SaliencyMapStdOptim::saccadicSuppression(SimEventQueue& q, const bool on) 00274 { 00275 GVX_TRACE(__PRETTY_FUNCTION__); 00276 // we setup a weak inhibitory conductance for saccadic suppression 00277 // of the Saliency Map, as there is evidence that some intra-saccadic visual 00278 // input may still influence eye movements. 00279 const float inG = 00280 on 00281 ? 1.0e-6F // on inhibitory conductance, in Siemens 00282 : 0.0F; // turning off 00283 00284 itsGinh.clear(inG); 00285 00286 LINFO("------- SaliencyMapStdOptim saccadic suppression %s -------", on ? "on":"off"); 00287 } 00288 00289 // ###################################################################### 00290 void SaliencyMapStdOptim::blinkSuppression(SimEventQueue& q, const bool on) 00291 { 00292 GVX_TRACE(__PRETTY_FUNCTION__); 00293 // we setup a weak inhibitory conductance for blink suppression of 00294 // the Saliency Map, as the visual input should also be turned off 00295 // in Brain 00296 const float inG = 00297 on 00298 ? 1.0e-6F // on inhibitory conductance, in Siemens 00299 : 0.0F; // turning off 00300 00301 itsGinh.clear(inG); 00302 00303 LINFO("------- SaliencyMapStdOptim blink suppression %s -------", on ? "on":"off"); 00304 } 00305 00306 // ###################################################################### 00307 Image<float> SaliencyMapStdOptim::getV() const 00308 { 00309 GVX_TRACE(__PRETTY_FUNCTION__); 00310 return itsV; 00311 } 00312 00313 // ###################################################################### 00314 float SaliencyMapStdOptim::getV(const Point2D<int>& p) const 00315 { 00316 GVX_TRACE(__PRETTY_FUNCTION__); 00317 return itsV.getVal(p); 00318 } 00319 00320 // ###################################################################### 00321 /* So things look consistent in everyone's emacs... */ 00322 /* Local Variables: */ 00323 /* mode: c++ */ 00324 /* indent-tabs-mode: nil */ 00325 /* End: */ 00326 00327 #endif // NEURO_SALIENCYMAPSTDOPTIM_C_DEFINED