00001 /*!@file AppPsycho/psycho-skin-indexing.C Psychophysics display of different skins for a gameboard */ 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-skin-indexing.C $ 00035 // $Id: psycho-skin-indexing.C 14376 2011-01-11 02:44:34Z pez $ 00036 // 00037 00038 #ifndef INVT_HAVE_LIBSDL_IMAGE 00039 00040 #include <cstdio> 00041 int main() 00042 { 00043 fprintf(stderr, "The SDL_image library must be installed to use this program\n"); 00044 return 1; 00045 } 00046 00047 #else 00048 00049 /* 00050 Attention: SDL_image is needed for linking 00051 00052 */ 00053 00054 #include "Component/ModelManager.H" 00055 #include "Image/Image.H" 00056 #include "Psycho/PsychoDisplay.H" 00057 #include "Psycho/EyeTrackerConfigurator.H" 00058 #include "Psycho/EyeTracker.H" 00059 #include "Psycho/PsychoOpts.H" 00060 #include "Component/EventLog.H" 00061 #include "Component/ComponentOpts.H" 00062 #include "Raster/Raster.H" 00063 #include "Util/MathFunctions.H" 00064 #include "Util/Types.H" 00065 #include <iostream> 00066 #include <fstream> 00067 #include <SDL/SDL.h> 00068 #include <SDL/SDL_image.h> 00069 #include "psycho-skin-resize.h" 00070 #include <stdio.h> 00071 #include <stdlib.h> 00072 #include <map> 00073 #include <time.h> 00074 00075 00076 using namespace std; 00077 00078 00079 //The attributes of the screen 00080 const int SCREEN_WIDTH = 840; 00081 const int SCREEN_HEIGHT = 680; 00082 const int SCREEN_BPP = 32; 00083 const int NUMBER_OF_CLASSES = 6; 00084 const int MAX_CELLS = 400 ; 00085 const int IMAGE_WIDTH = 128 ; 00086 const string classes[NUMBER_OF_CLASSES]={"class1","class2","class3","class4","class5","class6"}; 00087 SDL_Event event ; 00088 int delay = 15 ; 00089 bool programQuit = false ; 00090 map<string,map<string,SDL_Surface*> > skinsmap ; 00091 ModelManager manager("Psycho Skin Indexing"); 00092 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00093 00094 ////////////////////////////////////////// 00095 00096 SDL_Surface *load_image( string filename ) 00097 { 00098 //The image that's loaded 00099 SDL_Surface* loadedImage = NULL; 00100 00101 //The optimized image that will be used 00102 SDL_Surface* optimizedImage = NULL; 00103 00104 //Load the image 00105 loadedImage = IMG_Load( filename.c_str() ); 00106 00107 //If the image loaded 00108 if( loadedImage != NULL ) 00109 { 00110 //Create an optimized image 00111 optimizedImage = SDL_DisplayFormat( loadedImage ); 00112 00113 //Free the old image 00114 SDL_FreeSurface( loadedImage ); 00115 00116 //If the image was optimized just fine 00117 if( optimizedImage != NULL ) 00118 { 00119 //Map the color key 00120 Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF ); 00121 00122 //Set all pixels of color R 0, G 0xFF, B 0xFF to be transparent 00123 SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey ); 00124 } 00125 }else{cout<<filename;} 00126 00127 //Return the optimized image 00128 return optimizedImage; 00129 } 00130 /////////////////////////////////// 00131 00132 SDL_Surface *getAFreshSurface(int w , int h){ 00133 00134 SDL_Surface *sur = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 00135 0x00000000, 0x00000000, 0x00000000, 0x00000000); 00136 00137 return sur ; 00138 00139 } 00140 00141 /////////////////////////////////// 00142 00143 00144 void dumpSurface(SDL_Surface * surface){ 00145 00146 SDL_FreeSurface( surface ); 00147 } 00148 00149 ///////////////////////////////////////////// 00150 00151 void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination , SDL_Rect* clip = NULL) 00152 { 00153 //Make a temporary rectangle to hold the offsets 00154 SDL_Rect offset; 00155 00156 //Give the offsets to the rectangle 00157 offset.x = x; 00158 offset.y = y; 00159 00160 //Blit the surface 00161 SDL_BlitSurface( source, clip, destination, &offset ); 00162 } 00163 00164 00165 void clean_up() 00166 { 00167 00168 for( map<string,map<string,SDL_Surface*> >::iterator ii=skinsmap.begin(); ii!=skinsmap.end(); ++ii) 00169 { 00170 for(map<string,SDL_Surface*>::iterator jj=((*ii).second).begin() ; jj!= ((*ii).second).end() ; ++jj){ 00171 SDL_FreeSurface(jj->second); 00172 } 00173 00174 } 00175 00176 SDL_Quit(); 00177 } 00178 ///////////////////////////////////// 00179 void readTop(ifstream* inFile){ 00180 // tempSur = load_image("skin1/class1/ball.png"); 00181 char ch[1000]; 00182 while ((*inFile).getline(ch , 1000)){ 00183 string line = ch; 00184 LINFO("top reader reads : '%s'", line.c_str()); 00185 if(line.compare("end top")==0) break; 00186 string::size_type position = line.find("="); 00187 string skinname = line.substr(0, position); 00188 string path = line.substr(position+1); 00189 map<string,SDL_Surface*> themap; 00190 00191 for(int i = 0 ; i < NUMBER_OF_CLASSES ; i++){ 00192 string filepath ; 00193 filepath += path+"/"+classes[i]+"/ball.png" ; 00194 00195 themap[classes[i]]= load_image(filepath) ; 00196 } 00197 skinsmap[skinname] = themap; 00198 00199 } 00200 00201 } 00202 00203 void showStaticSlide(string *slideMap,string skinName , int col , int row , int px , int py , float rf){ 00204 00205 d->clearScreen(); 00206 map<string,SDL_Surface*> resizedSurfacesMap; 00207 map<string,int> clipNumMap; 00208 SDL_Rect theClip ; 00209 theClip.x = 0 ; 00210 theClip.y = 0 ; 00211 theClip.w = (int)(rf* IMAGE_WIDTH) ; 00212 theClip.h = (int)(rf* IMAGE_WIDTH) ; 00213 //bool slideQuit = false ; 00214 SDL_Surface* nbg = getAFreshSurface((int)(IMAGE_WIDTH*col*rf), (int)(IMAGE_WIDTH*row*rf)); 00215 00216 00217 //this block discovers how many clips are there in a sprite and put the number in a map 00218 //moreover it will construct required clips and put them in a map too 00219 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj ) 00220 { 00221 int numOfImages = ((jj->second)->h)/IMAGE_WIDTH ; 00222 clipNumMap[jj->first] = numOfImages ; 00223 //cout<<"Number of clips : "<<(jj->second)->h<<endl; 00224 00225 } 00226 00227 //this block makes a map from name of classes to the resized surface of each class 00228 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj ) 00229 { 00230 SDL_Surface *tmpSurface = getAFreshSurface(IMAGE_WIDTH,IMAGE_WIDTH); 00231 *tmpSurface = *(jj->second); 00232 tmpSurface = SDL_Resize(tmpSurface , rf , 3 ); 00233 resizedSurfacesMap[jj->first] = tmpSurface; 00234 00235 } 00236 00237 00238 00239 00240 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj){ 00241 string className = jj->first; 00242 00243 00244 00245 for(int i = 0 ; i < col*row ; i++){ 00246 00247 if(slideMap[i].compare( className )==0){ 00248 int clipY = (int)((rand()% clipNumMap[className])*IMAGE_WIDTH*rf); 00249 theClip.y = clipY ; 00250 apply_surface((int)((i%col)*IMAGE_WIDTH*rf),(int)((i/col)*IMAGE_WIDTH*rf),resizedSurfacesMap[className],nbg,&theClip) ; 00251 } 00252 } 00253 00254 00255 00256 } 00257 SDL_Rect offset; 00258 00259 //Give the offsets to the rectangle 00260 offset.x = px; 00261 offset.y = py; 00262 d->displaySDLSurfacePatch(nbg , &offset,NULL , -2,false, true); 00263 d->waitNextRequestedVsync(false, true); 00264 d->waitForKey(); 00265 00266 00267 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj ) 00268 { 00269 dumpSurface(resizedSurfacesMap[jj->first]); 00270 } 00271 dumpSurface(nbg) ; 00272 00273 } 00274 00275 00276 void showDynamicSlide(string *slideMap,string skinName , int col , int row , int px , int py , float rf){ 00277 00278 map<string,SDL_Surface*> resizedSurfacesMap; 00279 map<string,int> clipNumMap; 00280 int phase[col*row] ; 00281 SDL_Rect theClip ; 00282 theClip.x = 0 ; 00283 theClip.y = 0 ; 00284 theClip.w = (int)(rf* IMAGE_WIDTH) ; 00285 theClip.h = (int)(rf* IMAGE_WIDTH) ; 00286 bool slideQuit = false ; 00287 SDL_Surface *nbg = getAFreshSurface((int)(IMAGE_WIDTH*col*rf), (int)(IMAGE_WIDTH*row*rf)); 00288 00289 //this block discovers how many clips are there in a sprite and put the number in a map 00290 //moreover it will construct required clips and put then in a map too 00291 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj ) 00292 { 00293 int numOfImages = ((jj->second)->h)/IMAGE_WIDTH ; 00294 clipNumMap[jj->first] = numOfImages ; 00295 00296 } 00297 00298 //this block makes a map from name of classes to the resized surface of each class 00299 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj ) 00300 { 00301 SDL_Surface* tmpSurface = getAFreshSurface(IMAGE_WIDTH,IMAGE_WIDTH ); 00302 *tmpSurface = *(jj->second); 00303 tmpSurface = SDL_Resize(tmpSurface , rf , 3 ); 00304 resizedSurfacesMap[jj->first] = tmpSurface; 00305 00306 } 00307 00308 for(int i = 0 ; i < col*row ; i++){ 00309 00310 phase[i] = rand()% clipNumMap[*(slideMap+i)]; 00311 } 00312 00313 int l = 0 ; 00314 00315 while( slideQuit == false ) { 00316 00317 while(SDL_PollEvent( &event )){ 00318 00319 if(event.type == SDL_KEYDOWN){ 00320 if( event.key.keysym.sym == SDLK_SPACE ) 00321 { 00322 slideQuit = true ; 00323 } 00324 if( event.key.keysym.sym == SDLK_ESCAPE ) 00325 { 00326 slideQuit = true ; 00327 programQuit = true ; 00328 } 00329 if(event.key.keysym.sym == SDLK_UP){ 00330 if (delay > 2 )delay -= 2 ; 00331 } 00332 00333 if(event.key.keysym.sym == SDLK_DOWN){ 00334 if (delay < 500 )delay += 2 ; 00335 } 00336 00337 } 00338 00339 00340 if( event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE ) 00341 { 00342 programQuit = true; 00343 slideQuit = true ; 00344 } 00345 00346 00347 } 00348 00349 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj){ 00350 string className = jj->first; 00351 00352 for(int i = 0 ; i < col*row ; i++){ 00353 00354 int clipY = (int)(((l+phase[i]) % clipNumMap[className])*IMAGE_WIDTH*rf); 00355 theClip.y = clipY ; 00356 00357 if(slideMap[i].compare( className )==0){ 00358 apply_surface((int)((i%col)*IMAGE_WIDTH*rf),(int)((i/col)*IMAGE_WIDTH*rf),resizedSurfacesMap[className],nbg,&theClip); 00359 } 00360 } 00361 00362 00363 } 00364 00365 SDL_Rect offset; 00366 00367 //Give the offsets to the rectangle 00368 offset.x = px; 00369 offset.y = py; 00370 d->displaySDLSurfacePatch(nbg , &offset ,NULL, -2,true, true); 00371 00372 l++ ; 00373 SDL_Delay( delay ); 00374 } 00375 00376 00377 for(map<string,SDL_Surface*>::iterator jj=(skinsmap[skinName]).begin() ; jj!= (skinsmap[skinName]).end() ; ++jj ) 00378 { 00379 dumpSurface(resizedSurfacesMap[jj->first]); 00380 } 00381 dumpSurface(nbg) ; 00382 00383 } 00384 00385 00386 /* 00387 * Reads part of profile starting with slide till end of the part indicated by end slide 00388 * */ 00389 void readSlide(ifstream* inFile){ 00390 char ch[1000]; 00391 string skinName; 00392 float resizefactor = 1.0f; 00393 int px = 0, py = 0, rows = 0, columns = 0; 00394 string slideMap[MAX_CELLS]; 00395 bool isDynamic = false ; 00396 d->clearScreen() ; 00397 d->displayRedDotFixationBlink(); 00398 d->pushEvent(std::string("===== Reading Slide =====")); 00399 while ((*inFile).getline(ch , 1000)){ 00400 string line = ch; 00401 LINFO("slide reader reads : '%s'...", line.c_str()); 00402 d->pushEvent(line.c_str()); 00403 if(line.substr(0,4).compare("skin")==0){ 00404 string::size_type position = line.find("="); 00405 skinName = line.substr(position+1); 00406 00407 } 00408 if(line.substr(0,2).compare("rf")==0){ 00409 string::size_type position = line.find("="); 00410 char rf[10] ; 00411 strcpy(rf,line.substr(position+1).c_str()); 00412 resizefactor = atof(rf); 00413 } 00414 if(line.substr(0,2).compare("px")==0){ 00415 string::size_type position = line.find("="); 00416 char rf[10] ; 00417 strcpy(rf,line.substr(position+1).c_str()); 00418 px = atoi(rf); 00419 } 00420 if(line.substr(0,2).compare("py")==0){ 00421 string::size_type position = line.find("="); 00422 char rf[10] ; 00423 strcpy(rf,line.substr(position+1).c_str()); 00424 py = atoi(rf); 00425 } 00426 if(line.substr(0,2).compare("rs")==0){ 00427 string::size_type position = line.find("="); 00428 char rf[10] ; 00429 strcpy(rf,line.substr(position+1).c_str()); 00430 rows = atoi(rf); 00431 } 00432 if(line.substr(0,2).compare("cs")==0){ 00433 string::size_type position = line.find("="); 00434 char rf[10] ; 00435 strcpy(rf,line.substr(position+1).c_str()); 00436 columns = atoi(rf); 00437 } 00438 00439 if(line.substr(0,6).compare("static")==0){ 00440 isDynamic = false ; 00441 } 00442 00443 if(line.substr(0,7).compare("dynamic")==0){ 00444 isDynamic = true ; 00445 } 00446 00447 if(line.substr(0,3).compare("map")==0){ 00448 int p = 3 ; 00449 string cs = "class"; 00450 for (int i =0 ; i < rows*columns ; i++){ 00451 int pos = p+1 +i*2 ; 00452 string cn = line.substr(pos ,1); 00453 slideMap[i] = cs+cn; 00454 } 00455 if(isDynamic == true){ 00456 00457 showDynamicSlide(&slideMap[0],skinName,columns,rows,px,py,resizefactor) ; 00458 00459 }else{ 00460 showStaticSlide(&slideMap[0],skinName,columns,rows,px,py,resizefactor) ; 00461 } 00462 00463 00464 } 00465 00466 00467 00468 if(line.compare("end slide")==0) break; 00469 00470 00471 } 00472 00473 } 00474 00475 int readprofile(const char* filename){ 00476 ifstream inFile(filename, ios::in); 00477 if (! inFile) 00478 { 00479 return -1; 00480 } 00481 00482 char ch[1000]; 00483 while (inFile.getline(ch , 500)){ 00484 string line = ch; 00485 LINFO("profile reader reads : '%s'...", line.c_str()); 00486 if(line.compare("top")==0 ) readTop(&inFile); 00487 00488 if(line.compare("slide")==0) readSlide(&inFile); 00489 if(programQuit == true) break ; 00490 } 00491 00492 return 0 ; 00493 } 00494 00495 00496 extern "C" int main( int argc, char* args[] ){ 00497 MYLOGVERB = LOG_INFO; 00498 00499 manager.addSubComponent(d); 00500 nub::soft_ref<EventLog> el(new EventLog(manager)); 00501 manager.addSubComponent(el); 00502 00503 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy"); 00504 00505 d->setEventLog(el); 00506 00507 manager.start(); 00508 00509 // let's display an ISCAN calibration grid: 00510 d->clearScreen(); 00511 d->displayISCANcalib(); 00512 d->waitForKey(); 00513 // let's do an eye tracker calibration: 00514 d->displayText("<SPACE> to calibrate; other key to skip"); 00515 //int c = 00516 d->waitForKey(); 00517 // if (c == ' ') d->displayEyeTrackerCalibration(); 00518 00519 d->clearScreen(); 00520 d->displayText("<SPACE> for random play; other key for ordered"); 00521 //c = 00522 d->waitForKey(); 00523 00524 d->displayFixation(); 00525 00526 // ready to go whenever the user is ready: 00527 d->waitForKey(); 00528 d->waitNextRequestedVsync(false, true); 00529 00530 00531 string filename; 00532 if(argc == 2) { 00533 if(readprofile(args[1])< 0) return -1; 00534 }else{ 00535 cerr << "usage : " << args[0] << " file_name.exp \n"; 00536 return -1 ; 00537 } 00538 00539 clean_up(); 00540 manager.stop() ; 00541 return 0; 00542 } 00543 00544 #endif // INVT_HAVE_LIBSDL_IMAGE