00001 /*!@file Psycho/EyeSFile.C Read data from a .eyeS eye position file */ 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: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Psycho/EyeSFile.C $ 00035 // $Id: EyeSFile.C 14730 2011-04-14 18:28:58Z lior $ 00036 // 00037 00038 #ifndef PSYCHO_EYESFILE_C_DEFINED 00039 #define PSYCHO_EYESFILE_C_DEFINED 00040 00041 #include "Psycho/EyeSFile.H" 00042 00043 #include "Component/ModelOptionDef.H" 00044 #include "Media/MediaOpts.H" 00045 #include "Psycho/PsychoOpts.H" 00046 #include "rutz/trace.h" 00047 00048 #include <fstream> 00049 #include <iomanip> 00050 #include <sstream> 00051 00052 // Used by: EyeSFile 00053 static const ModelOptionDef OPT_EyeSFileName = 00054 { MODOPT_ARG_STRING, "EyeSFileName", &MOC_EYETRACK, OPTEXP_CORE, 00055 "Name of the .eyeS file from which to read eye movement samples", 00056 "eyeS-fname", '\0', "<fname.eyeS>", "" }; 00057 00058 // Used by: EyeSFile 00059 static const ModelOptionDef OPT_EyeSNumSkip = 00060 { MODOPT_ARG(int), "EyeSNumSkip", &MOC_EYETRACK, OPTEXP_CORE, 00061 "Number of leading samples to skip in the .eyeS file", 00062 "eyeS-num-skip", '\0', "<int>", "0" }; 00063 00064 // Used by: EyeSFile 00065 const ModelOptionDef OPT_EyeSPeriod = 00066 { MODOPT_ARG(SimTime), "EyeSPeriod", &MOC_EYETRACK, OPTEXP_CORE, 00067 "Eye tracker sampling period in the .eyeS file", 00068 "eyeS-period", '\0', "<float>", "240Hz" }; 00069 00070 // Used by: EyeSFile 00071 const ModelOptionDef OPT_EyeSDims = 00072 { MODOPT_ARG(Dims), "EyeSDims", &MOC_EYETRACK, OPTEXP_CORE, 00073 "Stimulus dimensions for the eye samples in the .eyeS file", 00074 "eyeS-dims", '\0', "<w>x<h>", "0x0" }; 00075 00076 EyeSFile::EyeSFile(OptionManager& mgr) 00077 : 00078 ModelComponent(mgr, "EyeSFile", "EyeSFile"), 00079 itsEyeFname(&OPT_EyeSFileName, this), 00080 itsEyeTrash(&OPT_EyeSNumSkip, this), 00081 itsEyePeriod(&OPT_EyeSPeriod, this), 00082 itsRawInputDims(&OPT_EyeSDims, this), 00083 itsFile(0), 00084 itsEyeSample(0), 00085 itsPos(0, 0) 00086 {} 00087 00088 EyeSFile::~EyeSFile() 00089 {} 00090 00091 void EyeSFile::start2() 00092 { 00093 ASSERT(itsFile == 0); 00094 00095 if (itsEyeFname.getVal().length() == 0) 00096 LFATAL("No --%s given!", itsEyeFname.getOptionDef()->longoptname); 00097 00098 itsFile = new std::ifstream(itsEyeFname.getVal().c_str()); 00099 if (!itsFile->is_open()) 00100 LFATAL("Couldn't open .eyeS file '%s' for reading", 00101 itsEyeFname.getVal().c_str()); 00102 00103 // FIXME merge all this stuff with EyeTrackerSaccadeController 00104 00105 // Look for auxiliary data files associated with the main .eyeS 00106 // file, and read data from them if present. Specifically, if 00107 // itsEyeFname is e.g. "foo.eyeS", then we will look for a file 00108 // "foo.eyeS.ntrash" to contain a value for itsEyeTrash, and we will 00109 // look for a file "foo.eyeS.rate" to contain a value for 00110 // itsEyePeriod. That way, those files can be generated once at the 00111 // same time that the .eyeS file itself is generated (probably from 00112 // some perl/matlab scripts). Note that the .rate file should 00113 // contain a suffix to indicate what units the value is in, 00114 // e.g. "240.19Hz" or "4.16337ms". 00115 00116 { 00117 std::ifstream f((itsEyeFname.getVal() + ".npts").c_str()); 00118 if (f.is_open()) 00119 { 00120 uint npts = 0; 00121 f >> npts; 00122 if (!f.fail()) 00123 LINFO("%s.npts = %u", itsEyeFname.getVal().c_str(), npts); 00124 } 00125 } 00126 00127 { 00128 std::ifstream f((itsEyeFname.getVal() + ".ntrash").c_str()); 00129 if (f.is_open()) 00130 { 00131 int ntrash = 0; 00132 f >> ntrash; 00133 if (!f.fail()) 00134 { 00135 LINFO("%s.ntrash = %d", itsEyeFname.getVal().c_str(), ntrash); 00136 const int oldval = itsEyeTrash.getVal(); 00137 itsEyeTrash.setVal(ntrash); 00138 LINFO("reset --%s from %d to %d", 00139 itsEyeFname.getOptionDef()->longoptname, 00140 oldval, itsEyeTrash.getVal()); 00141 } 00142 } 00143 } 00144 00145 { 00146 std::ifstream f((itsEyeFname.getVal() + ".rate").c_str()); 00147 if (f.is_open()) 00148 { 00149 std::string rate; 00150 f >> rate; 00151 if (!f.fail()) 00152 { 00153 LINFO("%s.rate = %s", itsEyeFname.getVal().c_str(), rate.c_str()); 00154 const SimTime oldval = itsEyePeriod.getVal(); 00155 itsEyePeriod.setValString(rate); 00156 LINFO("reset --%s from %fs (%fHz) to %fs (%fHz)", 00157 itsEyePeriod.getOptionDef()->longoptname, 00158 oldval.secs(), oldval.hertz(), 00159 itsEyePeriod.getVal().secs(), 00160 itsEyePeriod.getVal().hertz()); 00161 } 00162 } 00163 } 00164 00165 for (int i = 0; i < itsEyeTrash.getVal(); ++i) 00166 { 00167 std::string line; 00168 std::getline(*itsFile, line); 00169 } 00170 00171 // count the number of lines AFTER the initial skipped lines 00172 itsEyeSample = 0; 00173 00174 ASSERT(itsRawInputDims.getVal().isNonEmpty()); 00175 } 00176 00177 void EyeSFile::stop1() 00178 { 00179 ASSERT(itsFile != 0); 00180 itsFile->close(); 00181 delete itsFile; 00182 itsFile = 0; 00183 } 00184 00185 Point2D<int> EyeSFile::readUpTo(const SimTime& stime) 00186 { 00187 GVX_TRACE(__PRETTY_FUNCTION__); 00188 00189 ASSERT(itsFile != 0); 00190 00191 if (itsFile->eof()) 00192 return Point2D<int>(-1,-1); 00193 00194 double xsum = 0.0, ysum = 0.0; 00195 int pcount = 0; 00196 00197 while (itsEyeSample * itsEyePeriod.getVal() < stime) 00198 { 00199 ++itsEyeSample; 00200 std::string line; 00201 std::getline(*itsFile, line); 00202 *itsFile >> std::ws; 00203 if (line.find("NaN") == line.npos) 00204 { 00205 double x, y, targetx, targety, ampl; 00206 int status, fixlen; 00207 std::istringstream iss(line); 00208 00209 // see findSaccades.m for details on how the columns of 00210 // the .eyeS file are generated 00211 iss >> x >> y >> status >> targetx >> targety >> ampl >> fixlen; 00212 if (iss.fail()) 00213 LFATAL("error while scanning %s:%d:\n%s", 00214 itsEyeFname.getVal().c_str(), itsEyeSample, 00215 line.c_str()); 00216 xsum += x; 00217 ysum += y; 00218 ++pcount; 00219 } 00220 00221 if (itsFile->eof()) 00222 break; 00223 00224 if (itsFile->fail()) 00225 LFATAL("input failed at %s:%d", 00226 itsEyeFname.getVal().c_str(), itsEyeSample); 00227 } 00228 00229 if (pcount > 0) 00230 { 00231 const int x = int(xsum/pcount + 0.5); 00232 const int y = int(ysum/pcount + 0.5); 00233 00234 if (x >= 0 && x < itsRawInputDims.getVal().w() && 00235 y >= 0 && y < itsRawInputDims.getVal().h()) 00236 { 00237 itsPos = Point2D<int>(int(xsum/pcount), int(ysum/pcount)); 00238 } 00239 } 00240 00241 return itsPos; 00242 } 00243 00244 Point2D<float> EyeSFile::getPos() 00245 { 00246 GVX_TRACE(__PRETTY_FUNCTION__); 00247 00248 ASSERT(itsFile != 0); 00249 00250 if (itsFile->eof()) 00251 return Point2D<float>(-1,-1); 00252 00253 std::string line; 00254 std::getline(*itsFile, line); 00255 *itsFile >> std::ws; 00256 00257 std::istringstream iss(line); 00258 00259 double x, y, targetx, targety, ampl; 00260 int status, fixlen; 00261 iss >> x >> y >> status >> targetx >> targety >> ampl >> fixlen; 00262 if (iss.fail()) 00263 LFATAL("error while scanning %s:%d:\n%s", 00264 itsEyeFname.getVal().c_str(), itsEyeSample, 00265 line.c_str()); 00266 00267 if (itsFile->eof()) 00268 return Point2D<float>(-1,-1); 00269 00270 if (itsFile->fail()) 00271 LFATAL("input failed at %s:%d", 00272 itsEyeFname.getVal().c_str(), itsEyeSample); 00273 00274 return Point2D<float>(x,y); 00275 } 00276 00277 int EyeSFile::lineNumber() const 00278 { 00279 return itsEyeSample; 00280 } 00281 00282 // ###################################################################### 00283 /* So things look consistent in everyone's emacs... */ 00284 /* Local Variables: */ 00285 /* mode: c++ */ 00286 /* indent-tabs-mode: nil */ 00287 /* End: */ 00288 00289 #endif // PSYCHO_EYESFILE_C_DEFINED