00001 /*!@file Neuro/SaliencyMap.C Implementation for saliency map class */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // 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: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/SaliencyMap.C $ 00035 // $Id: SaliencyMap.C 13377 2010-05-09 15:55:07Z itti $ 00036 // 00037 00038 #include "Neuro/SaliencyMap.H" 00039 00040 #include "Channels/ChannelOpts.H" // for OPT_LevelSpec 00041 #include "Component/OptionManager.H" 00042 #include "Image/Image.H" 00043 #include "Image/MathOps.H" // for inplaceAddWeighted() 00044 #include "Image/FilterOps.H" // for inplaceAddWeighted() 00045 #include "Neuro/NeuroOpts.H" 00046 #include "Neuro/SpatialMetrics.H" 00047 #include "Neuro/NeuroSimEvents.H" 00048 #include "Simulation/SimulationOpts.H" 00049 #include "Simulation/SimEventQueue.H" 00050 #include "Transport/FrameInfo.H" 00051 #include "Transport/FrameOstream.H" 00052 #include "Util/Assert.H" 00053 #include "Util/MathFunctions.H" 00054 #include "Util/Types.H" 00055 #include "Util/log.H" 00056 #include "rutz/trace.h" 00057 00058 #include <cmath> 00059 00060 namespace 00061 { 00062 //! Helper function to compute inhibition of return 00063 double iorHelper(const double d, const double ampl, const double sdev) 00064 { 00065 double d_dev = d / sdev; d_dev = -0.5 * d_dev * d_dev; 00066 if (d_dev < -20.0) return 0.0; 00067 return ampl * exp(d_dev); 00068 } 00069 00070 //! Helper function to compute inhibition of return 00071 double iorHelper(const Point2D<int>& p1, const Point2D<int>& p2, 00072 const double pampl, const double mampl, 00073 const double psdev, const double msdev) 00074 { 00075 double dx = double(p1.i - p2.i); 00076 double dy = double(p1.j - p2.j); 00077 double d = sqrt(squareOf(dx) + squareOf(dy)); 00078 return iorHelper(d, pampl, psdev) - iorHelper(d, mampl, msdev); 00079 } 00080 } 00081 00082 // ###################################################################### 00083 // ###################################################################### 00084 // ########## SaliencyMap implementation 00085 // ###################################################################### 00086 // ###################################################################### 00087 00088 SaliencyMap::SaliencyMap(OptionManager& mgr, 00089 const std::string& descrName, 00090 const std::string& tagName) : 00091 SimModule(mgr, descrName, tagName) 00092 { 00093 GVX_TRACE(__PRETTY_FUNCTION__); 00094 } 00095 00096 // ###################################################################### 00097 SaliencyMap::~SaliencyMap() 00098 { 00099 GVX_TRACE(__PRETTY_FUNCTION__); 00100 } 00101 00102 // ###################################################################### 00103 // ###################################################################### 00104 // ########## SaliencyMapStub implementation 00105 // ###################################################################### 00106 // ###################################################################### 00107 00108 SaliencyMapStub::SaliencyMapStub(OptionManager& mgr, 00109 const std::string& descrName, 00110 const std::string& tagName) : 00111 SaliencyMap(mgr, descrName, tagName) 00112 { 00113 GVX_TRACE(__PRETTY_FUNCTION__); 00114 } 00115 00116 // ###################################################################### 00117 SaliencyMapStub::~SaliencyMapStub() 00118 { 00119 GVX_TRACE(__PRETTY_FUNCTION__); 00120 } 00121 00122 // ###################################################################### 00123 // ###################################################################### 00124 // ########## SaliencyMapAdapter implementation 00125 // ###################################################################### 00126 // ###################################################################### 00127 00128 SaliencyMapAdapter::SaliencyMapAdapter(OptionManager& mgr, 00129 const std::string& descrName, 00130 const std::string& tagName) : 00131 SaliencyMap(mgr, descrName, tagName), 00132 SIMCALLBACK_INIT(SimEventWTAwinner), 00133 SIMCALLBACK_INIT(SimEventVisualCortexOutput), 00134 SIMCALLBACK_INIT(SimEventSaccadeStatusEye), 00135 SIMCALLBACK_INIT(SimEventSaveOutput), 00136 itsMetrics(new SpatialMetrics(mgr)), 00137 itsIORtype(&OPT_IORtype, this), // see Neuro/NeuroOpts.{H,C} 00138 itsLevelSpec(&OPT_LevelSpec, this), //Channels/ChannelOpts.{H,C} 00139 itsSaveResults(&OPT_SMsaveResults, this), // see Neuro/NeuroOpts.{H,C} 00140 itsSaveCumResults(&OPT_SMsaveCumResults, this), // idem 00141 itsUseSaccadicSuppression(&OPT_SMuseSacSuppress, this), 00142 itsUseBlinkSuppression(&OPT_SMuseBlinkSuppress, this), 00143 itsMaxWinMv(&OPT_SMmaxWinV, this) 00144 { 00145 GVX_TRACE(__PRETTY_FUNCTION__); 00146 this->addSubComponent(itsMetrics); 00147 } 00148 00149 // ###################################################################### 00150 SaliencyMapAdapter::~SaliencyMapAdapter() 00151 { 00152 GVX_TRACE(__PRETTY_FUNCTION__); 00153 } 00154 00155 // ###################################################################### 00156 void SaliencyMapAdapter:: 00157 onSimEventWTAwinner(SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e) 00158 { 00159 const WTAwinner winner = e->winner(); 00160 const float winV = this->getV(winner.smpos); 00161 00162 // show SM voltage at winning location: 00163 LINFO("SM voltage at winner: %fmV above rest", 1000.0 * winV); 00164 00165 // if current winning voltage is too high, calm things down with 00166 // some mild broad inhibition: 00167 if (1000.0 * winV > itsMaxWinMv.getVal()) 00168 { 00169 LINFO("Triggering global inhibition to avoid map explosion."); 00170 this->depress(q, winner.smpos, 00171 0.00005 * (winV - itsMaxWinMv.getVal() / 1000.0), 00172 0.0, 00173 1000.0 * double(itsMetrics->getFOAradius()), 00174 100.0); 00175 } 00176 00177 // now do our inhibition-of-return, if any 00178 if (itsIORtype.getVal() != IORnone) 00179 { 00180 // any available ShapeEstimator IOR mask? NOTE: The shape 00181 // estimator will not work without also specifying 00182 // --shape-estim-mode= at the command line otherwise the shape 00183 // estimator will not run and this will ALWAYS be not 00184 // initialized! 00185 Image<float> IORmask; 00186 if (SeC<SimEventShapeEstimatorOutput> ee = 00187 q.check<SimEventShapeEstimatorOutput>(this, SEQ_ANY)) 00188 IORmask = ee->iorMask(); 00189 00190 if (itsIORtype.getVal() == IORdisc || IORmask.initialized() == false) 00191 { 00192 // compute the parameters of the local depression, and depress 00193 // amplitudes for M-hat: 00194 const double pAmpl = 0.1 * double(winV); // strongly inhib winner 00195 const double mAmpl = 1e-4 * pAmpl; // mildly excite surround 00196 // standard deviations for M_hat: inhibit of the foa size 00197 const double pSdev = 0.3 * double(itsMetrics->getFOAradius()) / 00198 double(1 << itsLevelSpec.getVal().mapLevel()); //foa inhib 00199 const double mSdev = 4.0 * pSdev; // wide mild excit outside foa 00200 this->depress(q, winner.smpos, pAmpl, mAmpl, pSdev, mSdev); 00201 LINFO("Inhibition of return fired."); 00202 } 00203 else if (itsIORtype.getVal() == IORshapeEst && IORmask.initialized()) 00204 { 00205 this->depress(q, winner.smpos, winV, IORmask); 00206 LINFO("ShapeEstimator-based inhibition of return fired."); 00207 } 00208 } 00209 } 00210 00211 // ###################################################################### 00212 void SaliencyMapAdapter:: 00213 onSimEventVisualCortexOutput(SimEventQueue& q, rutz::shared_ptr<SimEventVisualCortexOutput>& e) 00214 { 00215 // Use the new VisualCortex output as our inputs: 00216 this->input(q, e->vco()); 00217 } 00218 00219 // ###################################################################### 00220 void SaliencyMapAdapter:: 00221 onSimEventSaccadeStatusEye(SimEventQueue& q, rutz::shared_ptr<SimEventSaccadeStatusEye>& e) 00222 { 00223 // get any eye activity so we can check for saccades or blinks: 00224 00225 // any eye saccade and we are using saccadic suppression? 00226 if (itsUseSaccadicSuppression.getVal()) 00227 { 00228 if (e->saccadeStatus() == TSTATUS_BEGIN) this->saccadicSuppression(q, true); 00229 else if (e->saccadeStatus() == TSTATUS_END) this->saccadicSuppression(q, false); 00230 } 00231 00232 // any eye blink and we are using blink suppression? 00233 if (itsUseBlinkSuppression.getVal()) 00234 { 00235 if (e->blinkStatus() == TSTATUS_BEGIN) this->blinkSuppression(q, true); 00236 else if (e->blinkStatus() == TSTATUS_END) this->blinkSuppression(q, false); 00237 } 00238 } 00239 00240 // ###################################################################### 00241 void SaliencyMapAdapter:: 00242 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00243 { 00244 // get the OFS to save to, assuming sinfo is of type 00245 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00246 nub::ref<FrameOstream> ofs = dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs; 00247 00248 // get current membrane potentials: 00249 const Image<float> rawsm = this->getV(); 00250 00251 if (itsSaveResults.getVal()) 00252 // save un-normalized float images: 00253 ofs->writeFloat(rawsm, FLOAT_NORM_PRESERVE, "SM", FrameInfo("saliency map (bottom-up)", SRC_POS)); 00254 00255 if (itsSaveCumResults.getVal()) 00256 { 00257 // FIXME: this is hacky, probably we should accumulate itsCumMap 00258 // in doEvolve() instead of here... 00259 00260 if (itsCumMap.initialized()) 00261 const_cast<SaliencyMapAdapter*>(this)->itsCumMap += rawsm; 00262 else 00263 const_cast<SaliencyMapAdapter*>(this)->itsCumMap = rawsm; 00264 00265 ofs->writeFloat(itsCumMap, FLOAT_NORM_PRESERVE, "CUMSM", 00266 FrameInfo("cumulative saliency map", SRC_POS)); 00267 } 00268 } 00269 00270 // ###################################################################### 00271 // ###################################################################### 00272 // ########## SaliencyMapStd implementation 00273 // ###################################################################### 00274 // ###################################################################### 00275 00276 // ###################################################################### 00277 SaliencyMapStd::SaliencyMapStd(OptionManager& mgr, 00278 const std::string& descrName, 00279 const std::string& tagName) : 00280 SaliencyMapAdapter(mgr, descrName, tagName), 00281 SIMCALLBACK_INIT(SimEventClockTick), 00282 itsGinhDecay(&OPT_SMginhDecay, this), itsNeurons() 00283 { 00284 GVX_TRACE(__PRETTY_FUNCTION__); 00285 } 00286 00287 // ###################################################################### 00288 SaliencyMapStd::~SaliencyMapStd() 00289 { 00290 GVX_TRACE(__PRETTY_FUNCTION__); 00291 } 00292 00293 // ###################################################################### 00294 void SaliencyMapStd::input(SimEventQueue& q, const Image<float>& in) 00295 { 00296 // if this is our first, initialize our neurons: 00297 if (itsNeurons.initialized() == false) 00298 { 00299 itsNeurons.resize(in.getDims(), true); 00300 Image<LeakyIntegrator>::iterator 00301 nptr = itsNeurons.beginw(), stop = itsNeurons.endw(); 00302 const float decay = itsGinhDecay.getVal(); 00303 while(nptr != stop) (nptr++)->setGinhDecay(decay); 00304 } 00305 00306 // set every neuron's input: 00307 Image<LeakyIntegrator>::iterator nptr = itsNeurons.beginw(); 00308 Image<float>::const_iterator cptr = in.begin(), stop = in.end(); 00309 while (cptr != stop) (nptr++)->input(*cptr++); 00310 } 00311 00312 // ###################################################################### 00313 void SaliencyMapStd::depress(SimEventQueue& q, const Point2D<int>& winner, 00314 const double& pampl, const double& mampl, 00315 const double& psdev, const double& msdev) 00316 { 00317 GVX_TRACE(__PRETTY_FUNCTION__); 00318 Point2D<int> p; 00319 const int ww = itsNeurons.getWidth(); 00320 const int hh = itsNeurons.getHeight(); 00321 Image<LeakyIntegrator>::iterator src = itsNeurons.beginw(); 00322 00323 // open inhibitory conductances: 00324 for (p.j = 0; p.j < hh; p.j ++) 00325 for (p.i = 0; p.i < ww; p.i ++) 00326 (src++)->addGinh(float(iorHelper(winner, p, pampl, mampl, psdev, msdev))); 00327 00328 LDEBUG("Peak IOR conductance: %fmS", 00329 iorHelper(winner, winner, pampl, mampl, psdev, msdev) * 1000.0); 00330 } 00331 00332 // ###################################################################### 00333 void SaliencyMapStd::depress(SimEventQueue& q, const Point2D<int>& winner, const double& ampl, 00334 const Image<byte>& objectMask) 00335 { 00336 GVX_TRACE(__PRETTY_FUNCTION__); 00337 Point2D<int> p; 00338 const int ww = itsNeurons.getWidth(); 00339 const int hh = itsNeurons.getHeight(); 00340 Image<LeakyIntegrator>::iterator src = itsNeurons.beginw(); 00341 00342 // open inhibitory conductances: 00343 for (p.j = 0; p.j < hh; p.j ++) 00344 for (p.i = 0; p.i < ww; p.i ++) 00345 (src++)->addGinh(0.1F / 255.F * ampl * float(objectMask.getVal(p))); 00346 00347 LDEBUG("Peak IOR conductance: %fmS", 00348 0.1F / 255.F * ampl * float(objectMask.getVal(winner)) * 1000.0F); 00349 } 00350 00351 // ###################################################################### 00352 void SaliencyMapStd:: 00353 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& e) 00354 { 00355 // evolve our neurons one time step: 00356 Image<LeakyIntegrator>::iterator itr = itsNeurons.beginw(); 00357 Image<LeakyIntegrator>::iterator stop = itsNeurons.endw(); 00358 while (itr != stop) (itr++)->integrate(q.now()); 00359 00360 // post our current saliency map if we have one: 00361 const Image<float> sm = this->getV(); 00362 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, sm, itsLevelSpec.getVal().mapLevel()))); 00363 } 00364 00365 // ###################################################################### 00366 void SaliencyMapStd::saccadicSuppression(SimEventQueue& q, const bool on) 00367 { 00368 // we setup a weak inhibitory conductance for saccadic suppression 00369 // of the Saliency Map, as there is evidence that some 00370 // intra-saccadic visual input may still influence eye movements. 00371 const float inG = on ? 1.0e-6F : 0.0F; // inhibitory conductance in Siemens 00372 00373 // NOTE: this will erase any previous conductance pattern that may 00374 // have been present in the neurons, e.g., due to recent IORs. So it 00375 // is assumed here that IOR and saccadic suppression share the same 00376 // inhibitory mechanism. 00377 Image<LeakyIntegrator>::iterator src = itsNeurons.beginw(); 00378 Image<LeakyIntegrator>::iterator stop = itsNeurons.endw(); 00379 while(src != stop) (src++)->setGinh(inG); 00380 00381 LINFO("------- SaliencyMapStd saccadic suppression %s -------", on ? "on" : "off"); 00382 } 00383 00384 // ###################################################################### 00385 void SaliencyMapStd::blinkSuppression(SimEventQueue& q, const bool on) 00386 { 00387 // we setup a weak inhibitory conductance for blink suppression of 00388 // the Saliency Map, as the visual input should already have been 00389 // turned off by the Retina: 00390 const float inG = on ? 1.0e-6F : 0.0F; // inhibitory conductance in Siemens 00391 00392 // NOTE: this will erase any previous conductance pattern that may 00393 // have been present in the neurons, e.g., due to recent IORs. So it 00394 // is assumed here that IOR and saccadic suppression share the same 00395 // inhibitory mechanism. 00396 Image<LeakyIntegrator>::iterator src = itsNeurons.beginw(); 00397 Image<LeakyIntegrator>::iterator stop = itsNeurons.endw(); 00398 while(src != stop) (src++)->setGinh(inG); 00399 00400 LINFO("------- SaliencyMapStd blink suppression %s -------", on ? "on" : "off"); 00401 } 00402 00403 // ###################################################################### 00404 Image<float> SaliencyMapStd::getV() const 00405 { 00406 GVX_TRACE(__PRETTY_FUNCTION__); 00407 if (itsNeurons.initialized() == false) return Image<float>(); 00408 00409 Image<float> ret(itsNeurons.getDims(), NO_INIT); 00410 Image<float>::iterator dest = ret.beginw(); 00411 Image<LeakyIntegrator>::const_iterator src = itsNeurons.begin(); 00412 Image<LeakyIntegrator>::const_iterator stop = itsNeurons.end(); 00413 while (src != stop) *dest++ = (src++)->getV(); 00414 00415 return ret; 00416 } 00417 00418 // ###################################################################### 00419 float SaliencyMapStd::getV(const Point2D<int>& p) const 00420 { 00421 GVX_TRACE(__PRETTY_FUNCTION__); 00422 return itsNeurons.getVal(p).getV(); 00423 } 00424 00425 // ###################################################################### 00426 void SaliencyMapStd::reset1() 00427 { 00428 GVX_TRACE(__PRETTY_FUNCTION__); 00429 itsNeurons.freeMem(); 00430 } 00431 00432 00433 // ###################################################################### 00434 // ########## SaliencyMapTrivial implementation 00435 // ###################################################################### 00436 // ###################################################################### 00437 00438 // ###################################################################### 00439 SaliencyMapTrivial::SaliencyMapTrivial(OptionManager& mgr, 00440 const std::string& descrName, 00441 const std::string& tagName) : 00442 SaliencyMapAdapter(mgr, descrName, tagName), 00443 itsItoVcoeff(&OPT_SMItoVcoeff, this), 00444 itsNeurons() 00445 { 00446 GVX_TRACE(__PRETTY_FUNCTION__); 00447 } 00448 00449 // ###################################################################### 00450 SaliencyMapTrivial::~SaliencyMapTrivial() 00451 { 00452 GVX_TRACE(__PRETTY_FUNCTION__); 00453 } 00454 00455 // ###################################################################### 00456 void SaliencyMapTrivial::reset1() 00457 { 00458 GVX_TRACE(__PRETTY_FUNCTION__); 00459 itsNeurons.freeMem(); 00460 } 00461 00462 // ###################################################################### 00463 void SaliencyMapTrivial::input(SimEventQueue& q, const Image<float>& current) 00464 { 00465 GVX_TRACE(__PRETTY_FUNCTION__); 00466 itsNeurons = current * itsItoVcoeff.getVal(); 00467 00468 // post our current saliency map if we have one: 00469 if (itsNeurons.initialized()) 00470 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00471 } 00472 00473 // ###################################################################### 00474 void SaliencyMapTrivial::depress(SimEventQueue& q, const Point2D<int>& winner, 00475 const double& pampl, const double& mampl, 00476 const double& psdev, const double& msdev) 00477 { 00478 GVX_TRACE(__PRETTY_FUNCTION__); 00479 Point2D<int> p; 00480 const int ww = itsNeurons.getWidth(); 00481 const int hh = itsNeurons.getHeight(); 00482 Image<float>::iterator src = itsNeurons.beginw(); 00483 00484 // open inhibitory conductances: 00485 for (p.j = 0; p.j < hh; p.j ++) 00486 for (p.i = 0; p.i < ww; p.i ++) 00487 { 00488 *src -= float(iorHelper(winner, p, pampl, mampl, psdev, msdev)); 00489 if (*src < 0.0F) *src = 0.0F; 00490 ++ src; 00491 } 00492 00493 LDEBUG("Peak IOR conductance: %fmS", 00494 float(iorHelper(winner, winner, pampl, mampl, psdev, msdev)) * 1000.0F); 00495 00496 // post our current saliency map if we have one: 00497 if (itsNeurons.initialized()) 00498 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00499 } 00500 00501 // ###################################################################### 00502 void SaliencyMapTrivial::depress(SimEventQueue& q, const Point2D<int>& winner, const double& ampl, 00503 const Image<byte>& objectMask) 00504 { 00505 GVX_TRACE(__PRETTY_FUNCTION__); 00506 Image<float> inhib = objectMask * (ampl / 255.0F); 00507 itsNeurons -= inhib; // subtract inhib for current saliency values 00508 inplaceRectify(itsNeurons); // remove possible negative values 00509 00510 // post our current saliency map if we have one: 00511 if (itsNeurons.initialized()) 00512 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00513 } 00514 00515 // ###################################################################### 00516 void SaliencyMapTrivial::saccadicSuppression(SimEventQueue& q, const bool on) 00517 { 00518 GVX_TRACE(__PRETTY_FUNCTION__); 00519 // we setup a weak inhibitory conductance for saccadic suppression 00520 // of the Saliency Map, as there is evidence that some intra-saccadic visual 00521 // input may still influence eye movements. 00522 if (on) itsNeurons -= 1.0e-6F; 00523 LINFO("------- SaliencyMapTrivial saccadic suppression %s -------", on ? "on":"off"); 00524 00525 // post our current saliency map if we have one: 00526 if (itsNeurons.initialized()) 00527 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00528 } 00529 00530 // ###################################################################### 00531 void SaliencyMapTrivial::blinkSuppression(SimEventQueue& q, const bool on) 00532 { 00533 GVX_TRACE(__PRETTY_FUNCTION__); 00534 // we setup a weak inhibitory conductance for blink suppression of 00535 // the Saliency Map, as the visual input should also be turned off 00536 // in Brain 00537 if (on) itsNeurons -= 1.0e-6F; 00538 LINFO("------- SaliencyMapTrivial blink suppression %s -------", on ? "on":"off"); 00539 00540 // post our current saliency map if we have one: 00541 if (itsNeurons.initialized()) 00542 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00543 } 00544 00545 // ###################################################################### 00546 Image<float> SaliencyMapTrivial::getV() const 00547 { 00548 GVX_TRACE(__PRETTY_FUNCTION__); 00549 return itsNeurons; 00550 } 00551 00552 // ###################################################################### 00553 float SaliencyMapTrivial::getV(const Point2D<int>& p) const 00554 { 00555 GVX_TRACE(__PRETTY_FUNCTION__); 00556 return itsNeurons.getVal(p); 00557 } 00558 00559 // ###################################################################### 00560 // ###################################################################### 00561 // ########## SaliencyMapFast implementation 00562 // ###################################################################### 00563 // ###################################################################### 00564 00565 // ###################################################################### 00566 SaliencyMapFast::SaliencyMapFast(OptionManager& mgr, 00567 const std::string& descrName, 00568 const std::string& tagName) : 00569 SaliencyMapAdapter(mgr, descrName, tagName), 00570 itsTimeStep(&OPT_SimulationTimeStep, this), // see Neuro/NeuroOpts.{H,C} 00571 itsInputCoeff(&OPT_SMfastInputCoeff, this), // ModelOptionDefs.C 00572 itsItoVcoeff(&OPT_SMItoVcoeff, this), // idem 00573 itsNeurons(), itsInputCopy(), itsT() 00574 { 00575 GVX_TRACE(__PRETTY_FUNCTION__); 00576 } 00577 00578 // ###################################################################### 00579 SaliencyMapFast::~SaliencyMapFast() 00580 { 00581 GVX_TRACE(__PRETTY_FUNCTION__); 00582 } 00583 00584 // ###################################################################### 00585 void SaliencyMapFast::reset1() 00586 { 00587 GVX_TRACE(__PRETTY_FUNCTION__); 00588 itsNeurons.freeMem(); itsT = SimTime::ZERO(); 00589 } 00590 00591 // ###################################################################### 00592 void SaliencyMapFast::input(SimEventQueue& q, const Image<float>& current) 00593 { 00594 GVX_TRACE(__PRETTY_FUNCTION__); 00595 00596 // make sure we are up to date: 00597 integrate(q); 00598 00599 // get the new inputs: 00600 itsInputCopy = current * itsItoVcoeff.getVal(); 00601 itsNeurons = itsInputCopy; 00602 00603 // post current map: 00604 // post our current saliency map if we have one: 00605 if (itsNeurons.initialized()) 00606 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00607 } 00608 00609 // ###################################################################### 00610 void SaliencyMapFast::depress(SimEventQueue& q, const Point2D<int>& winner, 00611 const double& pampl, const double& mampl, 00612 const double& psdev, const double& msdev) 00613 { 00614 GVX_TRACE(__PRETTY_FUNCTION__); 00615 00616 // make sure we are up to date: 00617 integrate(q); 00618 00619 Point2D<int> p; 00620 const int ww = itsNeurons.getWidth(); 00621 const int hh = itsNeurons.getHeight(); 00622 Image<float>::iterator src = itsNeurons.beginw(); 00623 00624 // open inhibitory conductances: 00625 for (p.j = 0; p.j < hh; p.j ++) 00626 for (p.i = 0; p.i < ww; p.i ++) 00627 { 00628 *src -= float(iorHelper(winner, p, pampl*30, mampl, psdev, msdev)); 00629 if (*src < 0.0F) *src = 0.0F; 00630 ++ src; 00631 } 00632 00633 LDEBUG("Peak IOR conductance: %fmS", 00634 float(iorHelper(winner, winner, pampl*30, mampl, psdev, msdev)) * 1000.0F); 00635 00636 // post our current saliency map if we have one: 00637 if (itsNeurons.initialized()) 00638 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00639 } 00640 00641 // ###################################################################### 00642 void SaliencyMapFast::depress(SimEventQueue& q, const Point2D<int>& winner, const double& ampl, 00643 const Image<byte>& objectMask) 00644 { 00645 GVX_TRACE(__PRETTY_FUNCTION__); 00646 // make sure we are up to date: 00647 integrate(q); 00648 00649 Image<float> inhib = objectMask * (ampl / 255.0F); 00650 itsNeurons -= inhib; // subtract inhib for current saliency values 00651 inplaceRectify(itsNeurons); // remove possible negative values 00652 00653 // post our current saliency map if we have one: 00654 if (itsNeurons.initialized()) 00655 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00656 } 00657 00658 // ###################################################################### 00659 void SaliencyMapFast::integrate(SimEventQueue& q) 00660 { 00661 GVX_TRACE(__PRETTY_FUNCTION__); 00662 double nsteps = (q.now() - itsT).secs() / itsTimeStep.getVal().secs(); 00663 if (nsteps >= 1.0 && itsInputCoeff.getVal() < 1) // If we need to merge with old ones 00664 { 00665 float c1 = pow(itsInputCoeff.getVal(), nsteps), c2 = 1.0F - c1; 00666 itsNeurons *= c1; 00667 inplaceAddWeighted(itsNeurons, itsInputCopy, c2); 00668 } 00669 itsT = q.now(); 00670 } 00671 00672 // ###################################################################### 00673 void SaliencyMapFast::saccadicSuppression(SimEventQueue& q, const bool on) 00674 { 00675 GVX_TRACE(__PRETTY_FUNCTION__); 00676 // make sure we are up to date: 00677 integrate(q); 00678 00679 // we setup a weak inhibitory conductance for saccadic suppression 00680 // of the Saliency Map, as there is evidence that some intra-saccadic visual 00681 // input may still influence eye movements. 00682 if (on) itsNeurons -= 1.0e-6F; 00683 LINFO("------- SaliencyMapFast saccadic suppression %s -------", on ? "on":"off"); 00684 00685 // post our current saliency map if we have one: 00686 if (itsNeurons.initialized()) 00687 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00688 } 00689 00690 // ###################################################################### 00691 void SaliencyMapFast::blinkSuppression(SimEventQueue& q, const bool on) 00692 { 00693 GVX_TRACE(__PRETTY_FUNCTION__); 00694 // make sure we are up to date: 00695 integrate(q); 00696 00697 // we setup a weak inhibitory conductance for blink suppression of 00698 // the Saliency Map, as the visual input should also be turned off 00699 // in Brain 00700 if (on) itsNeurons -= 1.0e-6F; 00701 LINFO("------- SaliencyMapFast blink suppression %s -------", on ? "on":"off"); 00702 00703 // post our current saliency map if we have one: 00704 if (itsNeurons.initialized()) 00705 q.post(rutz::make_shared(new SimEventSaliencyMapOutput(this, itsNeurons, itsLevelSpec.getVal().mapLevel()))); 00706 } 00707 00708 // ###################################################################### 00709 Image<float> SaliencyMapFast::getV() const 00710 { 00711 GVX_TRACE(__PRETTY_FUNCTION__); 00712 return itsNeurons; 00713 } 00714 00715 // ###################################################################### 00716 float SaliencyMapFast::getV(const Point2D<int>& p) const 00717 { 00718 GVX_TRACE(__PRETTY_FUNCTION__); 00719 return itsNeurons.getVal(p); 00720 } 00721 00722 // ###################################################################### 00723 /* So things look consistent in everyone's emacs... */ 00724 /* Local Variables: */ 00725 /* indent-tabs-mode: nil */ 00726 /* End: */