00001 /*!@file AppPsycho/psycho-concurrent-digit.C Psychophysics display of still images for concurrent task */ 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-concurrent-digit.C $ 00035 // $Id: psycho-concurrent-digit.C 10794 2009-02-08 06:21:09Z itti $ 00036 // 00037 00038 #include "Component/ModelManager.H" 00039 #include "Image/Image.H" 00040 #include "Psycho/PsychoDisplay.H" 00041 #include "Psycho/EyeTrackerConfigurator.H" 00042 #include "Psycho/EyeTracker.H" 00043 #include "Psycho/PsychoOpts.H" 00044 #include "Component/EventLog.H" 00045 #include "Component/ComponentOpts.H" 00046 #include "Raster/Raster.H" 00047 #include "Util/MathFunctions.H" 00048 #include "Util/Types.H" 00049 #include "GameBoard/basic-graphics.H" 00050 #include <sys/types.h> 00051 #include <dirent.h> 00052 #include <errno.h> 00053 #include <vector> 00054 #include <string> 00055 #include <iostream> 00056 #include <SDL/SDL.h> 00057 #include <SDL/SDL_image.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 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 ModelManager manager("Psycho-Concurrent-Digit"); 00085 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00086 map<uint,uint> testMap ; 00087 map<string,string> argMap ; 00088 map<string,vector<SDL_Rect*>*> clipsmap; 00089 00090 ////////////////////////////////////////////// 00091 00092 // a functionf for stringigying things 00093 template <class T> std::string stringify(T i) 00094 { 00095 ostringstream o ; 00096 o << i ; 00097 return o.str(); 00098 } 00099 00100 00101 ////////////////////////////////////////////// 00102 void getMouseEvent(){ 00103 bool quit = false ; 00104 SDL_Event event ; 00105 while( quit == false ) { 00106 while( SDL_PollEvent( &event ) ) { 00107 if( event.type == SDL_MOUSEBUTTONDOWN ) { quit = true; } 00108 } 00109 } 00110 } 00111 //pushes back the name of files in the directory into the given vector 00112 int getdir (string dir, vector<string> &files) 00113 { 00114 DIR *dp; 00115 struct dirent *dirp; 00116 if((dp = opendir(dir.c_str())) == NULL) { 00117 cout << "Error(" << errno << ") opening " << dir << endl; 00118 return errno; 00119 } 00120 string fn = "" ; 00121 size_t found; 00122 string extension = "" ; 00123 while ((dirp = readdir(dp)) != NULL) { 00124 fn = string(dirp->d_name) ; 00125 found = fn.find_last_of("."); 00126 if(found > 0 && found <1000){ 00127 extension = fn.substr(found) ; 00128 if(extension.compare(".png")== 0 || extension.compare(".jpg")==0 ) 00129 files.push_back(dir+"/"+fn); 00130 } 00131 } 00132 closedir(dp); 00133 return 0; 00134 } 00135 00136 bool itIsInThere(int x , vector<int> bag){ 00137 for( uint i=0 ; i < bag.size(); i++ ){ 00138 if(x == bag[i]) return true ; 00139 } 00140 return false ; 00141 } 00142 00143 //////////////////////////////////////////////////////// 00144 ///// simply generates a sequence of digits displayed on random places on the screen 00145 //////////////////////////////////////////////////////// 00146 string digitMemorizationTask(uint l, int maxForDigit=10 ,float wp = 1.0f, float hp = 1.0f, int displayFrame = 10 , int delayFrame = 30 ){ 00147 d->clearScreen() ; 00148 vector<int> pickedones = vector<int>() ; 00149 string test = string("") ; 00150 string tp = string("") ; 00151 int widthRange = (int)((float)(d->getWidth()) * wp); 00152 int heightRange = (int)((float)(d->getHeight()) * hp); 00153 int wMargin = (d->getWidth() - widthRange)/2 ; 00154 int hMargin = (d->getHeight() - heightRange) / 2 ; 00155 for(uint i = 0 ; i < l ; i++){ 00156 int nd; 00157 do{ nd= rand()% maxForDigit ; }while(itIsInThere(nd,pickedones) && pickedones.size() < 11) ; 00158 pickedones.push_back(nd); 00159 tp = stringify(nd) ; 00160 // int x = (rand()%widthRange) + wMargin; 00161 // int y = (rand()%heightRange ) + hMargin ; 00162 //d->displayText(tp,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00163 test += tp ; 00164 //d->waitFrames(displayFrame) ; 00165 d->clearScreen() ; 00166 //if(i<l-1) 00167 //d->waitFrames(delayFrame) ; 00168 } 00169 00170 int x = (rand()%widthRange) + wMargin; 00171 int y = (rand()%heightRange ) + hMargin ; 00172 d->displayText(test,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00173 d->waitFrames(displayFrame*l) ; 00174 return test ; 00175 } 00176 00177 00178 //////////////////////////////////////////////////////// 00179 ///// simply generates a sequence of digits displayed on random places on the screen 00180 //////////////////////////////////////////////////////// 00181 string unlimitedDigitMemorizationTask(int maxForDigit=10 ,float wp = 1.0f, float hp = 1.0f, int displayFrame = 30 , int delayFrame = 30){ 00182 vector<int> pickedones = vector<int>() ; 00183 00184 string test = string("") ; 00185 string tp = string("") ; 00186 int widthRange = (int)((float)(d->getWidth()) * wp); 00187 int heightRange = (int)((float)(d->getHeight()) * hp); 00188 int wMargin = (d->getWidth() - widthRange)/2 ; 00189 int hMargin = (d->getHeight() - heightRange) / 2 ; 00190 //bool flag = true ; 00191 SDL_Event event; 00192 00193 00194 while( true ){ 00195 d->clearScreen() ; 00196 while( SDL_PollEvent(&event) != 0 ){ 00197 if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) return test ; 00198 } 00199 d->waitFrames(delayFrame) ; 00200 int nd; 00201 do{ nd= rand()% maxForDigit ; }while(itIsInThere(nd,pickedones) && pickedones.size() < 11) ; 00202 pickedones.push_back(nd); 00203 tp = stringify(nd) ; 00204 // int x = (rand()%widthRange) + wMargin; 00205 // int y = (rand()%heightRange ) + hMargin ; 00206 // d->displayText(tp,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00207 test += tp ; 00208 // d->waitFrames(displayFrame) ; 00209 // d->clearScreen() ; 00210 } 00211 int x = (rand()%widthRange) + wMargin; 00212 int y = (rand()%heightRange ) + hMargin ; 00213 d->displayText(test,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00214 d->waitFrames(displayFrame) ; 00215 return test ; 00216 } 00217 00218 00219 //////////////////////////////////////////////////////// 00220 ///////this will change the order of elements in a vector to a random order 00221 //////////////////////////////////////////////////////// 00222 void scramble(vector<string>& v){ 00223 vector<string> tv = vector<string>() ; 00224 while(v.size()>0){ 00225 tv.push_back(v[0]); 00226 v.erase(v.begin()); 00227 } 00228 int i = 0 ; 00229 while(tv.size()>0){ 00230 i = rand()%tv.size() ; 00231 v.push_back(tv[i]); 00232 tv.erase(tv.begin()+i); 00233 } 00234 } 00235 00236 00237 //////////////////////////////////////////////////////////////// 00238 ////This is our button factory 00239 //////////////////////////////////////////////////////////////// 00240 SDL_Surface* getButtonImage(string label , PixRGB<byte> txtcolor=PixRGB<byte>(0,0,0) , PixRGB<byte> bgcolor=PixRGB<byte>(255,255,255) ,Point2D<int> size = Point2D<int>(100,100) ,PixRGB<byte> bordercolor=PixRGB<byte>(0,0,0) , int border=3){ 00241 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00242 textIm.clear(bgcolor); 00243 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00244 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00245 Uint32 bc = d->getUint32color(bordercolor); 00246 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00247 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00248 SDL_Rect clip; 00249 clip.x = 0 ; 00250 clip.y = 0 ; 00251 clip.w = size.i ; 00252 clip.h = size.j ; 00253 apply_surface(0,0,*surf,*blank,clip); 00254 dumpSurface(surf) ; 00255 return blank ; 00256 } 00257 00258 //////////////////////////////////////////////////////////////////////// 00259 ////This is the function for creating the keypad, in fact it generates 00260 ////12 buttons and associates the actions to the region for each button 00261 //////////////////////////////////////////////////////////////////////// 00262 00263 SDL_Surface* getKeyPad(map<string , SDL_Rect>& buttmap){ 00264 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00265 SDL_Rect clip; 00266 clip.x=0; 00267 clip.y=0; 00268 clip.w= pad->w / 3 ; 00269 clip.h = pad->h / 4 ; 00270 //keys for 1 to 9 00271 for( int i = 1 ; i < 10 ; i++){ 00272 SDL_Surface* but = getButtonImage(stringify(i),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3); 00273 SDL_Rect cl ; 00274 cl.x = ((i-1)%3)*(pad->w)/3 ; cl.y= ((i-1)/3)*((pad->h)/4) ; 00275 cl.w = clip.w ; 00276 cl.h = clip.h ; 00277 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00278 buttmap[stringify(i)] = cl ; 00279 dumpSurface(but); 00280 } 00281 SDL_Rect cl1 ; 00282 cl1.x = 0 ; cl1.y= 3*((pad->h)/4) ; 00283 cl1.w = clip.w ; 00284 cl1.h = clip.h ; 00285 buttmap["z"] = cl1 ; 00286 SDL_Surface* but = getButtonImage(string("<-"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3); 00287 apply_surface(0, 3*((pad->h)/4),*but,*pad,clip); 00288 dumpSurface(but); 00289 SDL_Rect cl2 ; 00290 cl2.x = (pad->w)/3 ; cl2.y= 3*((pad->h)/4) ; 00291 cl2.w = clip.w ; 00292 cl2.h = clip.h ; 00293 buttmap["0"] = cl2 ; 00294 but = getButtonImage(string("0"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3); 00295 apply_surface((pad->w)/3, 3*((pad->h)/4),*but,*pad,clip); 00296 dumpSurface(but); 00297 SDL_Rect cl3 ; 00298 cl3.x = 2*(pad->w)/3 ; cl3.y= 3*((pad->h)/4) ; 00299 cl3.w = clip.w ; 00300 cl3.h = clip.h ; 00301 buttmap["o"] = cl3 ; 00302 but = getButtonImage(string("Ok"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3); 00303 apply_surface(2*(pad->w)/3, 3*((pad->h)/4),*but,*pad,clip); 00304 dumpSurface(but); 00305 return pad ; 00306 } 00307 00308 00309 00310 00311 /////////////////////////////////////////////////////////////////////////// 00312 /////this function listens to mouse clicks and then finds the region of the screen 00313 /////associated with the action, buttmap is the map of the region, offset is the offset of 00314 /////buttons 00315 /////////////////////////////////////////////////////////////////////////// 00316 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00317 int quit = 0 ; 00318 string s ; 00319 SDL_Event event ; 00320 while( quit!=2 ){ 00321 while( SDL_PollEvent( &event ) ) { 00322 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00323 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00324 if(event.button.x >= (it->second).x + offset.i && event.button.x <= (it->second).x + (it->second).w + offset.i && event.button.y >= (it->second).y+ offset.j && event.button.y <= (it->second).y + (it->second).h + offset.j) { 00325 quit = 2 ; 00326 s = it->first ; 00327 break; 00328 } 00329 00330 } 00331 } 00332 00333 } 00334 } 00335 return s ; 00336 00337 } 00338 00339 00340 //////////////////////////////////////////////////// 00341 ////This function creates a virtual keypad, creates a map of buttons 00342 ////and their representation area and listens to the button press and at 00343 ////the end returns the keyed digits 00344 //////////////////////////////////////////////////// 00345 string getDigitSequenceFromSubject(uint maxl = 7 ){ 00346 d->showCursor(true) ; 00347 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00348 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00349 //now let's get the keypad surface while we get the actions map to regions 00350 SDL_Surface * keypad = getKeyPad(*buttmap); 00351 //this will be the offset of displaying the keypad on the screen 00352 SDL_Rect offset ; 00353 offset.x = (d->getWidth() - keypad->w) /2; 00354 offset.y = (d-> getHeight() - keypad->h) /2; 00355 //now let's display the keypad 00356 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00357 //this will hold the final string keyed be the subject 00358 string p = string("") ; 00359 //this is a temporary string holding the last action related to the pressed key 00360 string tp = string(""); 00361 //now let's record subject's key press 00362 while( tp.compare("o")!=0 ){ 00363 //this button is actually the display for the current string 00364 SDL_Surface* dp = getButtonImage(p ,PixRGB<byte>(195,60,12) ,PixRGB<byte>(255,255,255) ,Point2D<int>(d->getWidth()/6,d->getHeight() /15) ,PixRGB<byte>(0,25,180) , 4) ; 00365 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00366 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00367 //now let's listen to button events 00368 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00369 dumpSurface(dp) ; 00370 if(tp.compare("z")==0 && p.size()>=0 ) { 00371 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00372 }else{ 00373 if(p.size() < maxl && tp.compare("o")!=0) { 00374 p +=tp ; 00375 } 00376 00377 } 00378 00379 } 00380 buttmap = 0 ; 00381 dumpSurface(keypad) ; 00382 d->clearScreen() ; 00383 return p ; 00384 00385 } 00386 00387 00388 00389 //////////////////////////////////////////////////////////////////// 00390 //// gets a string as the argument and returns a string composed of 00391 //// characters of the first string sorted in the ascending order 00392 /////////////////////////////////////////////////////////////////// 00393 string ascSort(string st) 00394 { 00395 string res = "" ; 00396 vector<string> v = vector<string>(); 00397 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00398 00399 std::sort(v.begin(), v.end()); 00400 00401 for ( uint i = 0 ; i < v.size() ; i++ ){ 00402 res += v[i] ; 00403 } 00404 return res; 00405 } 00406 00407 //////////////////////////////////////////////////////////////////// 00408 //// gets a string as the argument and returns a string composed of 00409 //// characters of the first string sorted in the descending order 00410 /////////////////////////////////////////////////////////////////// 00411 string desSort(string st) 00412 { 00413 string res = "" ; 00414 vector<string> v = vector<string>(); 00415 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00416 std::sort(v.begin(), v.end()); 00417 std::reverse(v.begin(), v.end()); 00418 for ( uint i = 0 ; i < v.size() ; i++ ){ 00419 res += v[i] ; 00420 } 00421 return res; 00422 } 00423 00424 /////////////////////////////////////////////////////////////// 00425 //////gets the test string, answer and the mode and identifies if 00426 //////the answer matches the thing it should be, mode=0 checks if 00427 //////if the answer and test string simply the same, mode=1 matches 00428 //////the answer against the ascending sorted string of the test string 00429 //////mode=2 compares the answer against the descending sorted of 00430 //////the test string 00431 /////////////////////////////////////////////////////////////// 00432 bool isAnswerCorrect(string test , string answer , int mode){ 00433 00434 if(mode == 0 && answer.compare(test)==0) return true ; 00435 00436 if(mode == 1 && answer.compare(ascSort(test))==0) return true ; 00437 00438 if(mode == 2 && answer.compare(desSort(test))==0) return true ; 00439 00440 return false; 00441 } 00442 00443 00444 00445 int addArgument(const string st,const string delim="="){ 00446 int i = st.find(delim) ; 00447 argMap[st.substr(0,i)] = st.substr(i+1); 00448 00449 return 0 ; 00450 } 00451 00452 std::string getArgumentValue(string arg){ 00453 return argMap[arg] ; 00454 } 00455 00456 std::string getUsageComment(){ 00457 00458 string com = string("\nlist of arguments : \n"); 00459 00460 com += "\ndelay-interval=[>1]:[>1] (the interval for random delay after stroop task) {default=10}\n"; 00461 com += "\nfixation-blink=[y/n] (show the blink for fixation after stroop task or no) {defaule y}\n"; 00462 com += "\nimage-dir=[path to image directory] (needed for mode 2 and 3) {default=60:160} \n" ; 00463 com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ; 00464 com += "\nmemo=[a_string_without_white_space]\n"; 00465 com += "\nmode=[1..5] (1 memorization only , 2 dynamic memorization only (ending with evens ascending and ending with odds discending)" 00466 ", 3 memorization + image display , 4 for dynamic memorization + image display " 00467 "5 for image display only ) {default=1}\n"; 00468 com += "\ndigit-test-size=[<1](number of words in the stroop task){default=6} \n" ; 00469 com += "\nsubject=[subject_name] \n" ; 00470 com += "\ntest-rounds=[>1] (needed for mode1) {default=5}\n"; 00471 com += "\ndigit-onset=[>1] (number of frames that the digit will remain onset per digit){default=10}\n"; 00472 com += "\ndigit-offset=[>1](number of frames that between two consequent digit onset){default=30}\n"; 00473 com += "\nwidth-range=[1..100](the percentage of the width of screen for showing the digits){default=100}\n"; 00474 com += "\nheight-range=[1..100](the percentage of the height of screen for showing the digits){default=100}\n"; 00475 com += "\nblink-num=[>1](number of blinking of fixation cross){default=3} \n"; 00476 com += "\nblink-delay=[>1](delay for blinking cross apprearnce on the screen){default=2}\n"; 00477 com += "\ncalib-refresh-period=[>1](number of tests between two calibration){default=12} \n"; 00478 return com ; 00479 } 00480 00481 00482 extern "C" int main(const int argc, char** argv) 00483 { 00484 00485 MYLOGVERB = LOG_INFO; // suppress debug messages 00486 //let's push the initial value for the parameters 00487 argMap["mode"] = "1" ; 00488 argMap["logfile"]="psycho-digit-concurrent.psy" ; 00489 argMap["digit-test-size"]="6" ; 00490 argMap["image-dir"]=".."; 00491 argMap["test-rounds"]="5"; 00492 argMap["delay-interval"]="60:160" ; 00493 argMap["subject"]="" ; 00494 argMap["memo"]="" ; 00495 argMap["fixation-blink"]="y" ; 00496 argMap["digit-onset"]="10" ; 00497 argMap["digit-offset"]="30" ; 00498 argMap["width-range"]="100" ; 00499 argMap["height-range"]="100" ; 00500 argMap["blink-num"]="3" ; 00501 argMap["blink-delay"]="2" ; 00502 argMap["calib-refresh-period"] = "12" ; 00503 manager.addSubComponent(d); 00504 nub::soft_ref<EventLog> el(new EventLog(manager)); 00505 manager.addSubComponent(el); 00506 nub::soft_ref<EyeTrackerConfigurator> 00507 etc(new EyeTrackerConfigurator(manager)); 00508 manager.addSubComponent(etc); 00509 00510 if (manager.parseCommandLine(argc, argv, 00511 "at least one argument needed", 1, -1)==false){ 00512 cout<<getUsageComment()<<endl; 00513 return(1); 00514 } 00515 00516 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00517 addArgument(manager.getExtraArg(i),std::string("=")) ; 00518 } 00519 00520 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00521 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00522 // hook our various babies up and do post-command-line configs: 00523 nub::soft_ref<EyeTracker> et = etc->getET(); 00524 d->setEyeTracker(et); 00525 d->setEventLog(el); 00526 et->setEventLog(el); 00527 00528 00529 // let's get all our ModelComponent instances started: 00530 manager.start(); 00531 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00532 // let's display an ISCAN calibration grid: 00533 d->clearScreen(); 00534 d->displayISCANcalib(); 00535 d->waitForMouseClick(); 00536 00537 // let's do an eye tracker calibration: 00538 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip"); 00539 int c = d->waitForMouseClick(); 00540 if (c == 1) d->displayEyeTrackerCalibration(3,5,1 , true); 00541 00542 d->clearScreen(); 00543 int calibPeriod = atoi(argMap["calib-refresh-period"].c_str()); 00544 00545 int blinkNum = atoi(argMap["blink-num"].c_str()); 00546 int blinkDelay = atoi(argMap["blink-delay"].c_str()); 00547 //let's see in what mode the user like to run the program 00548 int mode = atoi(argMap["mode"].c_str()) ; 00549 //mode 1 and 2 inlude single memorization task, 1 for just memorization and 2 for dynamic memorization 00550 //in dynamic memorization the subject has to sort the string in ascending order when the last digit is even 00551 //and descending order if the last digit is odd 00552 if(mode==1 || mode==2 ){ 00553 int numOfTests = atoi(argMap["test-rounds"].c_str()) ; 00554 int stringSize = atoi(argMap["digit-test-size"].c_str()) ; 00555 string::size_type position = argMap["delay-interval"].find(":"); 00556 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ; 00557 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ; 00558 float wr = ((float)(atoi(argMap["width-range"].c_str())))/100.0f; 00559 float hr = ((float)(atoi(argMap["height-range"].c_str())))/100.0f; 00560 int onsetDel = atoi(argMap["digit-onset"].c_str()) ; 00561 int offsetDel = atoi(argMap["digit-offset"].c_str()) ; 00562 00563 for(int i = 0 ; i < numOfTests ; i++){ 00564 d->pushEvent("**************************************") ; 00565 d->showCursor(true); 00566 d->displayText("click one of the mouse buttons to start!"); 00567 d->waitForMouseClick() ; 00568 d->showCursor(false); 00569 // d->clearScreen(); 00570 string testString ; 00571 if(stringSize == 0 ){ 00572 testString = unlimitedDigitMemorizationTask( 10 , wr , hr , onsetDel , offsetDel); 00573 }else{ 00574 testString = digitMemorizationTask(stringSize, 10 , wr , hr , onsetDel , offsetDel) ; 00575 } 00576 // 00577 d->pushEvent("the memorization sequence is : "+testString) ; 00578 d->waitFrames((rand()%(maxDel - minDel)) +minDel); 00579 string answer = getDigitSequenceFromSubject(testString.size()); 00580 bool af = false ; 00581 if(mode==1){ 00582 af = isAnswerCorrect(testString,answer,0); 00583 }else{ 00584 int m = atoi(testString.substr(testString.size()-1).c_str()) % 2 ; 00585 switch( m ){ 00586 case 0 : af = isAnswerCorrect(testString , answer , 1 ) ; break ; 00587 case 1 : af = isAnswerCorrect(testString , answer , 2 ) ; break ; 00588 } 00589 00590 } 00591 d->pushEvent("subject keyed : "+answer); 00592 if(af){ 00593 d->pushEvent("answer was correct"); 00594 }else{ 00595 d->pushEvent("answer was incorrect"); 00596 } 00597 00598 } 00599 } 00600 00601 //mode 3 and 4 is reserved for concurrent task; 3 for simple memorization + free viewing 00602 //; 4 for dynamic memorization + free viewing again in dynamic one . Again for strings ending with odd numbers descending 00603 //sorting is required while for strings ending with even digits ascending order is required 00604 if(mode == 3 || mode == 4){ 00605 string::size_type position = argMap["delay-interval"].find(":"); 00606 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ; 00607 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ; 00608 int stringSize = atoi(argMap["digit-test-size"].c_str()) ; 00609 string dir = argMap["image-dir"]; 00610 vector<string> files = vector<string>(); 00611 getdir(dir,files); 00612 float wr = ((float)(atoi(argMap["width-range"].c_str())))/100.0f; 00613 float hr = ((float)(atoi(argMap["height-range"].c_str())))/100.0f; 00614 int onsetDel = atoi(argMap["digit-onset"].c_str()) ; 00615 int offsetDel = atoi(argMap["digit-offset"].c_str()) ; 00616 int c = 0 ; 00617 while(files.size()>0){ 00618 c++ ; 00619 if(c%calibPeriod == 0){ 00620 // let's do an eye tracker calibration: 00621 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip"); 00622 int cl = d->waitForMouseClick(); 00623 if (cl == 1) d->displayEyeTrackerCalibration(3,5,1 , true); 00624 d->clearScreen(); 00625 } 00626 int imageIndex = rand()%files.size() ; 00627 SDL_Surface *surf = load_image(files[imageIndex]); 00628 float r1 = (float)d->getWidth()/(float)surf->w ; 00629 float r2 = (float)d->getHeight() / (float)surf->h ; 00630 surf = SDL_Resize(surf ,min(r1,r2) , 5 ); 00631 SDL_Rect offset; 00632 offset.x = (d->getWidth() - surf->w) /2; 00633 offset.y = (d-> getHeight() - surf->h) /2; 00634 d->pushEvent("**************************************") ; 00635 d->showCursor(true); 00636 d->displayText("click a mouse button to start!"); 00637 d->waitForMouseClick() ; 00638 d->showCursor(false); 00639 string testString ; 00640 if(stringSize == 0 ){ 00641 testString = unlimitedDigitMemorizationTask( 10 , wr , hr , onsetDel , offsetDel); 00642 }else{ 00643 testString = digitMemorizationTask(stringSize, 10 , wr , hr , onsetDel , offsetDel) ; 00644 } 00645 d->pushEvent("the memorization sequence is : "+testString) ; 00646 00647 d->clearScreen() ; 00648 d->waitNextRequestedVsync(false, true); 00649 d->pushEvent(std::string("===== Showing image: ") + 00650 files[imageIndex] + " ====="); 00651 // start the eye tracker: 00652 et->track(true); 00653 //blink the fixation: 00654 if(argMap["fixation-blink"].compare("y")==0) d->displayFixationBlink(-1,-1,blinkNum,blinkDelay); 00655 d->pushEvent("image will go up"); 00656 d->displaySDLSurfacePatch(surf , &offset,NULL , -2,false, true); 00657 d->waitFrames((rand()%(maxDel-minDel)) +minDel ); 00658 d->clearScreen() ; 00659 d->pushEvent("image is down"); 00660 dumpSurface(surf); 00661 // stop the eye tracker: 00662 usleep(50000); 00663 et->track(false); 00664 //see if the subject was looking at the screen! 00665 string answer = getDigitSequenceFromSubject(testString.size()); 00666 bool af = false ; 00667 if(mode==3){ 00668 af = isAnswerCorrect(testString,answer,0); 00669 }else{ 00670 int m = atoi(testString.substr(testString.size()-1).c_str()) % 2 ; 00671 switch( m ){ 00672 case 0 : af = isAnswerCorrect(testString , answer , 1 ) ; break ; 00673 case 1 : af = isAnswerCorrect(testString , answer , 2 ) ; break ; 00674 } 00675 00676 } 00677 d->pushEvent("subject keyed : "+answer); 00678 if(af){ 00679 d->pushEvent("answer was correct"); 00680 }else{ 00681 d->pushEvent("answer was incorrect"); 00682 } 00683 d->clearScreen() ; 00684 files.erase(files.begin()+imageIndex); 00685 } 00686 } 00687 00688 //mode 5 is reserved for simple free viewing task 00689 if(mode == 5){ 00690 string::size_type position = argMap["delay-interval"].find(":"); 00691 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ; 00692 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ; 00693 string dir = argMap["image-dir"]; 00694 vector<string> files = vector<string>(); 00695 getdir(dir,files); 00696 int c = 0 ; 00697 00698 while(files.size()>0){ 00699 c++ ; 00700 if(c%calibPeriod == 0){ 00701 // let's do an eye tracker calibration: 00702 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip"); 00703 int cl = d->waitForMouseClick(); 00704 if (cl == 1) d->displayEyeTrackerCalibration(3,5,1 , true); 00705 d->clearScreen(); 00706 } 00707 int imageIndex = rand()%files.size() ; 00708 //this block turned out to be buggy! so I decided to switch to working with SDL_Surface instead 00709 //Image< PixRGB<byte> > image = 00710 //Raster::ReadRGB(files[imageIndex]); 00711 00712 //SDL_Surface *surf = d->makeBlittableSurface(image, true); 00713 SDL_Surface *surf = load_image(files[imageIndex]); 00714 float r1 = (float)d->getWidth()/(float)surf->w ; 00715 float r2 = (float)d->getHeight() / (float)surf->h ; 00716 surf = SDL_Resize(surf ,min(r1,r2) , 5 ); 00717 SDL_Rect offset; 00718 offset.x = (d->getWidth() - surf->w) /2; 00719 offset.y = (d-> getHeight() - surf->h) /2; 00720 d->waitFrames(45); 00721 d->waitNextRequestedVsync(false, true); 00722 d->pushEvent(std::string("===== Showing image: ") + 00723 files[imageIndex] + " ====="); 00724 00725 // start the eye tracker: 00726 et->track(true); 00727 //blink the fixation: 00728 if(argMap["fixation-blink"].compare("y")==0) d->displayFixationBlink(-1,-1,blinkNum,blinkDelay); 00729 00730 d->displaySDLSurfacePatch(surf , &offset,NULL , -2,false, true); 00731 d->waitFrames((rand()%(maxDel-minDel)) +minDel ); 00732 dumpSurface(surf); 00733 // stop the eye tracker: 00734 usleep(50000); 00735 et->track(false); 00736 d->clearScreen() ; 00737 files.erase(files.begin()+imageIndex); 00738 } 00739 00740 } 00741 00742 d->clearScreen(); 00743 d->displayText("Experiment complete. Thank you!"); 00744 d->waitForMouseClick(); 00745 //getEvent(); 00746 // stop all our ModelComponents 00747 manager.stop(); 00748 00749 00750 // all done! 00751 return 0; 00752 } 00753 00754 #endif // INVT_HAVE_LIBSDL_IMAGE 00755