00001 /*!@file AppPsycho/psycho-sra.C Psychophysics test to the accuracy in retrieving visuospatial memory */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // 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: Nader Noori <nnoori@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-sra.C $ 00035 // $Id: psycho-spatial-memory.C 13040 2010-03-23 03:59:25Z nnoori $ 00036 // paradigm can found at /lab/nnoori/works/experiments/sra/docs/paradigm.txt 00037 // 00038 00039 #include "Component/ModelManager.H" 00040 #include "Image/Image.H" 00041 #include "Psycho/PsychoDisplay.H" 00042 #include "Psycho/EyeTrackerConfigurator.H" 00043 #include "Psycho/EyeTracker.H" 00044 #include "Psycho/PsychoOpts.H" 00045 #include "Component/EventLog.H" 00046 #include "Component/ComponentOpts.H" 00047 #include "Raster/Raster.H" 00048 #include "Util/MathFunctions.H" 00049 #include "Util/Types.H" 00050 #include "GameBoard/basic-graphics.H" 00051 #include <sys/types.h> 00052 #include <dirent.h> 00053 #include <errno.h> 00054 #include <vector> 00055 #include <string> 00056 #include <iostream> 00057 #include <SDL/SDL.h> 00058 #include <SDL/SDL_image.h> 00059 #include <SDL/SDL_mixer.h> 00060 #include <stdio.h> 00061 #include <stdlib.h> 00062 #include <sstream> 00063 #include <time.h> 00064 #include "Image/DrawOps.H" 00065 #include "GameBoard/resize.h" 00066 #include <iostream> 00067 #include <fstream> 00068 #include <set> 00069 #include <algorithm> 00070 #include <ctime> 00071 00072 #ifndef INVT_HAVE_LIBSDL_IMAGE 00073 #include <cstdio> 00074 int main() 00075 { 00076 fprintf(stderr, "The SDL_image library must be installed to use this program\n"); 00077 return 1; 00078 } 00079 00080 #else 00081 00082 00083 00084 using namespace std; 00085 00086 // ###################################################################### 00087 00088 ModelManager manager("Psycho sra"); 00089 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00090 map<string,string> argMap ; 00091 00092 ////////////////////////////////////////////// 00093 // a functionf for stringigying things 00094 ////////////////////////////////////////////// 00095 template <class T> std::string stringify(T i) 00096 { 00097 ostringstream o ; 00098 o << i ; 00099 return o.str(); 00100 } 00101 00102 00103 // ###################################################################### 00104 00105 00106 int addArgument(const string st,const string delim="="){ 00107 int i = st.find(delim) ; 00108 argMap[st.substr(0,i)] = st.substr(i+1); 00109 00110 return 0 ; 00111 } 00112 00113 std::string getArgumentValue(string arg){ 00114 return argMap[arg] ; 00115 } 00116 00117 00118 00119 std::string getUsageComment(){ 00120 00121 string com = string("\nlist of arguments : \n"); 00122 00123 com += "\nlogfile=[logfilename.psy] {default = psycho-sm-or.psy}\n" ; 00124 com += "\nmemo=[a_string_without_white_space]\n"; 00125 com += "\nsubject=[subject_name] \n" ; 00126 com += "\nnum-of-trials=[>1] (number of trials ) {default=10}\n"; 00127 com += "\nmode=[1,2](1 for horizontal and 2 for vertical layout}\n"; 00128 com += "\ndot-onset=[>1](number of frames that the single dot should be presented){default=16}\n"; 00129 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00130 com += "\ntone1=[a valid file name](name of wav file without extension for tone 1){default=sin}\n"; 00131 com += "\ntone2=[a valid file name](name of wav file without extension for tone 2){default=square}\n"; 00132 com += "\ndelay=[ delay value in terms of frames befor recall signal]\n"; 00133 com += "\ngaze-park1-x\n"; 00134 com += "\ngaze-park1-y\n"; 00135 com += "\ngaze-park2-x\n"; 00136 com += "\ngaze-park2-y\n"; 00137 return com ; 00138 } 00139 00140 void initialize(){ 00141 argMap["experiment"]="spatial-recall-accuracy(sra)"; 00142 argMap["logfile"]="./psycho-sra.psy" ; 00143 argMap["num-of-trials"]="10"; 00144 argMap["subject"]="" ; 00145 argMap["memo"]="" ; 00146 argMap["delay1"]="60"; 00147 argMap["delay2"]="120"; 00148 argMap["mode"]="1" ; 00149 argMap["sound-dir"]=".."; 00150 argMap["tone1"]="sine"; 00151 argMap["tone2"]="square"; 00152 argMap["gaze-park-x"]="-1"; 00153 argMap["gaze-park-y"]="-1"; 00154 argMap["dot-onset"]="30"; 00155 argMap["number-of-intervals"]="3"; 00156 argMap["interval-distance"]="120"; 00157 argMap["interval-width"]="120"; 00158 argMap["gaze-park1-x"]="840"; 00159 argMap["gaze-park1-y"]="240"; 00160 argMap["gaze-park2-x"]="1080"; 00161 argMap["gaze-park2-y"]="240"; 00162 } 00163 00164 extern "C" int main(const int argc, char** argv) 00165 { 00166 MYLOGVERB = LOG_INFO; // suppress debug messages 00167 initialize(); 00168 00169 manager.addSubComponent(d);// 00170 nub::soft_ref<EventLog> el(new EventLog(manager));// 00171 manager.addSubComponent(el);// 00172 d->setEventLog(el);// 00173 nub::soft_ref<EyeTrackerConfigurator> 00174 etc(new EyeTrackerConfigurator(manager));// 00175 manager.addSubComponent(etc);// 00176 if (manager.parseCommandLine(argc, argv,"at least one argument needed", 1, -1)==false){ 00177 cout<<getUsageComment()<<endl; 00178 return(1); 00179 }// 00180 //and here we see what else is passed through command line 00181 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00182 addArgument(manager.getExtraArg(i),std::string("=")) ; 00183 }// 00184 00185 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]);// 00186 manager.setOptionValString(&OPT_EyeTrackerType, "EL");// 00187 nub::soft_ref<EyeTracker> eyet = etc->getET();// 00188 d->setEyeTracker(eyet);// 00189 eyet->setEventLog(el);// 00190 manager.start();// 00191 //here we set default values 00192 00193 00194 00195 00196 00197 // let's get all our ModelComponent instances started: 00198 00199 eyet->setBackgroundColor(d);// 00200 00201 //let's write every parameter in the log file 00202 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ;// 00203 00204 00205 //now let's get the arguments and push them into some variables used for defining the behavior of the program 00206 //let's see in what mode the user like to run the program 00207 int mode = atoi(argMap["mode"].c_str());// 1 is horizontal visual presentation 2 for vertical 00208 int num_of_trials = atoi(argMap["num-of-trials"].c_str()); 00209 int gaze1_x = atoi(argMap["gaze-park1-x"].c_str()); 00210 int gaze1_y = atoi(argMap["gaze-park1-y"].c_str()); 00211 int gaze2_x = atoi(argMap["gaze-park2-x"].c_str()); 00212 int gaze2_y = atoi(argMap["gaze-park2-y"].c_str()); 00213 int delay1 = atoi(argMap["delay1"].c_str()); 00214 int delay2 = atoi(argMap["delay2"].c_str()); 00215 int dot_onset = atoi(argMap["dot-onset"].c_str()); 00216 int interval_distance = atoi(argMap["interval-distance"].c_str()); 00217 int interval_width = atoi(argMap["interval-width"].c_str()); 00218 00219 00220 //let's load up the audios 00221 Mix_Music* tone1 = NULL;//tone 1 00222 Mix_Music* tone2 = NULL;//tone 2 00223 //now let's open the audio channel 00224 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00225 LINFO( "did not open the mix-audio") ; 00226 // return -1 ; 00227 } 00228 string tmpstr = argMap["sound-dir"]+"/"+argMap["tone1"]+".wav"; 00229 tone1 = Mix_LoadMUS(tmpstr.c_str()); 00230 tmpstr = argMap["sound-dir"]+"/"+argMap["tone2"]+".wav"; 00231 tone2 = Mix_LoadMUS(tmpstr.c_str()); 00232 00233 00234 //here we shoot the real experiment 00235 // let's display an ISCAN calibration grid: 00236 d->clearScreen(); 00237 d->displayISCANcalib(); 00238 d->waitForMouseClick(); 00239 d->clearScreen(); 00240 d->waitForMouseClick(); 00241 d->displayText("Here the experiment starts! click to start!"); 00242 d->waitForMouseClick(); 00243 d->displayText("CLICK for calibration!"); 00244 d->waitForMouseClick(); 00245 eyet->calibrate(d); 00246 d->clearScreen(); 00247 00248 //now let's start trials 00249 for(int tr = 0 ; tr < num_of_trials ; tr++){ 00250 int intr = rand()%3 -1; 00251 int gaze_park_x=0; 00252 int gaze_park_y=0; 00253 if(intr == -1){ 00254 gaze_park_x = gaze1_x ; gaze_park_y = gaze1_y; 00255 } 00256 if(intr == 0){ 00257 int peshk = rand()%2; 00258 if (peshk == 0){ 00259 gaze_park_x = gaze1_x ; gaze_park_y = gaze1_y; 00260 }else{ 00261 gaze_park_x = gaze2_x ; gaze_park_y = gaze2_y; 00262 } 00263 } 00264 if(intr == 1){ 00265 gaze_park_x = gaze2_x ; gaze_park_y = gaze2_y; 00266 } 00267 00268 00269 d->displayFixationBlink(gaze_park_x,gaze_park_y,true); 00270 d->pushEvent("*** trial start : " + stringify(tr) +" ***"); 00271 d->pushEvent("gaze parked at :["+stringify(gaze_park_x)+","+stringify(gaze_park_y)+"]"); 00272 d->waitForMouseClick(); 00273 d->clearScreen(); 00274 00275 //these two values keep the location of dot 00276 int xS=0; 00277 int yS=0; 00278 00279 //if peresentation_direction is set to 0 let's toss a coin to see for this trial which direction should be tried out 00280 00281 int del = rand()%2; 00282 int delay=0; 00283 switch(del){ 00284 case 0 : delay = delay1 ; break ; 00285 case 1 : delay = delay2 ; break ; 00286 } 00287 00288 int lft = intr * interval_distance - interval_width/2 + interval_width*intr; 00289 00290 d->pushEvent("delay: "+ stringify(delay) ); 00291 d->pushEvent("interval: "+stringify(intr)); 00292 00293 // for(int interval = 0 ; interval < num_of_intervals ; interval++){ 00294 // center[interval] = presentation_direction * ( num_of_intervals/2 - interval)*interval_distance + rand()%interval_width - interval_width/2; 00295 int thePos = lft+ rand()%interval_width; 00296 int x = d->getWidth() /2 ; int y = d->getHeight()/2; 00297 switch(mode){ 00298 case 1 : x += thePos;break; 00299 case 2 : y += thePos;break; 00300 } 00301 xS = x ; yS = y; 00302 d->pushEvent("presentation "+stringify(intr) + " : [" +stringify(xS)+","+ stringify(yS)+"]" ); 00303 if( Mix_PlayMusic( tone1, 0 ) == -1 ) { LINFO("tone 1 is not there, what should I play?");return 1; } 00304 while( Mix_PlayingMusic() == 1 ){} 00305 d->displayRedDotFixation(x,y,true); 00306 d->pushEvent("displayEvent start gazing at : "+stringify(tr)+"." +stringify(intr)+"."+stringify(xS)+"."+stringify(yS)); 00307 eyet->track(true); 00308 d->waitFrames(dot_onset); 00309 d->clearScreen(); 00310 eyet->track(false); 00311 d->pushEvent("displayEvent stop gazing at : "+stringify(tr)+"." +stringify(intr)+"."+stringify(xS)+"."+stringify(yS)); 00312 //} 00313 if( Mix_PlayMusic( tone2, 0 ) == -1 ) { LINFO("tone 2 is not there, what should I play?");return 1; } 00314 while( Mix_PlayingMusic() == 1 ){} 00315 d->displayFixation(gaze_park_x,gaze_park_y,true); 00316 d->waitFrames(delay); 00317 d->clearScreen(); 00318 00319 // for(int interval = 0 ; interval < num_of_intervals ; interval++){ 00320 if( Mix_PlayMusic( tone1, 0 ) == -1 ) { LINFO("tone 1 is not there, what should I play?");return 1; } 00321 while( Mix_PlayingMusic() == 1 ){} 00322 d->pushEvent("recall "+ stringify(intr) + " : [" +stringify(xS)+","+stringify(yS)+"]" ); 00323 d->pushEvent("displayEvent start racall gaze at : "+stringify(tr)+"." +stringify(intr)+"."+stringify(xS)+"."+stringify(yS)); 00324 eyet->track(true); 00325 d->waitFrames(dot_onset); 00326 d->clearScreen(); 00327 eyet->track(false); 00328 d->pushEvent("displayEvent stop recall gaze at : "+stringify(tr)+"." +stringify(intr)+"."+stringify(xS)+"."+stringify(yS)); 00329 //} 00330 00331 if( Mix_PlayMusic( tone2, 0 ) == -1 ) { LINFO("tone 2 is not there, what should I play?");return 1; } 00332 while( Mix_PlayingMusic() == 1 ){} 00333 00334 }//end of trial 00335 00336 //end of experiment 00337 d->displayText("That\'s it!"); 00338 d->waitForMouseClick(); 00339 manager.stop(); 00340 return 0; 00341 } 00342 00343 #endif // INVT_HAVE_LIBSDL_IMAGE 00344