00001 /*!@file AppPsycho/psycho-stealth.C Psychophysics display of primary task's 00002 search arrays followed by stealthy insertion of secondary task's 00003 search arrays */ 00004 00005 // //////////////////////////////////////////////////////////////////// // 00006 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00007 // University of Southern California (USC) and the iLab at USC. // 00008 // See http://iLab.usc.edu for information about this project. // 00009 // //////////////////////////////////////////////////////////////////// // 00010 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00011 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00012 // in Visual Environments, and Applications'' by Christof Koch and // 00013 // Laurent Itti, California Institute of Technology, 2001 (patent // 00014 // pending; application number 09/912,225 filed July 23, 2001; see // 00015 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00016 // //////////////////////////////////////////////////////////////////// // 00017 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00018 // // 00019 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00020 // redistribute it and/or modify it under the terms of the GNU General // 00021 // Public License as published by the Free Software Foundation; either // 00022 // version 2 of the License, or (at your option) any later version. // 00023 // // 00024 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00025 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00026 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00027 // PURPOSE. See the GNU General Public License for more details. // 00028 // // 00029 // You should have received a copy of the GNU General Public License // 00030 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00031 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00032 // Boston, MA 02111-1307 USA. // 00033 // //////////////////////////////////////////////////////////////////// // 00034 // 00035 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00036 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-stealth.C $ 00037 // $Id: psycho-stealth.C 8426 2007-05-24 06:57:57Z itti $ 00038 // 00039 00040 #include "Component/ModelManager.H" 00041 #include "Image/Image.H" 00042 #include "Psycho/PsychoDisplay.H" 00043 #include "Psycho/EyeTrackerConfigurator.H" 00044 #include "Psycho/EyeTracker.H" 00045 #include "GUI/GUIOpts.H" 00046 #include "Psycho/PsychoOpts.H" 00047 #include "Component/EventLog.H" 00048 #include "Component/ComponentOpts.H" 00049 #include "Raster/Raster.H" 00050 #include "Util/Types.H" 00051 #include <fstream> 00052 #include <string> 00053 00054 // ###################################################################### 00055 extern "C" int main(const int argc, char** argv) 00056 { 00057 MYLOGVERB = LOG_INFO; // suppress debug messages 00058 00059 // Instantiate a ModelManager: 00060 ModelManager manager("Psycho stealth"); 00061 00062 // Instantiate our various ModelComponents: 00063 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00064 manager.addSubComponent(d); 00065 00066 nub::soft_ref<EyeTrackerConfigurator> 00067 etc(new EyeTrackerConfigurator(manager)); 00068 manager.addSubComponent(etc); 00069 00070 nub::soft_ref<EventLog> el(new EventLog(manager)); 00071 manager.addSubComponent(el); 00072 00073 // set some display params 00074 //manager.setOptionValString(&OPT_SDLdisplayDims, "1280x1024"); 00075 manager.setOptionValString(&OPT_SDLdisplayDims, "1024x768"); 00076 d->setModelParamVal("PsychoDisplayBackgroundColor", PixRGB<byte>(0)); 00077 d->setModelParamVal("PsychoDisplayTextColor", PixRGB<byte>(255)); 00078 d->setModelParamVal("PsychoDisplayBlack", PixRGB<byte>(255)); 00079 d->setModelParamVal("PsychoDisplayWhite", PixRGB<byte>(128)); 00080 d->setModelParamVal("PsychoDisplayFixSiz", 5); 00081 d->setModelParamVal("PsychoDisplayFixThick", 5); 00082 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy"); 00083 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00084 00085 00086 // Parse command-line: 00087 if (manager.parseCommandLine(argc, argv, "<fileList> <stealthPrefix>" 00088 "<numStealth>", 00089 3,-1)==false) 00090 return(1); 00091 00092 // hook our various babies up and do post-command-line configs: 00093 nub::soft_ref<EyeTracker> et = etc->getET(); 00094 d->setEyeTracker(et); 00095 d->setEventLog(el); 00096 et->setEventLog(el); 00097 00098 // let's get all our ModelComponent instances started: 00099 manager.start(); 00100 00101 // let's display an ISCAN calibration grid: 00102 d->clearScreen(); 00103 d->displayISCANcalib(); 00104 d->waitForKey(); 00105 00106 // let's do an eye tracker calibration: 00107 d->displayText("<SPACE> to calibrate; other key to skip"); 00108 int c = d->waitForKey(); 00109 if (c == ' ') d->displayEyeTrackerCalibration(3, 3); 00110 00111 d->clearScreen(); 00112 00113 // setup array of movie indices: 00114 std::ifstream file(manager.getExtraArg(0).c_str()); 00115 if (file == 0) LFATAL("Couldn't open object file: '%s'", 00116 manager.getExtraArg(0).c_str()); 00117 // prefix or path to stealth trials 00118 std::string stealthPrefix = manager.getExtraArg(1); 00119 // number of items per stealth trial 00120 int numStealth = atoi (manager.getExtraArg(2).c_str()); 00121 00122 std::string line; 00123 // for online feedback on primary task T1 00124 int correct = 0, accuracy = 100, total = 0; 00125 // find the number of reports on M,T,D for the secondary task T2 00126 int N[numStealth]; 00127 for (int i = 0; i < numStealth; i++) N[i] = 0; 00128 while(getline(file, line)) 00129 { 00130 // parse the line to get the file names 00131 // format: <image> <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, 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 noCheatName = token; 00144 break; 00145 case 2: 00146 checkName = token; 00147 break; 00148 } 00149 start = end + 1; 00150 end = line.find_first_of(" ", start); 00151 i ++; 00152 } 00153 // last token 00154 recoName = line.substr(start); 00155 00156 // load up the frame and show a fixation cross on a blank screen: 00157 d->clearScreen(); 00158 00159 LINFO("Loading '%s'...", imageName.c_str()); 00160 Image< PixRGB<byte> > image = 00161 Raster::ReadRGB(imageName); 00162 00163 SDL_Surface *surf = d->makeBlittableSurface(image, true); 00164 00165 LINFO("'%s' ready.", imageName.c_str()); 00166 00167 // ready to go whenever the user is ready: 00168 d->displayText("hit any key when ready"); 00169 d->waitForKey(); 00170 d->waitNextRequestedVsync(false, true); 00171 00172 // start the eye tracker: 00173 et->track(true); 00174 d->pushEvent(std::string("===== Showing image: ") +imageName + " ====="); 00175 00176 // blink the fixation: 00177 d->displayFixationBlink(); 00178 00179 // show the image: 00180 d->displaySurface(surf, -2, true); 00181 00182 if (imageName.find(stealthPrefix, 0) != std::string::npos) { 00183 // flash T2 trial 00184 for (int j = 0; j < 7; j ++) d->waitNextRequestedVsync(); 00185 } 00186 else { 00187 // T1 trial 00188 c = d->waitForKey(); 00189 } 00190 00191 // free the image: 00192 SDL_FreeSurface(surf); 00193 00194 // stop the eye tracker: 00195 usleep(50000); 00196 et->track(false); 00197 00198 // flash a random grid of numbers and check response to prevent 00199 // cheating 00200 LINFO("Loading '%s'...", noCheatName.c_str()); 00201 00202 Image< PixRGB<byte> > noCheat = 00203 Raster::ReadRGB(noCheatName); 00204 00205 surf = d->makeBlittableSurface(noCheat, true); 00206 00207 00208 LINFO("'%s' ready.", noCheatName.c_str()); 00209 d->pushEvent(std::string("===== Showing noCheat: ") + noCheatName 00210 + " ====="); 00211 00212 // flash the image for 99ms: 00213 d->displaySurface(surf, -2, true); 00214 for (int j = 0; j < 6; j ++) d->waitNextRequestedVsync(); 00215 00216 // free the image: 00217 SDL_FreeSurface(surf); 00218 00219 // wait for response: 00220 d->displayText("Enter the number at the target location"); 00221 c = d->waitForKey(); 00222 int c2 = d->waitForKey(); 00223 00224 if (imageName.find(stealthPrefix, 0) == std::string::npos) { 00225 // check response for the T1 trial 00226 std::ifstream check (checkName.c_str()); 00227 if (check == 0) LFATAL("Couldn't open check file: '%s'", 00228 checkName.c_str()); 00229 std::string response; 00230 total ++; 00231 while (getline(check, response)) 00232 { 00233 LINFO (" reading from %s", checkName.c_str()); 00234 LINFO (" subject entered %d%d", c, c2); 00235 LINFO (" reading %c%c from %s", response[0], response[1], 00236 checkName.c_str()); 00237 // check the response 00238 char tmp[40]; 00239 if (((int)response[0] == c) && ((int)response[1] == c2)) 00240 { 00241 correct ++; 00242 accuracy = correct * 100 / total; 00243 sprintf(tmp, "Correct! Accuracy is %d%%", accuracy); 00244 d->displayText(tmp); 00245 d->pushEvent(std::string("===== Correct =====")); 00246 } 00247 else 00248 { 00249 accuracy = correct * 100 / total; 00250 sprintf(tmp, "Wrong! Accuracy is %d%%", accuracy); 00251 d->displayText(tmp); 00252 d->pushEvent(std::string("===== Wrong =====")); 00253 } 00254 // maintain display 00255 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00256 } 00257 } 00258 else { 00259 // check response for the T2 trial 00260 std::ifstream reco (recoName.c_str()); std::string sline; 00261 if (reco == 0) LFATAL("Couldn't open reco file: '%s'", 00262 recoName.c_str()); 00263 std::string response; int lineNum = 0; 00264 LINFO (" reading from %s", recoName.c_str()); 00265 LINFO (" subject entered %c%c", c, c2); 00266 // compare subject's response to that stored in the reco file 00267 bool match = false; 00268 while(getline(reco, sline)) 00269 { 00270 // parse the line to get the correct response 00271 // format: <row> <col> <imageName> <response> 00272 std::string::size_type end = sline.find_first_of(" "), start = 0; 00273 std::string response; 00274 while (end != std::string::npos) { 00275 std::string token = sline.substr(start, end-start); 00276 start = end + 1; 00277 end = sline.find_first_of(" ", start); 00278 } 00279 response = sline.substr(start); 00280 LINFO (" reading %c%c from %s", response[0], response[1], 00281 recoName.c_str()); 00282 // does the report match the stored response? 00283 if (((int)response[0] == c) && ((int)response[1] == c2)) 00284 { 00285 // found match, update the number of reports 00286 N[lineNum] = N[lineNum] + 1; 00287 match = true; 00288 char s[40]; sprintf(s, "N = ( "); 00289 for (int i = 0; i < numStealth; i ++) 00290 sprintf(s, "%s %d ", s, N[i]); 00291 LINFO ("%s )", s); 00292 break; 00293 } 00294 lineNum ++; // parse the next line 00295 i = 0; // reset token index for parsing the next line 00296 } 00297 if (match == false) 00298 d->displayText("Oops, You entered an invalid number..."); 00299 00300 // maintain display 00301 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync(); 00302 00303 } 00304 00305 } 00306 00307 d->clearScreen(); 00308 d->displayText("Experiment complete. Thank you!"); 00309 d->waitForKey(); 00310 00311 // output the number of reports 00312 char s[40]; sprintf(s, "N = ( "); 00313 for (int i = 0; i < numStealth; i ++) 00314 sprintf(s, "%s %d ", s, N[i]); 00315 LINFO ("%s )", s); 00316 LINFO ("accuracy = %d%%", accuracy); 00317 00318 // stop all our ModelComponents 00319 manager.stop(); 00320 00321 // all done! 00322 return 0; 00323 } 00324 00325 // ###################################################################### 00326 /* So things look consistent in everyone's emacs... */ 00327 /* Local Variables: */ 00328 /* indent-tabs-mode: nil */ 00329 /* End: */