EyeData.H

Go to the documentation of this file.
00001 /*!@file Psycho/EyeData.H Struct for eye-tracker data with a wrapped ParamMap */
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: John Shen <shenjohn@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Psycho/EyeData.H $
00035 //
00036 
00037 #ifndef PSYCHO_EYEDATA_H_DEFINED
00038 #define PSYCHO_EYEDATA_H_DEFINED
00039 
00040 #include "Image/Point2D.H"
00041 #include "Psycho/SaccadeState.H"
00042 #include "Util/Types.H"
00043 #include "Util/StringUtil.H"
00044 #include "Util/log.H"
00045 #include "rutz/compat_cmath.h" // for isnan()
00046 #include "rutz/shared_ptr.h"
00047 #include "Component/ParamMap.H"
00048 #include <cmath>
00049 
00050 //! Simple struct for eye-tracker data
00051 /*! Different eye trackers may or may not fill all data
00052   members. Members that should always be filled are x and y. Note that
00053   this class is costly in terms of storage, so typically one would
00054   want to use it only to pass data samples around, but not to store a
00055   long series of samples in memory. For example, Psycho/EyeTrace.H
00056   uses a more compact format to internally store eye data, and uses
00057   EyeData objects to deliver that data to whoever wants it. */
00058 class EyeData 
00059 {
00060 public:
00061   //! Fully initialized constructor, no extra data
00062   inline EyeData(const float x_, const float y_, const float pdiam_,
00063                  const SaccadeState sstate_, const bool bstate_);
00064 
00065   //! Fully initialized constructor, extra data in ParamMap
00066   inline EyeData(const float x_, const float y_, const float pdiam_,
00067                          const SaccadeState sstate_, const bool bstate_,
00068                          rutz::shared_ptr<ParamMap> dat);
00069   
00070   // initialized constructor, extra data
00071   inline EyeData(const float x_, const float y_, const float pdiam_,
00072                         const SaccadeState sstate_, const bool bstate_,
00073                         const float dx_, const float dy_, const float ampl_,
00074                         const float dur_, const float time_,
00075                        const unsigned int num_); 
00076 
00077   //  inline EyeData(const float x_, const float y_, const float pdiam_,
00078   //             const SaccadeState sstate_, const bool bstate_,
00079   //     rutz::shared_ptr<ParamMap> dat);
00080 
00081   //  inline EyeData(rutz::shared_ptr<ParamMap> dat);
00082   // inline EyeData(std::map<std::string, float> dat);
00083 
00084   inline ~EyeData();
00085 
00086   //@}
00087   // ######################################################################
00088   /*! @name Helper functions */
00089   //@{
00090 
00091  //! Are we in unknown state (uninitialized, loss of tracking, etc)
00092   inline bool isInUnknown() const;
00093 
00094   //! Are we in fixation?
00095   inline bool isInFixation() const;
00096 
00097   //! Are we in saccade?
00098   inline bool isInSaccade() const;
00099 
00100   //! Are we in smooth pursuit?
00101   inline bool isInSmoothPursuit() const;
00102 
00103   //! Are we in blink?
00104   inline bool isInBlink() const;
00105 
00106   //! Are we in a series of combined saccades
00107   inline bool isInCombinedSaccade() const;
00108 
00109   //! Get the saccade state directly
00110   inline SaccadeState saccadeState() const;
00111 
00112   //! Do we have valid pupil diameter data?
00113   inline bool hasPupilDiam() const;
00114 
00115   //! Do we have valid extra metadata?
00116   /*! Only a very few samples in an eye trace have this extra data,
00117     possibly none. The data may be present at the onset of each
00118     event and contains information about each event. */
00119   inline bool hasMetaData(const std::string field) const;
00120 
00121   inline bool hasSpecialMetaData(const std::string field) const;
00122 
00123   //! Do we have valid extra saccade target data?
00124   /*! Only a very few samples in an eye trace have this extra data,
00125     possibly none. The data may be present at the onset of each
00126     saccade and contains information about the target of the saccade. */
00127   //!NB: This is rewritten now for any sample that has extra data,
00128   // not just saccades. 
00129   inline bool hasSaccadeTargetData() const;
00130 
00131   //! Do we have valid (x,y) coordinates?
00132   inline bool isValid() const;
00133 
00134   //! Are our coordinates within some dims?
00135   inline bool isWithin(const Dims& dims) const;
00136 
00137   //! Is this field name a special field?
00138   inline bool isSpecialField(std::string field) const;
00139 
00140   //@}
00141 
00142   // ######################################################################
00143   /*! @name Access functions */
00144   //@{
00145 
00146   //! Get eye position, not rounded
00147   inline void getPosition(float& xx, float& yy) const;
00148 
00149   //! Get eye position, rounded to nearest int coordinates
00150   inline Point2D<int> position() const;
00151 
00152   //! Get pupil diameter
00153   /*! Note that this may be a NaN or other trash if there is no
00154     available data about pupil diameter, check with hasPupilDiameter()
00155     before if you want to ensure that you get a valid number. */
00156   inline float pupilDiameter() const;
00157 
00158   //! Get all metadata
00159   inline rutz::shared_ptr<ParamMap> getMetaData() const;
00160   
00161   //! Get list of metadata fields
00162   inline std::vector<std::string> getMetaDataList() const;
00163 
00164   //! Get one field of metadata
00165   inline double getMetaDataField(std::string field) const;
00166 
00167   //! Get saccade target, not rounded
00168   /*! Note that this will contain trash if there is no saccade target
00169     data. Check with hasMetaData() first to avoid this. */
00170   inline void getSaccadeTarget(float& targx, float& targy) const;
00171 
00172   //! Get rounded saccade target
00173   /*! Note that this will contain trash if there is no saccade target
00174     data. Check with hasMetaData() first to avoid this. */
00175   inline Point2D<int> saccadeTarget() const;
00176 
00177   //! Get saccade amplitude
00178   /*! Note that this will contain trash if there is no saccade target
00179     data. Check with hasMetaData() first to avoid this. */
00180   inline float saccadeAmplitude() const;
00181 
00182   //! Get saccade duration
00183   /*! Note that this will contain trash if there is o saccade target
00184     data. Check with hasMetaData() first to avoid this. */
00185   inline float saccadeDuration() const;
00186 
00187   //! Get the time at the endpoint of the saccade
00188   /*! Note that this will contain trash if there is no saccade target
00189     data. Check with hasMetaData() first to avoid this. */
00190   inline float saccadeTime() const;
00191 
00192   //! Get saccade number
00193   /*! Note that this will contain trash if there is no saccade target
00194     data. Check with hasMetaData() first to avoid this.
00195     Returned saccade number is zero-based. */
00196   inline unsigned int saccadeNumber() const;
00197 
00198   //! Output the data for debug purposes only
00199   /*! Commented out for build purposes. Include fstream to bring it back. */
00200   //inline void outputData(std::ostream &out) const;
00201 private:
00202   //Optional data in tree of ParamMaps
00203   const float x, y;          //!< eye position coordinates, in pixels
00204   const float pdiam;         //!< pupil diameter, in pixels
00205   const SaccadeState sstate; //!< See definitions in SaccadeState.H
00206   const bool bstate;         //!< Blink state
00207  
00208   const rutz::shared_ptr<ParamMap> itsExtraData;
00209   inline std::string special(std::string field) const;
00210   inline std::string unspecial(std::string field) const;
00211 
00212 };
00213 
00214 // ######################################################################
00215 // ######################################################################
00216 // ##########               inlined functions                ############
00217 // ######################################################################
00218 // ######################################################################
00219 inline EyeData::EyeData(const float x_, const float y_, const float pdiam_,
00220                         const SaccadeState sstate_, const bool bstate_) :
00221   x(x_), y(y_), pdiam(pdiam_), sstate(sstate_), bstate(bstate_),
00222   itsExtraData(new ParamMap)
00223 { }
00224 
00225 inline EyeData::EyeData(const float x_, const float y_, const float pdiam_,
00226                  const SaccadeState sstate_, const bool bstate_,
00227                                         rutz::shared_ptr<ParamMap> dat) :
00228  x(x_), y(y_), pdiam(pdiam_), sstate(sstate_), bstate(bstate_),
00229   itsExtraData(dat)
00230 {}
00231 inline EyeData::EyeData(const float x_, const float y_, const float pdiam_,
00232                         const SaccadeState sstate_, const bool bstate_,
00233                         const float dx_, const float dy_, const float ampl_,
00234                         const float dur_, const float time_,
00235                         const unsigned int num_) :
00236         x(x_), y(y_), pdiam(pdiam_), sstate(sstate_), bstate(bstate_),
00237         itsExtraData(new ParamMap)
00238 {
00239   itsExtraData->putDoubleParam("targetx",dx_);
00240   itsExtraData->putDoubleParam("targety",dy_);
00241   itsExtraData->putDoubleParam("ampl",ampl_);
00242   itsExtraData->putDoubleParam("dur",dur_);
00243   itsExtraData->putDoubleParam("time",time_);
00244   itsExtraData->putDoubleParam("num",num_);
00245 }
00246 
00247 inline EyeData::~EyeData()
00248 { }
00249 
00250 inline bool EyeData::isInUnknown() const
00251 { return (sstate == SACSTATE_UNK); }
00252 
00253 inline bool EyeData::isInFixation() const{ return (sstate == SACSTATE_FIX); }
00254 
00255 inline bool EyeData::isInSaccade() const
00256 { return (sstate == SACSTATE_SAC) || (sstate == SACSTATE_COM); }
00257 
00258 inline bool EyeData::isInSmoothPursuit() const
00259 { return (sstate == SACSTATE_SMO); }
00260 
00261 inline bool EyeData::isInBlink() const
00262 { return bstate; }
00263 
00264 inline bool EyeData::isInCombinedSaccade() const
00265 { return (sstate == SACSTATE_COM); }
00266 
00267 inline SaccadeState EyeData::saccadeState() const
00268 { return sstate; }
00269 
00270 inline bool EyeData::hasPupilDiam() const
00271 { return !isnan(pdiam); }
00272 
00273 inline bool EyeData::hasMetaData(const std::string field = "any") const
00274 { if(field.compare("any") == 0) return itsExtraData.is_valid();
00275   else return (itsExtraData.is_valid() && 
00276                (itsExtraData->hasParam(field) ||
00277                 itsExtraData->hasParam(special(field)) )); }
00278 
00279 inline bool EyeData::hasSpecialMetaData(const std::string field) const
00280 { 
00281   return (hasMetaData("any") && itsExtraData->hasParam(special(field)));    
00282 }
00283 
00284 // in order to make this much more general, we should use a dictionary of similar terms in a file somewhere
00285 
00286 inline bool EyeData::hasSaccadeTargetData() const
00287 {
00288   std::vector<std::string> sac_args;
00289   // TODO: make enums/DEFINEs for which fields define a saccade
00290   // or for another region of interest
00291   const std::string fields("targetx targety");
00292   split(fields," ", std::back_inserter(sac_args));
00293   
00294   for(std::vector<std::string>::iterator iter = sac_args.begin();
00295       iter != sac_args.end();
00296       ++iter) 
00297     if (hasMetaData(*iter) == false) return false; 
00298   return true;
00299 }
00300 
00301 inline bool EyeData::isValid() const
00302 { return !(isnan(x) || isnan(y)); }
00303 
00304 inline bool EyeData::isWithin(const Dims& dims) const
00305 {
00306   if (isValid() == false) return false;
00307   const int i = int(x + 0.49999F), j = int(y + 0.49999F);
00308   return (i >= 0 && i < dims.w() && j >= 0 && j < dims.h());
00309 }
00310 
00311 inline bool EyeData::isSpecialField(std::string field) const
00312 {
00313    return field[0]=='*';
00314 }
00315 
00316 inline void EyeData::getPosition(float& xx, float& yy) const
00317 { xx = x; yy = y; }
00318 
00319 inline Point2D<int> EyeData::position() const
00320 { return Point2D<int>(int(x + 0.49999F), int(y + 0.49999F)); }
00321 
00322 inline float EyeData::pupilDiameter() const
00323 { return pdiam; }
00324 
00325 inline rutz::shared_ptr<ParamMap> EyeData::getMetaData() const
00326 { return itsExtraData; }
00327 
00328 inline std::vector<std::string> EyeData::getMetaDataList() const 
00329 {
00330   std::vector<std::string> argList;
00331   if(hasMetaData()) 
00332     for (ParamMap::key_iterator iter = getMetaData()->keys_begin();
00333          iter != getMetaData()->keys_end();
00334          ++iter)
00335       argList.push_back(*iter);
00336  
00337   return argList; }
00338     
00339 inline double EyeData::getMetaDataField(std::string field) const
00340 { 
00341   if (hasSpecialMetaData(field)) 
00342     return itsExtraData->getDoubleParam(special(field));
00343   else if(hasMetaData(field)) 
00344     return itsExtraData->getDoubleParam(field);
00345   else LFATAL("No data field %s in EyeData",field.c_str());
00346   return -1;
00347 }
00348 
00349 inline void EyeData::getSaccadeTarget(float& targx, float& targy) const
00350 { targx = getMetaDataField("targetx"); 
00351   targy = getMetaDataField("targety"); }
00352 
00353 inline Point2D<int> EyeData::saccadeTarget() const
00354 { 
00355   if(hasSaccadeTargetData())
00356     {
00357       float dx, dy;
00358       getSaccadeTarget(dx, dy);
00359       return Point2D<int>(int(dx + 0.49999F), int(dy + 0.49999F)); 
00360     }
00361   else
00362     { return Point2D<int>(1,1);} // TODO: should throw exception here
00363 }
00364 
00365 inline float EyeData::saccadeAmplitude() const
00366 { return getMetaDataField("amp"); }
00367 
00368 inline float EyeData::saccadeDuration() const
00369 { return itsExtraData->getDoubleParam("dur"); }
00370 
00371 inline float EyeData::saccadeTime() const
00372 { return itsExtraData->getDoubleParam("time"); }
00373 
00374 inline unsigned int EyeData::saccadeNumber() const
00375 { return uint(itsExtraData->getDoubleParam("num")); }
00376 
00377 // Commented out for build purposes.
00378 /* 
00379 inline void EyeData::outputData(std::ostream &out) const
00380 { 
00381   out << "(x,y,pd) = (" << x << "," << y << "," << pdiam << ")\t" 
00382       << "status = " << sstate-1 << "\n";  //-1 is for enum->0based status idx
00383   if(hasMetaData())
00384     {
00385       std::vector<std::string> metaFields = getMetaDataList();
00386       for(std::vector<std::string>::iterator iter = metaFields.begin();
00387           iter != metaFields.end();
00388           ++iter) 
00389         out << *iter << " = " << getMetaDataField(*iter) << "\n";
00390     }
00391 };
00392 */
00393 // ######################################################################
00394 /* So things look consistent in everyone's emacs... */
00395 /* Local Variables: */
00396 /* mode: c++ */
00397 /* indent-tabs-mode: nil */
00398 /* End: */
00399 
00400 inline std::string EyeData::special(std::string field) const
00401 {
00402   if(field[0]=='*') return field;
00403   else return "*"+field;
00404 }
00405 
00406 inline std::string EyeData::unspecial(std::string field) const
00407 {
00408   if(field[0]=='*') return field.erase(0,1);
00409   else return field;
00410 }
00411 #endif // PSYCHO_EYEDATA_H_DEFINED
Generated on Sun May 8 08:05:32 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3