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-spy3.C $ 00036 // $Id: psycho-spy3.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 // get true random numbers: 00102 initRandomNumbers(); 00103 00104 // let's do an eye tracker calibration: 00105 d->displayText("<SPACE> to calibrate; other key to skip"); 00106 int c = d->waitForKey(); 00107 if (c == ' ') d->displayEyeTrackerCalibration(3, 3, 1); 00108 00109 d->clearScreen(); 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 00116 00117 std::string line; 00118 getline(file, line); 00119 //parse the line to get the filepath 00120 //format: <abs filepath> 00121 std::string fpath = line.substr(0); 00122 00123 getline(file, line); 00124 // parse the line to get the total number of images 00125 // format: <num> 00126 int numImgs = atoi(line.substr(0).c_str()); 00127 std::string imgArr[numImgs][6]; 00128 00129 for(int a=0; a<numImgs; a++){ 00130 getline(file, line); 00131 00132 // parse the line to get the file names 00133 // format: <image> <target> <bg> <noCheat> <checkResponse> <reco> 00134 std::string::size_type end = line.find_first_of(" "); 00135 std::string::size_type start = 0; 00136 int i = 0; std::string imageName, targetName, bgName, noCheatName, checkName, recoName; 00137 while (end != std::string::npos) { 00138 std::string token = line.substr(start, end-start); 00139 switch(i) 00140 { 00141 case 0: 00142 imageName = token; 00143 break; 00144 case 1: 00145 targetName = token; 00146 break; 00147 case 2: 00148 bgName = token; 00149 case 3: 00150 noCheatName = token; 00151 break; 00152 case 4: 00153 checkName = token; 00154 break; 00155 } 00156 start = end + 1; 00157 end = line.find_first_of(" ", start); 00158 i ++; 00159 } 00160 // last token 00161 recoName = line.substr(start); 00162 00163 // store file names in imgArr 00164 imgArr[a][0] = imageName; 00165 imgArr[a][1] = targetName; 00166 imgArr[a][2] = bgName; 00167 imgArr[a][3] = noCheatName; 00168 imgArr[a][4] = checkName; 00169 imgArr[a][5] = recoName; 00170 } 00171 00172 //set up indices for randomizing images 00173 int index[numImgs]; 00174 for (int i = 0; i < numImgs; i++) index[i] = i; 00175 LINFO("Randomizing images..."); randShuffle(index, numImgs); 00176 00177 //begin experiment 00178 // int correct = 0, accuracy = 100, total = 0; 00179 int totalScore = 0; 00180 00181 Timer timer, rt_timer; 00182 00183 for(int a=0; a<numImgs; a++){ 00184 00185 std::string imageName, targetName, bgName, noCheatName, checkName, recoName; 00186 imageName = fpath + imgArr[index[a]][0]; 00187 targetName = fpath + imgArr[index[a]][1]; 00188 bgName = fpath + imgArr[index[a]][2]; 00189 noCheatName = fpath + imgArr[index[a]][3]; 00190 checkName = fpath + imgArr[index[a]][4]; 00191 recoName = fpath + imgArr[index[a]][5]; 00192 00193 // load up the frame and show a fixation cross on a blank screen: 00194 d->clearScreen(); 00195 LINFO("Loading '%s'...", targetName.c_str()); 00196 Image< PixRGB<byte> > target = Raster::ReadRGB(targetName); 00197 LINFO("Loading '%s'...", bgName.c_str()); 00198 Image< PixRGB<byte> > background = Raster::ReadRGB(bgName); 00199 LINFO("Loading '%s'...", imageName.c_str()); 00200 Image< PixRGB<byte> >image = Raster::ReadRGB(imageName); 00201 LINFO("Loading '%s'...", noCheatName.c_str()); 00202 Image< PixRGB<byte> > noCheat = Raster::ReadRGB(noCheatName); 00203 00204 SDL_Surface *surftarget = d->makeBlittableSurface(target, true); 00205 SDL_Surface *surfbackground = d->makeBlittableSurface(background, true); 00206 SDL_Surface *surfimage = d->makeBlittableSurface(image, true); 00207 SDL_Surface *surfnocheat = d->makeBlittableSurface(noCheat, true); 00208 00209 LINFO("All images ready."); 00210 00211 // ready to go whenever the user is ready: 00212 d->displayText("hit any key when ready"); 00213 d->waitForKey(); 00214 d->waitNextRequestedVsync(false, true); 00215 00216 //fixation and target prime display 00217 // start the eye tracker: 00218 et->track(true); 00219 d->pushEvent(std::string("===== Showing target: ") + targetName + 00220 " ====="); 00221 00222 // blink the fixation: 00223 d->displayFixationBlink(); 00224 00225 // show target image for 10*99ms: 00226 d->displaySurface(surftarget, -2, true); 00227 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00228 SDL_FreeSurface(surftarget); 00229 00230 // show bg image for 10*99ms: 00231 d->displaySurface(surfbackground, -2, true); 00232 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00233 SDL_FreeSurface(surfbackground); 00234 00235 // stop the eye tracker: 00236 usleep(50000); 00237 et->track(false); 00238 00239 // load up the frame and show a fixation cross on a blank screen: 00240 d->clearScreen(); 00241 00242 //fixation and image display 00243 // start the eye tracker: 00244 et->track(true); 00245 d->pushEvent(std::string("===== Showing image: ") +imageName + " ====="); 00246 00247 // blink the fixation for a randomized amount of time: 00248 const int iter = 3 + randomUpToIncluding(5); 00249 d->displayFixationBlink(-1, -1, iter); 00250 00251 // gobble up any keystrokes: 00252 while(d->checkForKey() != -1) ; 00253 00254 // show the image until user responds, for up to 5s: 00255 d->displaySurface(surfimage, -2, true); 00256 double startTime = timer.getSecs(); 00257 double reactTime = 0.0; 00258 rt_timer.reset(); 00259 00260 // wait for key; it will record reaction time in the logs: 00261 while(d->checkForKey() == -1 && (timer.getSecs() < startTime + 5.0)) 00262 usleep(1000); 00263 reactTime = rt_timer.getSecs(); 00264 SDL_FreeSurface(surfimage); 00265 00266 // stop the eye tracker: 00267 usleep(50000); 00268 et->track(false); 00269 00270 // flash a random grid of numbers and check response to prevent 00271 // cheating 00272 d->pushEvent(std::string("===== Showing noCheat: ") + noCheatName 00273 + " ====="); 00274 00275 // flash the image for 99ms: 00276 d->displaySurface(surfnocheat, -2, true); 00277 for (int j = 0; j < 3; j ++) d->waitNextRequestedVsync(); 00278 SDL_FreeSurface(surfnocheat); 00279 00280 // wait for response: 00281 d->displayText("Enter the number at the target location"); 00282 c = d->waitForKey(); 00283 int c2 = d->waitForKey(); 00284 std::ifstream check (checkName.c_str()); 00285 if (check == 0) LFATAL("Couldn't open check file: '%s'", 00286 checkName.c_str()); 00287 std::string response; 00288 //total ++; 00289 while (getline(check, response)) 00290 { 00291 LINFO (" reading from %s", checkName.c_str()); 00292 LINFO (" subject entered %d%d", c, c2); 00293 LINFO (" reading %c%c from %s", response[0], response[1], 00294 checkName.c_str()); 00295 00296 // calculate score for reaction time 00297 int score = 0; 00298 if (reactTime <= 1.0) score = 10; 00299 else if (reactTime <= 2.0) score = 5; 00300 else if (reactTime <= 3.0) score = 4; 00301 else if (reactTime <= 4.0) score = 3; 00302 else if (reactTime <= 5.0) score = 2; 00303 else score = 1; 00304 00305 // check the response 00306 char tmp[40]; 00307 if (((int)response[0] == c) && ((int)response[1] == c2)) 00308 { 00309 // correct ++; 00310 //accuracy = (correct * 100) / total; 00311 //sprintf(tmp, "Correct! Accuracy is %d%%", accuracy); 00312 00313 totalScore += score; 00314 sprintf(tmp, "+%d...Total Score = %d", score, totalScore); 00315 d->displayText(tmp); 00316 d->pushEvent(std::string("===== Correct =====")); 00317 } 00318 else 00319 { 00320 //accuracy = (correct * 100) / total; 00321 // sprintf(tmp, "Wrong! Accuracy is %d%%", accuracy); 00322 00323 sprintf(tmp, "+0...Total Score = %d", totalScore); 00324 d->displayText(tmp); 00325 d->pushEvent(std::string("===== Wrong =====")); 00326 } 00327 00328 // maintain display 00329 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00330 } 00331 00332 et->recalibrate(d,20); 00333 } 00334 00335 char tmp[40]; 00336 sprintf(tmp, "===== Total Score = %d", totalScore); 00337 d->pushEvent(tmp); 00338 00339 d->clearScreen(); 00340 d->displayText("Experiment complete. Thank you!"); 00341 d->waitForKey(); 00342 00343 // stop all our ModelComponents 00344 manager.stop(); 00345 00346 // all done! 00347 return 0; 00348 } 00349 00350 extern "C" int main(const int argc, char** argv) 00351 { 00352 // simple wrapper around submain() to catch exceptions (because we 00353 // want to allow PsychoDisplay to shut down cleanly; otherwise if we 00354 // abort while SDL is in fullscreen mode, the X server won't return 00355 // to its original resolution) 00356 try 00357 { 00358 return submain(argc, argv); 00359 } 00360 catch (...) 00361 { 00362 REPORT_CURRENT_EXCEPTION; 00363 } 00364 00365 return 1; 00366 } 00367 00368 // ###################################################################### 00369 /* So things look consistent in everyone's emacs... */ 00370 /* Local Variables: */ 00371 /* indent-tabs-mode: nil */ 00372 /* End: */