psycho-mem-capacity-test.C

00001 /*!@file AppPsycho/psycho-mem-capacity.C Psychophysics measuring the digit memorization capacity */
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-mem-capacity-test.C $
00035 // $Id: psycho-mem-capacity-test.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 // ######################################################################
00085 
00086 ModelManager manager("Psycho-Concurrent-Digit");
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 
00094 // a functionf for stringigying things
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 bool itIsInThere(int x , vector<int> bag){
00106         for( uint i=0 ; i < bag.size(); i++ ){
00107           if(x == bag[i]) return true ;
00108         }
00109         return false ;
00110 }
00111 
00112 ////////////////////////////////////////////////////////
00113 ///// simply generates a sequence of digits displayed on random places on the screen
00114 ////////////////////////////////////////////////////////
00115 string digitMemorizationTask(uint l, int maxForDigit=10 ,float wp = 1.0f, float hp = 1.0f, int displayFrame = 10 , int delayFrame = 30 ){
00116   d->clearScreen() ;
00117   vector<int> pickedones = vector<int>() ;
00118   string test = string("") ;
00119   string tp = string("") ;
00120   int widthRange = (int)((float)(d->getWidth()) * wp);
00121   int heightRange = (int)((float)(d->getHeight()) * hp);
00122   int wMargin = (d->getWidth() - widthRange)/2 ;
00123   int hMargin = (d->getHeight() - heightRange) / 2 ;
00124   for(uint i = 0 ; i < l ; i++){
00125     int nd;
00126     do{ nd= rand()% maxForDigit ; }while(itIsInThere(nd,pickedones) && pickedones.size() < 11) ;
00127     pickedones.push_back(nd);
00128     tp = stringify(nd) ;
00129     test += tp ;
00130   }
00131 
00132         int x = (rand()%widthRange)  + wMargin;
00133         int y = (rand()%heightRange ) + hMargin ;
00134         d->displayText(test,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ;
00135         d->waitFrames(displayFrame*l) ;
00136         d->clearScreen() ;
00137         return test ;
00138 }
00139 
00140 
00141 ////////////////////////////////////////////////////////
00142 ///////this will change the order of elements in a vector to a random order
00143 ////////////////////////////////////////////////////////
00144 void scramble(vector<string>& v){
00145         vector<string> tv = vector<string>() ;
00146         while(v.size()>0){
00147                 tv.push_back(v[0]);
00148                 v.erase(v.begin());
00149         }
00150         int i = 0 ;
00151         while(tv.size()>0){
00152                 i = rand()%tv.size() ;
00153                 v.push_back(tv[i]);
00154                 tv.erase(tv.begin()+i);
00155         }
00156 }
00157 
00158 
00159 ////////////////////////////////////////////////////////////////
00160 ////This is our button factory
00161 ////////////////////////////////////////////////////////////////
00162 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){
00163   Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS);
00164   textIm.clear(bgcolor);
00165   writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor);
00166   SDL_Surface *surf = d->makeBlittableSurface(textIm , true);
00167   Uint32 bc = d->getUint32color(bordercolor);
00168   drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border);
00169   SDL_Surface* blank =getABlankSurface(size.i , size.j);
00170   SDL_Rect clip;
00171   clip.x = 0 ;
00172   clip.y = 0 ;
00173   clip.w = size.i ;
00174   clip.h = size.j ;
00175   apply_surface(0,0,*surf,*blank,clip);
00176   dumpSurface(surf) ;
00177   return blank ;
00178 }
00179 
00180 ////////////////////////////////////////////////////////////////////////
00181 ////This is the function for creating the keypad, in fact it generates
00182 ////12 buttons and associates the actions to the region for each button
00183 ////////////////////////////////////////////////////////////////////////
00184 
00185 SDL_Surface* getKeyPad(map<string , SDL_Rect>& buttmap){
00186   SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3);
00187   SDL_Rect clip;
00188   clip.x=0;
00189   clip.y=0;
00190   clip.w= pad->w / 3 ;
00191   clip.h = pad->h / 4 ;
00192   //keys for 1 to 9
00193   for( int i = 1 ; i < 10 ; i++){
00194     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);
00195     SDL_Rect cl ;
00196     cl.x = ((i-1)%3)*(pad->w)/3 ; cl.y= ((i-1)/3)*((pad->h)/4) ;
00197     cl.w = clip.w ;
00198     cl.h = clip.h ;
00199     apply_surface( cl.x , cl.y ,*but,*pad,clip);
00200     buttmap[stringify(i)] = cl ;
00201     dumpSurface(but);
00202   }
00203   SDL_Rect cl1 ;
00204   cl1.x = 0 ; cl1.y= 3*((pad->h)/4) ;
00205   cl1.w = clip.w ;
00206   cl1.h = clip.h ;
00207   buttmap["z"] = cl1 ;
00208   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);
00209   apply_surface(0, 3*((pad->h)/4),*but,*pad,clip);
00210   dumpSurface(but);
00211   SDL_Rect cl2 ;
00212   cl2.x = (pad->w)/3 ; cl2.y= 3*((pad->h)/4) ;
00213   cl2.w = clip.w ;
00214   cl2.h = clip.h ;
00215   buttmap["0"] = cl2 ;
00216   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);
00217   apply_surface((pad->w)/3, 3*((pad->h)/4),*but,*pad,clip);
00218   dumpSurface(but);
00219   SDL_Rect cl3 ;
00220   cl3.x = 2*(pad->w)/3 ; cl3.y= 3*((pad->h)/4) ;
00221   cl3.w = clip.w ;
00222   cl3.h = clip.h ;
00223   buttmap["o"] = cl3 ;
00224   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);
00225   apply_surface(2*(pad->w)/3, 3*((pad->h)/4),*but,*pad,clip);
00226   dumpSurface(but);
00227         return pad ;
00228 }
00229 
00230 
00231 
00232 
00233 ///////////////////////////////////////////////////////////////////////////
00234 /////this function listens to mouse clicks and then finds the region of the screen
00235 /////associated with the action, buttmap is the map of the region, offset is the offset of
00236 /////buttons
00237 ///////////////////////////////////////////////////////////////////////////
00238 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){
00239         int quit = 0 ;
00240         string s ;
00241         SDL_Event event ;
00242         while( quit!=2 ){
00243                  while( SDL_PollEvent( &event ) ) {
00244                    if(event.type == SDL_MOUSEBUTTONDOWN  && event.button.button == SDL_BUTTON_LEFT ){
00245                      for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){
00246                        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) {
00247                          quit = 2 ;
00248                          s = it->first ;
00249                          break;
00250                        }
00251 
00252                      }
00253                    }
00254 
00255                 }
00256         }
00257         return s ;
00258 
00259 }
00260 
00261 
00262 ////////////////////////////////////////////////////
00263 ////This function creates a virtual keypad, creates a map of buttons
00264 ////and their representation area and listens to the button press and at
00265 ////the end returns the keyed digits
00266 ////////////////////////////////////////////////////
00267 string getDigitSequenceFromSubject(uint maxl = 7 ){
00268         d->showCursor(true) ;
00269         //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect
00270         map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>();
00271         //now let's get the keypad surface while we get the actions map to regions
00272         SDL_Surface * keypad = getKeyPad(*buttmap);
00273         //this will be the offset of displaying the keypad on the screen
00274         SDL_Rect offset ;
00275         offset.x = (d->getWidth() - keypad->w) /2;
00276         offset.y = (d-> getHeight() - keypad->h) /2;
00277         //now let's display the keypad
00278         d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true);
00279         //this will hold the final string keyed be the subject
00280         string p = string("") ;
00281         //this is a temporary string holding the last action related to the pressed key
00282         string tp = string("");
00283         //now let's record subject's key press
00284         while( tp.compare("o")!=0 ){
00285                 //this button is actually the display for the current string
00286                 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) ;
00287                 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ;
00288                 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ;
00289                 //now let's listen to button events
00290                 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ;
00291                 dumpSurface(dp) ;
00292                 if(tp.compare("z")==0 && p.size()>=0 ) {
00293                         if (p.size()>0) p = p.substr(0,p.size()-1) ;
00294                 }else{
00295                   if(p.size() < maxl && tp.compare("o")!=0) {
00296                                 p +=tp ;
00297                         }
00298 
00299                 }
00300 
00301         }
00302         buttmap = 0 ;
00303         dumpSurface(keypad) ;
00304         d->clearScreen() ;
00305         return p ;
00306 
00307 }
00308 
00309 
00310 
00311 ////////////////////////////////////////////////////////////////////
00312 //// gets a string as the argument and returns a string composed of
00313 //// characters of the first string sorted in the ascending order
00314 ///////////////////////////////////////////////////////////////////
00315 string ascSort(string st)
00316 {
00317   string res = "" ;
00318   vector<string> v = vector<string>();
00319   for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ;
00320 
00321   std::sort(v.begin(), v.end());
00322 
00323   for ( uint i = 0 ; i < v.size() ; i++ ){
00324     res += v[i] ;
00325   }
00326   return res;
00327 }
00328 
00329 ////////////////////////////////////////////////////////////////////
00330 //// gets a string as the argument and returns a string composed of
00331 //// characters of the first string sorted in the descending order
00332 ///////////////////////////////////////////////////////////////////
00333 string desSort(string st)
00334 {
00335   string res = "" ;
00336   vector<string> v = vector<string>();
00337   for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ;
00338   std::sort(v.begin(), v.end());
00339   std::reverse(v.begin(), v.end());
00340   for ( uint i = 0 ; i < v.size() ; i++ ){
00341     res += v[i] ;
00342   }
00343   return res;
00344 }
00345 
00346 ///////////////////////////////////////////////////////////////
00347 //////gets the test string, answer and the mode and identifies if
00348 //////the answer matches the thing it should be, mode=0 checks if
00349 //////if the answer and test string simply the same, mode=1 matches
00350 //////the answer against the ascending sorted string of the test string
00351 //////mode=2 compares the answer against the descending sorted of
00352 //////the test string
00353 ///////////////////////////////////////////////////////////////
00354 bool isAnswerCorrect(string test , string answer , int mode){
00355 
00356   if(mode == 0 && answer.compare(test)==0) return true ;
00357 
00358   if(mode == 1 && answer.compare(ascSort(test))==0) return true ;
00359 
00360   if(mode == 2 && answer.compare(desSort(test))==0) return true ;
00361 
00362   return false;
00363 }
00364 
00365 
00366 
00367 int addArgument(const string st,const string delim="="){
00368         int i = st.find(delim) ;
00369         argMap[st.substr(0,i)] = st.substr(i+1);
00370 
00371         return 0 ;
00372 }
00373 
00374 std::string getArgumentValue(string arg){
00375         return argMap[arg] ;
00376 }
00377 
00378 std::string getUsageComment(){
00379 
00380         string com = string("\nlist of arguments : \n");
00381 
00382         com += "\ndelay-interval=[>1]:[>1] (the interval for random delay after stroop task) {default=10}\n";
00383         com += "\nfixation-blink=[y/n] (show the blink for fixation after stroop task or no) {defaule y}\n";
00384         com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ;
00385         com += "\nmemo=[a_string_without_white_space]\n";
00386         com += "\nmode=[1] {default = 1}\n";
00387         com += "\nstart-digit-size=[<1](number of words in the stroop task){default=6} \n" ;
00388         com += "\nmax-digit-size=[>6](the maximum digits that will be used for test){default=10} \n";
00389         com += "\naccuracy-threshold=[>0 and <1.0] (the threshold for accuracy){default=.85}\n" ;
00390         com += "\nsubject=[subject_name] \n" ;
00391         com += "\ntest-rounds=[>1] (number of tests for each string size) {default=10}\n";
00392         com += "\ndigit-onset=[>1] (number of frames that the digit will remain onset for each digit){default=10}\n";
00393         com += "\ndigit-offset=[>1](number of frames that between two consequent digit onset){default=30}\n";
00394         com += "\nwidth-range=[1..100](the percentage of the width of screen for showing the digits){default=100}\n";
00395         com += "\nheight-range=[1..100](the percentage of the height of screen for showing the digits){default=100}\n";
00396         return com ;
00397 }
00398 
00399 
00400 extern "C" int main(const int argc, char** argv)
00401 {
00402 
00403           MYLOGVERB = LOG_INFO;  // suppress debug messages
00404         //let's push the initial value for the parameters
00405         argMap["mode"] = "1" ;
00406         argMap["logfile"]="psycho-digit-concurrent.psy" ;
00407         argMap["start-digit-size"]="6" ;
00408         argMap["max-digit-size"]="10" ;
00409         argMap["accuracy-threshold"]=".85";
00410         argMap["test-rounds"]="10";
00411         argMap["delay-interval"]="60:160" ;
00412         argMap["subject"]="" ;
00413         argMap["memo"]="" ;
00414         argMap["fixation-blink"]="y" ;
00415         argMap["digit-onset"]="10" ;
00416         argMap["digit-offset"]="30" ;
00417         argMap["width-range"]="100" ;
00418         argMap["height-range"]="100" ;
00419 
00420         manager.addSubComponent(d);
00421         nub::soft_ref<EventLog> el(new EventLog(manager));
00422         manager.addSubComponent(el);
00423         d->setEventLog(el);
00424 
00425         if (manager.parseCommandLine(argc, argv,
00426             "at least one argument needed", 1, -1)==false){
00427                     cout<<getUsageComment()<<endl;
00428                         return(1);
00429             }
00430 
00431         for(uint i = 0 ; i < manager.numExtraArgs() ; i++){
00432                 addArgument(manager.getExtraArg(i),std::string("=")) ;
00433         }
00434 
00435         manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]);
00436 
00437 
00438 
00439   // let's get all our ModelComponent instances started:
00440           manager.start();
00441         for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ;
00442   // let's display an ISCAN calibration grid:
00443           d->clearScreen();
00444           d->displayISCANcalib();
00445           d->waitForMouseClick();
00446 
00447   // let's do an eye tracker calibration:
00448           d->displayText("Here the experiment starts! click to start!");
00449           d->waitForMouseClick();
00450           d->clearScreen();
00451         //let's see in what mode the user like to run the program
00452         int mode = atoi(argMap["mode"].c_str()) ;
00453         float accuracyThreshold = atof(argMap["accuracy-threshold"].c_str());
00454         //mode 1 and 2 inlude single memorization task, 1 for just memorization and 2 for dynamic memorization
00455         //in dynamic memorization the subject has to sort the string in ascending order when the last digit is even
00456         //and descending order if the last digit is odd
00457         if(mode==1 || true){
00458           int numOfTests = atoi(argMap["test-rounds"].c_str()) ;
00459           int startStringSize = atoi(argMap["start-digit-size"].c_str()) ;
00460           int maxStringSize = atoi(argMap["max-digit-size"].c_str());
00461           string::size_type position = argMap["delay-interval"].find(":");
00462           int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ;
00463           int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ;
00464           float wr = ((float)(atoi(argMap["width-range"].c_str())))/100.0f;
00465           float hr = ((float)(atoi(argMap["height-range"].c_str())))/100.0f;
00466           int onsetDel = atoi(argMap["digit-onset"].c_str()) ;
00467           int offsetDel = atoi(argMap["digit-offset"].c_str()) ;
00468           float accuracy=1.0f;
00469           int currentStringSize = startStringSize ;
00470                 while(accuracy>accuracyThreshold && currentStringSize <= maxStringSize){
00471 
00472                         int correctCount = 0 ;
00473                         for(int i = 0 ; i < numOfTests ; i++){
00474                         d->pushEvent("**************************************") ;
00475                         d->showCursor(true);
00476                         d->displayText("click one of the  mouse buttons to start!");
00477                         d->waitForMouseClick() ;
00478                         d->showCursor(false);
00479                         // d->clearScreen();
00480                         string  testString ;
00481                         testString = digitMemorizationTask(currentStringSize, 10 , wr , hr ,  onsetDel ,  offsetDel) ;
00482                         //
00483                         d->pushEvent("the memorization sequence is : "+testString) ;
00484                         d->waitFrames((rand()%(maxDel - minDel)) +minDel);
00485                         string  answer = getDigitSequenceFromSubject(testString.size());
00486                         bool af = false ;
00487                         af = isAnswerCorrect(testString,answer,0);
00488                         d->pushEvent("subject keyed : "+answer);
00489                         if(af){
00490                                 d->pushEvent("answer was correct");
00491                                 correctCount++ ;
00492                         }else{
00493                                 d->pushEvent("answer was incorrect");
00494                         }
00495 
00496                         }
00497                         accuracy = float(correctCount)/float(numOfTests);
00498                         d->pushEvent("string size:" + stringify(currentStringSize)+"  accuracy :"+stringify(accuracy));
00499                         currentStringSize++ ;
00500 
00501                 }
00502                 d->pushEvent("the appropriate test size :" + stringify((currentStringSize-1)));
00503         }
00504 
00505 
00506 
00507           d->clearScreen();
00508           d->displayText("Experiment complete. Thank you!");
00509           d->waitForMouseClick();
00510 
00511           // stop all our ModelComponents
00512           manager.stop();
00513 
00514 
00515           // all done!
00516           return 0;
00517 }
00518 
00519 #endif // INVT_HAVE_LIBSDL_IMAGE
00520 
Generated on Sun May 8 08:40:08 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3