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: */