SaccadeController.C

Go to the documentation of this file.
00001 /*!@file Neuro/SaccadeController.C 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.C $
00035 // $Id: SaccadeController.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 #include "Neuro/SaccadeController.H"
00039 
00040 #include "Simulation/SimEventQueue.H"
00041 #include "Neuro/NeuroOpts.H"
00042 #include "Neuro/NeuroSimEvents.H"
00043 #include "Util/log.H"
00044 #include "Util/sformat.H"
00045 
00046 // ######################################################################
00047 SaccadeController::SaccadeController(OptionManager& mgr,
00048                                      const std::string& descrName,
00049                                      const std::string& tagName,
00050                                      const SaccadeBodyPart bodypart,
00051                                      const int percept_qlen,
00052                                      const int decision_qlen) :
00053   SimModule(mgr, std::string(saccadeBodyPartName(bodypart)) +
00054             std::string(" ") + descrName,
00055             std::string(saccadeBodyPartName(bodypart)) + tagName),
00056   itsInitialPosition(bodypart == SaccadeBodyPartEye
00057                      ? &OPT_SCeyeInitialPosition
00058                      : &OPT_SCheadInitialPosition, this),
00059   percept(), decision(), pqlen(percept_qlen), dqlen(decision_qlen),
00060   itsState(SACSTATE_UNK), itsPrevState(SACSTATE_UNK),
00061   itsBlinkState(false), itsPrevBlinkState(false),
00062   itsBodyPart(bodypart)
00063 {
00064   if (pqlen < 2 || dqlen < 2)
00065     LFATAL("Queue lengths must be at least 2 for proper operation.");
00066 }
00067 
00068 // ######################################################################
00069 SaccadeController::~SaccadeController()
00070 {  }
00071 
00072 // ######################################################################
00073 void SaccadeController::reset1()
00074 {
00075   // reset some stuff for SaccadeController
00076   percept.clear();          decision.clear();
00077   itsState = SACSTATE_UNK;  itsPrevState = SACSTATE_UNK;
00078   itsBlinkState = false;    itsPrevBlinkState = false;
00079 
00080   // propagate to our base class:
00081   SimModule::reset1();
00082 }
00083 
00084 // ######################################################################
00085 void SaccadeController::setPercept(const WTAwinner& fix, SimEventQueue& q)
00086 {
00087   // push new percept to front of percept queue:
00088   percept.push_front(fix);
00089 
00090   // truncate percept queue if necessary:
00091   while(percept.size() > pqlen) percept.pop_back();
00092 
00093   // do some processing:
00094   computeWhenNewPercept(q);
00095 }
00096 
00097 // ######################################################################
00098 void SaccadeController::resetPos(const Point2D<int>& p, SimEventQueue& q)
00099 {
00100   // push new percept to front of percept queue:
00101   const WTAwinner win(p, q.now(), 0.0, false);
00102   percept.push_front(win);
00103 
00104   // truncate percept queue if necessary:
00105   while(percept.size() > pqlen) percept.pop_back();
00106 
00107   // do some processing:
00108   computeWhenResetPos(q);
00109 
00110   // If the reset location is valid, then we are in fixation,
00111   // otherwise we are in unknown state:
00112   if (p.isValid()) itsState = SACSTATE_FIX;
00113   else itsState = SACSTATE_UNK;
00114 
00115   // also always abort any blink:
00116   itsBlinkState = false;
00117 
00118   CLDEBUG("### State reset to [%s] (%d,%d) %.1fms ###",
00119           saccadeStateName(itsState), p.i, p.j, q.now().msecs());
00120   CLDEBUG("## Blink state reset to [Not-Blinking] (%d,%d) %.1fms ##",
00121           p.i, p.j, q.now().msecs());
00122 }
00123 
00124 // ######################################################################
00125 Point2D<int> SaccadeController::getDecision(SimEventQueue& q,
00126                                        const bool dopoststatus)
00127 {
00128   // if we have no percepts yet, we may want to push an initial
00129   // position in depending on command-line option:
00130   if (percept.empty() && q.now() == SimTime::ZERO())
00131     {
00132       const Point2D<int> p = itsInitialPosition.getVal();
00133       if (p.i == -2 && p.j == -2)
00134         {
00135           // we want to start at center; get the latest input frame to
00136           // figure oput where the center is:
00137           if (SeC<SimEventRetinaImage> e =
00138               q.check<SimEventRetinaImage>(this, SEQ_ANY))
00139             {
00140               const Point2D<int> c = e->center();
00141               resetPos(c, q);
00142               CLINFO("Starting %s at centered initial position (%d, %d).",
00143                      saccadeBodyPartName(itsBodyPart), c.i, c.j);
00144             }
00145           else
00146             CLFATAL("ooops, cannot find a retina image to get its center?");
00147         }
00148       else if (p.isValid())
00149         {
00150           // we want to start at a specified position:
00151           resetPos(p, q);
00152           CLINFO("Starting %s at specified initial position (%d, %d).",
00153                  saccadeBodyPartName(itsBodyPart), p.i, p.j);
00154         }
00155       else
00156         CLINFO("Starting %s at unspecified initial position.",
00157                saccadeBodyPartName(itsBodyPart));
00158     }
00159 
00160   // do some computation and push a new decision into decision queue,
00161   // if the new decision is different from the last one pushed into
00162   // the queue. This is also where we update our saccade and blink
00163   // state information:
00164   Point2D<int> last(-1, -1);
00165   if (decision.size()) last = decision.front().p;
00166   Point2D<int> loc = computeWhenNewDecision(itsState, itsBlinkState, q);
00167   bool nochange = (loc == last);
00168   if (loc.isValid() && nochange == false)
00169     decision.push_front(Point2DT(loc, q.now()));
00170 
00171   // truncate decision queue as necessary:
00172   while(decision.size() > dqlen) decision.pop_back();
00173 
00174   // display a few messages whenever we have a state change:
00175   if (itsState != itsPrevState)
00176     CLDEBUG("### State change [%s -> %s] at (%d,%d) %.1fms ###",
00177             saccadeStateName(itsPrevState), saccadeStateName(itsState),
00178             loc.i, loc.j, q.now().msecs());
00179   if (itsBlinkState != itsPrevBlinkState)
00180     CLDEBUG("## Blink state change [%s -> %s] at (%d,%d) %.1fms ##",
00181             itsPrevBlinkState ? "Blinking" : "Not-Blinking",
00182             itsBlinkState ? "Blinking" : "Not-Blinking",
00183             loc.i, loc.j, q.now().msecs());
00184 
00185   // post our status to the SimEventQueue?
00186   if (dopoststatus)
00187     {
00188       if (itsBodyPart == SaccadeBodyPartEye)
00189         {
00190           rutz::shared_ptr<SimEventSaccadeStatusEye>
00191             s(new SimEventSaccadeStatusEye(this, getPreviousDecision(0).p,
00192                                            itsState, itsPrevState,
00193                                            itsBlinkState, itsPrevBlinkState));
00194           q.post(s);
00195         }
00196       else
00197         {
00198           rutz::shared_ptr<SimEventSaccadeStatusHead>
00199             s(new SimEventSaccadeStatusHead(this, getPreviousDecision(0).p,
00200                                             itsState, itsPrevState,
00201                                             itsBlinkState, itsPrevBlinkState));
00202           q.post(s);
00203         }
00204     }
00205 
00206   // return current decision or (-1, -1) if no change since last time:
00207   if (nochange) return Point2D<int>(-1, -1); else return loc;
00208 }
00209 
00210 // ######################################################################
00211 void SaccadeController::dumpQueues() const
00212 {
00213   std::string ptxt, dtxt;
00214   for (unsigned int i = 0; i < percept.size(); i ++) {
00215     WTAwinner win = percept[i];
00216     ptxt += sformat("[(%d, %d) %.2fms %.2fmV] ", win.p.i, win.p.j,
00217                     win.t.msecs(), win.sv * 1000.0);
00218   }
00219   CLINFO("PERCEPT:  %s", ptxt.c_str());
00220   for (unsigned int i = 0; i < decision.size(); i ++) {
00221     Point2DT pt = decision[i];
00222     dtxt += sformat("[(%d, %d) %.2fms] ", pt.p.i, pt.p.j, pt.t.msecs());
00223   }
00224   CLINFO("DECISION: %s", dtxt.c_str());
00225 }
00226 
00227 // ######################################################################
00228 WTAwinner SaccadeController::getPreviousPercept(const unsigned int
00229                                                 index) const
00230 {
00231   if (percept.size() > index) return percept[index];
00232   else return WTAwinner::NONE();
00233 }
00234 
00235 // ######################################################################
00236 bool SaccadeController::havePercepts() const
00237 { return !(percept.empty()); }
00238 
00239 // ######################################################################
00240 int SaccadeController::getPqlen() const
00241 { return pqlen; }
00242 
00243 // ######################################################################
00244 void SaccadeController::resetPqlen(const int len)
00245 { percept.clear(); pqlen = len; }
00246 
00247 // ######################################################################
00248 void SaccadeController::killPercepts()
00249 { while(percept.size()) percept.pop_front(); }
00250 
00251 // ######################################################################
00252 Point2DT SaccadeController::getPreviousDecision(const unsigned int
00253                                                 index) const
00254 {
00255   if (decision.size() > index) return decision[index];
00256   else return Point2DT(-1, -1, SimTime::ZERO());
00257 }
00258 
00259 // ######################################################################
00260 bool SaccadeController::haveDecisions() const
00261 { return !(decision.empty()); }
00262 
00263 // ######################################################################
00264 int SaccadeController::getDqlen() const
00265 { return dqlen; }
00266 
00267 // ######################################################################
00268 void SaccadeController::resetDqlen(const int len)
00269 { decision.clear(); dqlen = len; }
00270 
00271 // ######################################################################
00272 void SaccadeController::killDecisions()
00273 { while(decision.size()) decision.pop_front(); }
00274 
00275 // ######################################################################
00276 SaccadeBodyPart SaccadeController::bodyPart() const
00277 { return itsBodyPart; }
00278 
00279 // ######################################################################
00280 void SaccadeController::evolve(SimEventQueue& q)
00281 {
00282   // keep track of our status from the last cycle:
00283   itsPrevState = itsState;
00284   itsPrevBlinkState = itsBlinkState;
00285 
00286   // call the virtual function that will be implemented by derived classes:
00287   this->doEvolve(q);
00288 }
00289 
00290 // ######################################################################
00291 SaccadeState SaccadeController::getState() const
00292 { return itsState; }
00293 
00294 // ######################################################################
00295 bool SaccadeController::getBlinkState() const
00296 { return itsBlinkState; }
00297 
00298 
00299 // ######################################################################
00300 /* So things look consistent in everyone's emacs... */
00301 /* Local Variables: */
00302 /* indent-tabs-mode: nil */
00303 /* End: */
Generated on Sun May 8 08:41:03 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3