psycho-spy2.C

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: */
Generated on Sun May 8 08:40:10 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3