00001 /*!@file AppPsycho/psycho-noCheat.C Psychophysics display of still images and 00002 check response to prevent cheating*/ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-spy2.C $ 00036 // $Id: psycho-spy2.C 10794 2009-02-08 06:21:09Z itti $ 00037 // 00038 00039 #include "Component/ModelManager.H" 00040 #include "Image/Image.H" 00041 #include "Psycho/PsychoDisplay.H" 00042 #include "GUI/GUIOpts.H" 00043 #include "Psycho/EyeTrackerConfigurator.H" 00044 #include "Psycho/EyeTracker.H" 00045 #include "Psycho/PsychoOpts.H" 00046 #include "Component/EventLog.H" 00047 #include "Component/ComponentOpts.H" 00048 #include "Raster/Raster.H" 00049 #include "Util/MathFunctions.H" 00050 #include "Util/Types.H" 00051 #include <fstream> 00052 00053 // ###################################################################### 00054 extern "C" int submain(const int argc, char** argv) 00055 { 00056 MYLOGVERB = LOG_INFO; // suppress debug messages 00057 00058 // Instantiate a ModelManager: 00059 ModelManager manager("Psycho no Cheating"); 00060 00061 // Instantiate our various ModelComponents: 00062 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00063 manager.addSubComponent(d); 00064 00065 nub::soft_ref<EyeTrackerConfigurator> 00066 etc(new EyeTrackerConfigurator(manager)); 00067 manager.addSubComponent(etc); 00068 00069 nub::soft_ref<EventLog> el(new EventLog(manager)); 00070 manager.addSubComponent(el); 00071 00072 // set some display params 00073 manager.setOptionValString(&OPT_SDLdisplayDims, "1920x1080"); 00074 d->setModelParamVal("PsychoDisplayBackgroundColor", PixRGB<byte>(0)); 00075 d->setModelParamVal("PsychoDisplayTextColor", PixRGB<byte>(255)); 00076 d->setModelParamVal("PsychoDisplayBlack", PixRGB<byte>(255)); 00077 d->setModelParamVal("PsychoDisplayWhite", PixRGB<byte>(128)); 00078 d->setModelParamVal("PsychoDisplayFixSiz", 5); 00079 d->setModelParamVal("PsychoDisplayFixThick", 5); 00080 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy"); 00081 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00082 00083 // Parse command-line: 00084 if (manager.parseCommandLine(argc, argv, "<fileList>", 1, -1)==false) 00085 return(1); 00086 00087 // hook our various babies up and do post-command-line configs: 00088 nub::soft_ref<EyeTracker> et = etc->getET(); 00089 d->setEyeTracker(et); 00090 d->setEventLog(el); 00091 et->setEventLog(el); 00092 00093 // let's get all our ModelComponent instances started: 00094 manager.start(); 00095 00096 // let's display an ISCAN calibration grid: 00097 d->clearScreen(); 00098 d->displayISCANcalib(); 00099 d->waitForKey(); 00100 00101 // let's do an eye tracker calibration: 00102 d->displayText("<SPACE> to calibrate; other key to skip"); 00103 int c = d->waitForKey(); 00104 if (c == ' ') d->displayEyeTrackerCalibration(3, 3, 1); 00105 00106 d->clearScreen(); 00107 00108 // get true random numbers: 00109 initRandomNumbers(); 00110 00111 // setup array of stimuli: 00112 std::ifstream file(manager.getExtraArg(0).c_str()); 00113 if (file == 0) LFATAL("Couldn't open object file: '%s'", 00114 manager.getExtraArg(0).c_str()); 00115 std::string line; 00116 getline(file, line); 00117 //parse the line to get the filepath 00118 //format: <abs filepath> 00119 std::string fpath = line.substr(0); 00120 00121 getline(file, line); 00122 // parse the line to get the total number of images 00123 // format: <num> 00124 int numImgs = atoi(line.substr(0).c_str()); 00125 std::string imgArr[numImgs][5]; 00126 00127 for(int a=0; a<numImgs; a++){ 00128 getline(file, line); 00129 00130 // parse the line to get the file names 00131 // format: <image> <prime> <noCheat> <checkResponse> <reco> 00132 std::string::size_type end = line.find_first_of(" "); 00133 std::string::size_type start = 0; 00134 int i = 0; std::string imageName, primeName, noCheatName, checkName, recoName; 00135 while (end != std::string::npos) { 00136 std::string token = line.substr(start, end-start); 00137 switch(i) 00138 { 00139 case 0: 00140 imageName = token; 00141 break; 00142 case 1: 00143 primeName = token; 00144 break; 00145 case 2: 00146 noCheatName = token; 00147 break; 00148 case 3: 00149 checkName = token; 00150 break; 00151 } 00152 start = end + 1; 00153 end = line.find_first_of(" ", start); 00154 i ++; 00155 } 00156 // last token 00157 recoName = line.substr(start); 00158 00159 // store file names in imgArr 00160 imgArr[a][0] = imageName; 00161 imgArr[a][1] = primeName; 00162 imgArr[a][2] = noCheatName; 00163 imgArr[a][3] = checkName; 00164 imgArr[a][4] = recoName; 00165 } 00166 00167 //set up indices for randomizing images 00168 int index[numImgs]; 00169 for (int i = 0; i < numImgs; i++) index[i] = i; 00170 LINFO("Randomizing images..."); randShuffle(index, numImgs); 00171 00172 //begin experiment 00173 //int correct = 0, total = 0, accuracy = 100; 00174 int totalScore = 0; 00175 00176 Timer timer, rt_timer; 00177 00178 for (int a = 0; a < numImgs; a++) { 00179 00180 std::string imageName, primeName, noCheatName, checkName, recoName; 00181 imageName = fpath + imgArr[index[a]][0]; 00182 primeName = fpath + imgArr[index[a]][1]; 00183 noCheatName = fpath + imgArr[index[a]][2]; 00184 checkName = fpath + imgArr[index[a]][3]; 00185 recoName = fpath + imgArr[index[a]][4]; 00186 00187 // load up the frame and the nocheat image, and show a fixation 00188 // cross on a blank screen: 00189 d->clearScreen(); 00190 LINFO("Loading '%s'...", primeName.c_str()); 00191 Image< PixRGB<byte> > prime = Raster::ReadRGB(primeName); 00192 LINFO("Loading '%s'...", imageName.c_str()); 00193 Image< PixRGB<byte> > image = Raster::ReadRGB(imageName); 00194 LINFO("Loading '%s'...", noCheatName.c_str()); 00195 Image< PixRGB<byte> > noCheat = Raster::ReadRGB(noCheatName); 00196 00197 SDL_Surface *surfprime = d->makeBlittableSurface(prime, true); 00198 SDL_Surface *surfimage = d->makeBlittableSurface(image, true); 00199 SDL_Surface *surfnocheat = d->makeBlittableSurface(noCheat, true); 00200 00201 LINFO("'%s', '%s' and '%s' ready.", primeName.c_str(), 00202 imageName.c_str(), noCheatName.c_str()); 00203 00204 // ready to go whenever the user is ready: 00205 d->displayText("hit any key when ready"); 00206 d->waitForKey(); 00207 d->waitNextRequestedVsync(false, true); 00208 00209 // fixation and target prime display 00210 // start the eye tracker: 00211 et->track(true); 00212 d->pushEvent(std::string("===== Showing prime: ") + primeName + " ====="); 00213 00214 // blink the fixation: 00215 d->displayFixationBlink(); 00216 00217 // show prime for 10*99ms: 00218 d->displaySurface(surfprime, -2, true); 00219 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00220 SDL_FreeSurface(surfprime); 00221 00222 // stop the eye tracker: 00223 usleep(50000); 00224 et->track(false); 00225 00226 // load up the frame and show a fixation cross on a blank screen: 00227 d->clearScreen(); 00228 00229 // fixation and image display 00230 // start the eye tracker: 00231 et->track(true); 00232 d->pushEvent(std::string("===== Showing image: ") +imageName + " ====="); 00233 00234 // blink the fixation for a randomized amount of time: 00235 const int iter = 3 + randomUpToIncluding(5); 00236 d->displayFixationBlink(-1, -1, iter); 00237 00238 // gobble up any keystrokes: 00239 while(d->checkForKey() != -1) ; 00240 00241 // show the image until user responds, for up to 5s: 00242 d->displaySurface(surfimage, -2, true); 00243 double startTime = timer.getSecs(); 00244 double reactTime = 0.0; 00245 rt_timer.reset(); 00246 00247 // wait for key; it will record reaction time in the logs: 00248 while(d->checkForKey() == -1 && (timer.getSecs() < startTime + 5.0)) 00249 usleep(1000); 00250 reactTime = rt_timer.getSecs(); 00251 SDL_FreeSurface(surfimage); 00252 00253 // stop the eye tracker: 00254 usleep(50000); 00255 et->track(false); 00256 00257 // flash a random grid of numbers and check response to prevent 00258 // cheating 00259 d->pushEvent(std::string("===== Showing noCheat: ") + noCheatName 00260 + " ====="); 00261 00262 // flash the image for 99ms: 00263 d->displaySurface(surfnocheat, -2, true); 00264 for (int j = 0; j < 3; j ++) d->waitNextRequestedVsync(); 00265 SDL_FreeSurface(surfnocheat); 00266 00267 // wait for response: 00268 d->displayText("Enter the number at the target location"); 00269 c = d->waitForKey(); 00270 int c2 = d->waitForKey(); 00271 std::ifstream check (checkName.c_str()); 00272 if (check == 0) LFATAL("Couldn't open check file: '%s'", 00273 checkName.c_str()); 00274 std::string response; 00275 // total ++; 00276 while (getline(check, response)) 00277 { 00278 LINFO (" reading from %s", checkName.c_str()); 00279 LINFO (" subject entered %d%d", c, c2); 00280 LINFO (" reading %c%c from %s", response[0], response[1], 00281 checkName.c_str()); 00282 00283 // calculate score for reaction time 00284 int score = 0; 00285 if (reactTime <= 1.0) score = 10; 00286 else if (reactTime <= 2.0) score = 5; 00287 else if (reactTime <= 3.0) score = 4; 00288 else if (reactTime <= 4.0) score = 3; 00289 else if (reactTime <= 5.0) score = 2; 00290 else score = 1; 00291 00292 // check the response 00293 char tmp[40]; 00294 if (((int)response[0] == c) && ((int)response[1] == c2)) 00295 { 00296 // correct ++; 00297 // accuracy = (correct * 100) / total; 00298 // sprintf(tmp, "Correct! Accuracy is %d%%", accuracy); 00299 00300 totalScore += score; 00301 sprintf(tmp, "+%d...Total Score = %d", score, totalScore); 00302 d->displayText(tmp); 00303 d->pushEvent(std::string("===== Correct =====")); 00304 } 00305 else 00306 { 00307 // accuracy = (correct * 100) / total; 00308 // sprintf(tmp, "Wrong! Accuracy is %d%%", accuracy); 00309 00310 sprintf(tmp, "+0...Total Score = %d", totalScore); 00311 d->displayText(tmp); 00312 d->pushEvent(std::string("===== Wrong =====")); 00313 } 00314 00315 // maintain display 00316 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00317 } 00318 00319 et->recalibrate(d,20); 00320 } 00321 00322 char tmp[40]; 00323 sprintf(tmp, "===== Total Score = %d", totalScore); 00324 d->pushEvent(tmp); 00325 00326 d->clearScreen(); 00327 d->displayText("Part 2 complete. Thank you!"); 00328 d->waitForKey(); 00329 00330 // stop all our ModelComponents 00331 manager.stop(); 00332 00333 // all done! 00334 return 0; 00335 } 00336 00337 extern "C" int main(const int argc, char** argv) 00338 { 00339 // simple wrapper around submain() to catch exceptions (because we 00340 // want to allow PsychoDisplay to shut down cleanly; otherwise if we 00341 // abort while SDL is in fullscreen mode, the X server won't return 00342 // to its original resolution) 00343 try 00344 { 00345 return submain(argc, argv); 00346 } 00347 catch (...) 00348 { 00349 REPORT_CURRENT_EXCEPTION; 00350 } 00351 00352 return 1; 00353 } 00354 00355 // ###################################################################### 00356 /* So things look consistent in everyone's emacs... */ 00357 /* Local Variables: */ 00358 /* indent-tabs-mode: nil */ 00359 /* End: */