00001 /*!@file Neuro/SaccadeController.H Base class for saccade generation */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 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: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/SaccadeController.H $ 00035 // $Id: SaccadeController.H 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #ifndef SACCADECONTROLLER_H_DEFINED 00039 #define SACCADECONTROLLER_H_DEFINED 00040 00041 #include "Component/ModelComponent.H" 00042 #include "Component/ModelParam.H" 00043 #include "Image/Point2DT.H" 00044 #include "Neuro/WTAwinner.H" 00045 #include "Neuro/SaccadeBodyPart.H" 00046 #include "Psycho/SaccadeState.H" 00047 #include "Simulation/SimModule.H" 00048 #include "Util/TransientStatus.H" 00049 #include <deque> 00050 00051 //! A base class to implement saccade controllers 00052 /*! This base class handles the basic queuing of percepts and 00053 fixations. Typically, new percepts (e.g., winner-take-all winners over 00054 the saliency map) should be passed to the saccade controller using 00055 setPercept(). During normal evolution of a simulation, evolve() should 00056 be called at every time step, in a manner similar to that of Brain, 00057 WTA and SM. In order to obtain coordinates of saccade targets computed 00058 by this class, getDecision() should be called. It will return (-1, -1) 00059 if no new saccade target is decided (either because it cannot be 00060 decided, or because it is the same as the last valid returned 00061 one). So, saccading to and fixating a new target will yield one 00062 initial valid set of returned coordinates, followed by subsequent 00063 returns of (-1, -1) as long as fixation is to be held 00064 stationary. Derived classes should overload computeWhenNewPercept(), 00065 called each time a new percept has arrived, and 00066 computeWhenNewDecision(), called each time a new decision is 00067 requested. In addition, derived classes should usually overload 00068 doEvolve(), typically called at each time step during a simulation. 00069 See SaccadeControllers.H for examples of derived classes which 00070 actually implement saccadic control strategies. */ 00071 00072 class SaccadeController : public SimModule 00073 { 00074 public: 00075 //! Constructor 00076 /*! @param bodypart should be SaccadeBodyPartEye or SaccadeBodyPartHead 00077 @param percept_qlen length of the queue of accumulated percepts 00078 @param decision_qlen length of the queue of generated decisions */ 00079 SaccadeController(OptionManager& mgr, 00080 const std::string& descrName, 00081 const std::string& tagName, 00082 const SaccadeBodyPart bodypart, 00083 const int percept_qlen, 00084 const int decision_qlen); 00085 00086 //! Destructor (virtual to ensure that derived classes correctly destroyed) 00087 virtual ~SaccadeController(); 00088 00089 //! evolve one time step (called, e.g., by Brain::evolve()) 00090 /*! evolve() should be invoked by external callers to allow the 00091 internals of the controller to evolve as time passes by but no 00092 new percept is available. Derived classes should not override 00093 this function, but should instead override doEvolve(), which is 00094 called from inside evolve(). */ 00095 void evolve(SimEventQueue& q); 00096 00097 //! Receive a new percept (e.g., winner from saliency map) 00098 /*! This method should be invoked by external callers each time a 00099 new percept is available. Do not overload this method, overload 00100 computeWhenNewPercept() instead if you need to perform some 00101 computation for each new percept. */ 00102 virtual void setPercept(const WTAwinner& fix, SimEventQueue& q); 00103 00104 //! Reset to an externally-given position 00105 /*! This will force the current position to the position given as 00106 argument, disregarding any internal physical model. So this may be 00107 used to externally drive the SaccadeController to given 00108 locations. A percept will be queued up, which will be built from 00109 the passed position/time plus default values for the WTAwinner 00110 fields. Do not overload this method, overload computeWhenReset() 00111 instead. NOTE: this will abort any current blink and will reset 00112 our internal state to fixation (if p is valid) or unknown (if p is 00113 invalid). */ 00114 virtual void resetPos(const Point2D<int>& p, SimEventQueue& q); 00115 00116 //! Get the fixation decided by the controller 00117 /*! @param t should be the current time (in seconds) and should be 00118 greater than or equal to the time of the last percept passed to 00119 setPercept(). The coordinates of the decided fixation are returned 00120 (or (-1, -1) of no decision has been made). If a decision is made 00121 but is the same as the previous one, the behavior here is to 00122 return (-1, -1), and the caller has the responsibility of holding 00123 fixation until a new, valid decision can be reached. Do not 00124 overload this method, overload computeWhenNewDecision() instead if 00125 you need to do some computation before returning a fixation. If 00126 dopoststatus is true, we will post a SimEventStatus[Eye|Head] with 00127 our current status to the SimEventQueue. */ 00128 virtual Point2D<int> getDecision(SimEventQueue& q, 00129 const bool dopoststatus = false); 00130 00131 //! Get a previous percept 00132 /*! This method allows one to access a previous percept passed 00133 through setPercept(), or (-1, -1) if no valid previous percept 00134 exists. 00135 @param index indicates which previous percept; a value of zero 00136 will return the last percept that was passed to setPercept(), and 00137 increasing values will return increasingly older percepts. If 00138 index is more than the queue length, (-1, -1) will be returned. */ 00139 WTAwinner getPreviousPercept(const unsigned int index = 0) const; 00140 00141 //! Do we already have any percepts queued up? 00142 bool havePercepts() const; 00143 00144 //! Returns length of percept queue 00145 /*! Note that the queue may not be full to that length yet */ 00146 int getPqlen() const; 00147 00148 //! Reset length of percept queue (contents will be lost) 00149 void resetPqlen(const int len); 00150 00151 //! Kill all previous percepts (empty the percept queue) 00152 void killPercepts(); 00153 00154 //! Get a previous decision 00155 /*! This method allows one to access a previous valid decision. It 00156 will not attempt to determine whether a new decision can be made 00157 now, like getDecision() does. It will simply return the result of 00158 what was previously decided (or (-1, -1) if no valid previous 00159 decision exists). 00160 @param index indicates which previous decision; a value of zero 00161 will return the last decision that was made and returned by 00162 getDecision(), and increasing values will return increasingly 00163 older decisions. if index is more than the queue length, (-1, -1) 00164 will be returned. */ 00165 Point2DT getPreviousDecision(const unsigned int index = 0) const; 00166 00167 //! Do we already have any decisions queued up? 00168 bool haveDecisions() const; 00169 00170 //! Returns length of decision queue 00171 /*! Note that the queue may not be full to that length yet */ 00172 int getDqlen() const; 00173 00174 //! Reset length of decision queue (contents will be lost) 00175 void resetDqlen(const int len); 00176 00177 //! Kill all previous decisions (empty the decision queue) 00178 void killDecisions(); 00179 00180 //! get our body part 00181 SaccadeBodyPart bodyPart() const; 00182 00183 //! Show contents of the queues, for debugging 00184 void dumpQueues() const; 00185 00186 protected: 00187 OModelParam<Point2D<int> > itsInitialPosition; //!< start position 00188 00189 //! Reset SaccadeController 00190 virtual void reset1(); 00191 00192 //! Called from within evolve() 00193 /*! Classes deriving from SaccadeController should implement this. */ 00194 virtual void doEvolve(SimEventQueue& q) = 0; 00195 00196 //! This method is called each time a new percept has arrived 00197 /*! The latest percept is at the front of the percept queue. Derived 00198 classes must provide some implementation for this method, as it is 00199 called from within setPercept(). */ 00200 virtual void computeWhenNewPercept(SimEventQueue& q) = 0; 00201 00202 //! This method is called each time a reset() occurs 00203 /*! The reset location/time is at the front of the percept 00204 queue. Derived classes must provide some implementation for this 00205 method, as it is called from within resetPos(). NOTE: a 00206 resetPos(), even if it is to a location far away from the current 00207 one, should not create a saccade, because it is a way to break a 00208 simulation and reset it, not a way to drive saccades 00209 externally. Saccades should arise internally in 00210 computeWhenNewDecision(). You should not change the state here as 00211 resetPos() itself will change if to fixation or unknown anyway. */ 00212 virtual void computeWhenResetPos(SimEventQueue& q) = 0; 00213 00214 //! This method is called each time a new decision is requested 00215 /*! The latest percept is at the front of the percept queue, and the 00216 latest previous decision at the front of the decision queue. The 00217 method should return the decision to be taken given the time 00218 passed as argument. This method should return the current decision 00219 for fixation, as well as current saccade and blink states. The 00220 wrapping getDecision() call will take care of eliminating 00221 decisions that are the same as the previous ones. Derived classes 00222 must provide some implementation for this method, as it is called 00223 from within getDecision(). */ 00224 virtual Point2D<int> computeWhenNewDecision(SaccadeState& sacstate, 00225 bool& blinkstate, 00226 SimEventQueue& q) = 0; 00227 00228 //! Helper for derived classes to get our internal saccade/fix/smooth state 00229 SaccadeState getState() const; 00230 00231 //! Helper for derived classes to get our internal blink state 00232 bool getBlinkState() const; 00233 00234 private: 00235 std::deque<WTAwinner> percept; // queue of accumulated percepts; front=latest 00236 std::deque<Point2DT> decision; // queue of accumulated decisions;front=latest 00237 unsigned int pqlen, dqlen; // size of percept & decisioon queues 00238 SaccadeState itsState; // our saccade/fix/smooth/etc state 00239 SaccadeState itsPrevState; // state before last evolve() 00240 bool itsBlinkState; // blink state 00241 bool itsPrevBlinkState; // previous blink state 00242 SaccadeBodyPart itsBodyPart; // are we eye or head? 00243 }; 00244 00245 // ###################################################################### 00246 /* So things look consistent in everyone's emacs... */ 00247 /* Local Variables: */ 00248 /* indent-tabs-mode: nil */ 00249 /* End: */ 00250 #endif