00001 /*!@file AppPsycho/psycho-wm-chunking.C Psychophysics test to measure the influence of eyemovement on memory task performance */ 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: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-wm-chunking.C $ 00035 00036 00037 #include "Component/ModelManager.H" 00038 #include "Image/Image.H" 00039 #include "Psycho/PsychoDisplay.H" 00040 #include "Psycho/EyeTrackerConfigurator.H" 00041 #include "Psycho/EyeTracker.H" 00042 #include "Psycho/PsychoOpts.H" 00043 #include "Component/EventLog.H" 00044 #include "Component/ComponentOpts.H" 00045 #include "Raster/Raster.H" 00046 #include "Util/MathFunctions.H" 00047 #include "Util/Types.H" 00048 #include "GameBoard/basic-graphics.H" 00049 #include <sys/types.h> 00050 #include <dirent.h> 00051 #include <errno.h> 00052 #include <vector> 00053 #include <string> 00054 #include <iostream> 00055 #include <SDL/SDL.h> 00056 #include <SDL/SDL_image.h> 00057 #include <SDL/SDL_mixer.h> 00058 #include <stdio.h> 00059 #include <stdlib.h> 00060 #include <sstream> 00061 #include <time.h> 00062 #include "Image/DrawOps.H" 00063 #include "GameBoard/resize.h" 00064 #include <iostream> 00065 #include <fstream> 00066 #include <set> 00067 #include <algorithm> 00068 #include <ctime> 00069 00070 #ifndef INVT_HAVE_LIBSDL_IMAGE 00071 #include <cstdio> 00072 int main() 00073 { 00074 fprintf(stderr, "The SDL_image library must be installed to use this program\n"); 00075 return 1; 00076 } 00077 00078 #else 00079 00080 00081 00082 using namespace std; 00083 00084 // ###################################################################### 00085 00086 ModelManager manager("psycho-wm-chunking"); 00087 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00088 map<uint,uint> testMap ; 00089 map<string,string> argMap ; 00090 map<string,vector<SDL_Rect*>*> clipsmap; 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 bool itIsInThere(int x , vector<int> bag){ 00103 for( uint i=0 ; i < bag.size(); i++ ){ 00104 if(x == bag[i]) return true ; 00105 } 00106 return false ; 00107 } 00108 00109 00110 00111 //////////////////////////////////////////////////////// 00112 ///////this will change the order of elements in a vector to a random order 00113 //////////////////////////////////////////////////////// 00114 void scramble(vector<int>& v){ 00115 vector<int> tv = vector<int>() ; 00116 while(v.size()>0){ 00117 tv.push_back(v[0]); 00118 v.erase(v.begin()); 00119 } 00120 int i = 0 ; 00121 while(tv.size()>0){ 00122 i = rand()%tv.size() ; 00123 v.push_back(tv[i]); 00124 tv.erase(tv.begin()+i); 00125 } 00126 } 00127 00128 00129 00130 //pushes back the name of wav files in the directory into the given vector 00131 int getdir (string dir, vector<string> &files) 00132 { 00133 DIR *dp; 00134 struct dirent *dirp; 00135 if((dp = opendir(dir.c_str())) == NULL) { 00136 cout << "Error(" << errno << ") opening " << dir << endl; 00137 return errno; 00138 } 00139 string fn = "" ; 00140 size_t found; 00141 string extension = "" ; 00142 while ((dirp = readdir(dp)) != NULL) { 00143 fn = string(dirp->d_name) ; 00144 found = fn.find_last_of("."); 00145 if(found > 0 && found <1000){ 00146 extension = fn.substr(found) ; 00147 if(extension.compare(".wav")== 0 ) 00148 files.push_back(dir+"/"+fn); 00149 } 00150 } 00151 closedir(dp); 00152 return 0; 00153 } 00154 00155 00156 00157 00158 00159 00160 00161 00162 int addArgument(const string st,const string delim="="){ 00163 int i = st.find(delim) ; 00164 argMap[st.substr(0,i)] = st.substr(i+1); 00165 00166 return 0 ; 00167 } 00168 00169 std::string getArgumentValue(string arg){ 00170 return argMap[arg] ; 00171 } 00172 00173 std::vector<int> getDigits(int n , string zs="n" , string rs="n" ){ 00174 if(rs.compare("n")==0){ 00175 if(zs.compare("n")==0 && n >9 ) {LINFO( "come on! what do you expect?!") ; exit(-1) ;} 00176 if(zs.compare("y")==0 && n >10 ) {LINFO( "come on! what do you expect?!") ; exit(-1) ;} 00177 } 00178 vector<int> digits ; 00179 int dig = 0 ; 00180 while( digits.size() < (uint)n ){ 00181 if(zs.compare("n")==0) {dig = 1+(random()%9);}else{dig = random()%10;} 00182 if(rs.compare("y")==0){digits.push_back(dig);}else{if(!itIsInThere(dig,digits)) digits.push_back(dig);} 00183 } 00184 return digits ; 00185 } 00186 00187 std::string getUsageComment(){ 00188 00189 string com = string("\nlist of arguments : \n"); 00190 00191 com += "\nlogfile=[logfilename.psy] {default = psycho-wm-chunking.psy}\n" ; 00192 com += "\nmemo=[a_string_without_white_space]\n"; 00193 com += "\nnum-of-digits=[>0](the size of string){default=3} \n"; 00194 com += "\nsubject=[subject_name] \n" ; 00195 com += "\nseperate-recall-rounds=[>1] (number of trials including seperate recall task ) {default=2}\n"; 00196 com += "\nfirst-to-last-rounds=[>1](number of trials including first to last chunking){default=2}}\n"; 00197 com += "\nlast-to-first-rounds=[>1](number of trials including last to firts chunking){default=2}}\n"; 00198 com += "\nalphabet=[a string of characters](a string of characters){default=0123456789}\n"; 00199 com += "\ncue-wait-frames=[>0](number of frames to show the cue){default=0}\n"; 00200 com += "\ncue-onset-frames=[>0](number of frames to show the cue onset){default=10}\n"; 00201 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00202 com += "\ndigit-repeat=[y/n](whether digits can repeat, y for yes , n for no){default=n}\n" ; 00203 com += "\ninclude-zero=[y/n](whether zero be included in the presented digits, y for yes , n for no){default=n}\n"; 00204 com += "\ndelay=[>1] (delay in number of frames in which recording happens)\n" ; 00205 return com ; 00206 } 00207 00208 00209 extern "C" int main(const int argc, char** argv) 00210 { 00211 00212 MYLOGVERB = LOG_INFO; // suppress debug messages 00213 //let's push the initial value for the parameters 00214 argMap["experiment"]="chunking firs to last, chunking last to first and no chunking"; 00215 argMap["logfile"]="psycho-wm-chunking.psy" ; 00216 argMap["num-of-digits"]="3" ; 00217 argMap["seperate-recall-rounds"]="2"; 00218 argMap["first-to-last-rounds"] = "2" ; 00219 argMap["last-to-first-rounds"] = "2" ; 00220 argMap["subject"]="" ; 00221 argMap["memo"]="" ; 00222 argMap["alphabet"]="0123456789"; 00223 argMap["cue-wait-frames"]="0" ; 00224 argMap["cue-onset-frames"] = "10" ; 00225 argMap["sound-dir"]=".."; 00226 argMap["include-zero"]="n"; 00227 argMap["digit-repeat"]="n" ; 00228 argMap["delay"] = "120" ; 00229 00230 manager.addSubComponent(d); 00231 nub::soft_ref<EventLog> el(new EventLog(manager)); 00232 manager.addSubComponent(el); 00233 d->setEventLog(el); 00234 nub::soft_ref<EyeTrackerConfigurator> 00235 etc(new EyeTrackerConfigurator(manager)); 00236 manager.addSubComponent(etc); 00237 00238 if (manager.parseCommandLine(argc, argv, 00239 "at least one argument needed", 1, -1)==false){ 00240 cout<<getUsageComment()<<endl; 00241 return(1); 00242 } 00243 00244 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00245 addArgument(manager.getExtraArg(i),std::string("=")) ; 00246 } 00247 00248 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00249 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00250 nub::soft_ref<EyeTracker> eyet = etc->getET(); 00251 d->setEyeTracker(eyet); 00252 eyet->setEventLog(el); 00253 00254 //now let's open the audio channel 00255 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00256 LINFO( "did not open the mix-audio") ; 00257 return -1 ; 00258 } 00259 //let's load the 10 audio files off the director of audios and put them in a map 00260 map<int,Mix_Music*> audioMap ; 00261 for( int i = 0 ; i < 10 ; i++ ){ 00262 string str = argMap["sound-dir"]+"/"+stringify(i)+".wav" ; 00263 audioMap[i] = Mix_LoadMUS(str.c_str()); 00264 } 00265 int delay = atoi(argMap["delay"].c_str()) ; 00266 int numOfDigits = atoi(argMap["num-of-digits"].c_str()); 00267 int cue_onset_frames = atoi(argMap["cue-onset-frames"].c_str()) ; 00268 int cue_wait_frames = atoi(argMap["cue-wait-frames"].c_str()) ; 00269 int num_of_first_task = atoi(argMap["seperate-recall-rounds"].c_str()); 00270 int num_of_second_task = atoi(argMap["first-to-last-rounds"].c_str()); 00271 int num_of_third_task = atoi(argMap["last-to-first-rounds"].c_str()); 00272 vector<int>* taskVector = new vector<int>(); 00273 for(int i = 0 ; i < num_of_first_task ; i++) taskVector->push_back(1); 00274 for(int i = 0 ; i < num_of_second_task ; i++) taskVector->push_back(2); 00275 for(int i = 0 ; i < num_of_third_task ; i++) taskVector->push_back(3); 00276 scramble(*taskVector); 00277 00278 // let's get all our ModelComponent instances started: 00279 manager.start(); 00280 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00281 // let's display an ISCAN calibration grid: 00282 d->clearScreen(); 00283 d->displayISCANcalib(); 00284 d->waitForMouseClick(); 00285 d->displayText("Here the experiment starts! click to start!"); 00286 d->waitForMouseClick(); 00287 d->clearScreen(); 00288 //let's do calibration 00289 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip"); 00290 int cl = d->waitForMouseClick(); 00291 if (cl == 1) d->displayEyeTrackerCalibration(3,5,1 , true); 00292 d->clearScreen(); 00293 00294 Uint32 fc = d->getUint32color(PixRGB<byte>(255,0,0)); 00295 Uint32 sc = d->getUint32color(PixRGB<byte>(0,255,0)); 00296 Uint32 tc = d->getUint32color(PixRGB<byte>(0,0,255)); 00297 SDL_Surface* f_pad= getABlankSurface(36,34); 00298 SDL_Surface* s_pad= getABlankSurface(36,34); 00299 SDL_Surface* t_pad= getABlankSurface(36,34) ; 00300 fillRectangle(f_pad,fc,0,0,35 ,33); 00301 fillRectangle(s_pad,sc,0,0,35 ,33); 00302 fillRectangle(t_pad,tc,0,0,35 ,33); 00303 SDL_Rect cue_offset ; 00304 cue_offset.x = (d->getWidth() -36) /2; 00305 cue_offset.y = (d-> getHeight() - 34) /2; 00306 int fs = 0 ; 00307 int ss = 0; 00308 int ts = 0 ; 00309 for( uint r = 0 ; r < taskVector->size() ; r++ ){ 00310 d->showCursor(true); 00311 d->displayText("click one of the mouse buttons to start!"); 00312 d->waitForMouseClick() ; 00313 d->showCursor(false) ; 00314 d->clearScreen() ; 00315 d->displayFixationBlink(); 00316 int task = taskVector->at(r) ; 00317 vector<int> digits = getDigits(numOfDigits,argMap["include-zero"],argMap["digit-repeat"]); 00318 int counter = 0 ; 00319 while( counter < numOfDigits ){ 00320 if(Mix_PlayingMusic() == 0 ){ 00321 //Play the music 00322 if( Mix_PlayMusic( audioMap[digits[counter]], 0 ) == -1 ) { return 1; } 00323 d->pushEvent("the "+stringify(counter)+"th : " +stringify(digits[counter])); 00324 counter++ ; 00325 } 00326 } 00327 //just hold it there to the end of the audio playing 00328 while( Mix_PlayingMusic() == 1 ){} 00329 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ; 00330 std::string imst = "===== Showing image: def"; 00331 PixRGB<byte> cuecolor; 00332 switch( task ){ 00333 case 1 : fs++ ; d->displaySDLSurfacePatch(f_pad , &cue_offset,NULL , -2,false, true); imst += "_first_"+stringify(fs)+".png" ; break ; 00334 case 2 : ss++ ; d->displaySDLSurfacePatch(s_pad , &cue_offset,NULL , -2,false, true);imst += "_second_"+stringify(ss)+".png" ;break ; 00335 case 3 : ts++ ; d->displaySDLSurfacePatch(t_pad , &cue_offset,NULL , -2,false, true);imst += "_third_" +stringify(ts)+".png";break ; 00336 } 00337 00338 d->pushEvent(imst); 00339 d->waitFrames(cue_onset_frames); 00340 eyet->track(true); 00341 d->clearScreen() ; 00342 d->waitFrames(delay); 00343 eyet->track(false); 00344 d->displayText("SAY THE NUMBER LOUD!"); 00345 d->waitForMouseClick(); 00346 d->pushEvent("**************************************") ; 00347 } 00348 d->clearScreen(); 00349 d->displayText("Experiment complete. Thank you!"); 00350 d->waitForMouseClick(); 00351 00352 00353 // stop all our ModelComponents 00354 manager.stop(); 00355 00356 //let's free up the audio files 00357 for( int i = 0 ; i < 10 ; i++ ){ 00358 Mix_FreeMusic(audioMap[i]); 00359 } 00360 //time to close the audio channel 00361 Mix_CloseAudio(); 00362 // all done! 00363 return 0; 00364 } 00365 00366 #endif // INVT_HAVE_LIBSDL_IMAGE 00367