00001 /*!@file AppPsycho/psycho-recall.C Test recall for objects in scenes */ 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-recall.C $ 00035 // $Id: psycho-recall.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #include "Component/ModelManager.H" 00039 #include "Component/EventLog.H" 00040 #include "Image/Image.H" 00041 #include "Image/CutPaste.H" 00042 #include "Image/DrawOps.H" 00043 #include "Image/ImageSet.H" 00044 #include "Image/ShapeOps.H" 00045 #include "Psycho/PsychoDisplay.H" 00046 #include "Psycho/EyeTrackerConfigurator.H" 00047 #include "Psycho/EyeTracker.H" 00048 #include "Psycho/PsychoOpts.H" 00049 #include "Component/ComponentOpts.H" 00050 #include "GUI/GUIOpts.H" 00051 #include "Raster/Raster.H" 00052 #include "Util/Types.H" 00053 #include "Util/StringUtil.H" 00054 #include "Util/MathFunctions.H" 00055 #include <fstream> 00056 00057 //! Test recall for objects in scenes 00058 /*! This shows an image to be inspected under eye-tracking. Then a 00059 series of objects. For each object, the user makes a decision as to 00060 whether it was in the scene or not. Input file format should be: 00061 00062 image1.png obj1.png obj2.png ... objN.png 00063 image2.png obj1.png ... objK.png 00064 ... 00065 00066 */ 00067 00068 // ###################################################################### 00069 static int submain(const int argc, char** argv) 00070 { 00071 MYLOGVERB = LOG_INFO; // suppress debug messages 00072 00073 // Instantiate a ModelManager: 00074 ModelManager manager("Psychophysics Recall"); 00075 00076 // Instantiate our various ModelComponents: 00077 nub::soft_ref<EventLog> el(new EventLog(manager)); 00078 manager.addSubComponent(el); 00079 00080 nub::soft_ref<EyeTrackerConfigurator> 00081 etc(new EyeTrackerConfigurator(manager)); 00082 manager.addSubComponent(etc); 00083 00084 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00085 manager.addSubComponent(d); 00086 00087 // set a default display size: 00088 manager.exportOptions(MC_RECURSE); 00089 manager.setOptionValString(&OPT_SDLdisplayDims, "1920x1080"); 00090 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy"); 00091 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00092 00093 // Parse command-line: 00094 if (manager.parseCommandLine(argc, argv, "<fileList>", 1, -1) == false) 00095 return(1); 00096 00097 // hook our various babies up and do post-command-line configs: 00098 nub::soft_ref<EyeTracker> et = etc->getET(); 00099 d->setEyeTracker(et); 00100 d->setEventLog(el); 00101 et->setEventLog(el); 00102 initRandomNumbers(); 00103 00104 // let's get all our ModelComponent instances started: 00105 manager.start(); 00106 00107 // get the list of images 00108 std::ifstream file(manager.getExtraArg(0).c_str()); 00109 if (file == 0) LFATAL("Couldn't open file: '%s'", 00110 manager.getExtraArg(0).c_str()); 00111 00112 // load up all the image descriptions: 00113 std::string line; 00114 std::vector<std::string> lines; 00115 while(getline(file, line)) lines.push_back(line); 00116 00117 // create a randomized index: 00118 uint *idx = new uint[lines.size()]; 00119 for (uint i = 0; i < lines.size(); i ++) idx[i] = i; 00120 randShuffle(idx, lines.size()); 00121 LINFO("Randomized %"ZU" trials.", lines.size()); 00122 00123 // let's display an ISCAN calibration grid: 00124 d->clearScreen(); 00125 d->displayISCANcalib(); 00126 d->waitForKey(); 00127 00128 // let's do an eye tracker calibration: 00129 d->displayText("<SPACE> to calibrate; other key to skip"); 00130 int c = d->waitForKey(); 00131 if (c == ' ') d->displayEyeTrackerCalibration(); 00132 d->clearScreen(); 00133 d->displayText("<SPACE> To Begin Experiment"); 00134 c = d->waitForKey(); 00135 00136 00137 for (uint ii = 0; ii < lines.size(); ++ii) 00138 { 00139 std::vector<std::string> tokens; 00140 split(lines[idx[ii]], " \t", std::back_inserter(tokens)); 00141 if (tokens.size() < 2) 00142 LFATAL("Need at least one image and one object per line: %s", 00143 lines[idx[ii]].c_str()); 00144 00145 // pick a random display order for the objects: 00146 uint *ii = new uint[tokens.size()-1]; 00147 for (uint i = 0; i < tokens.size()-1; ++i) ii[i] = i+1; 00148 randShuffle(ii, tokens.size()-1); 00149 00150 00151 // load up the two image and show a fixation cross on a blank screen: 00152 d->clearScreen(); 00153 LINFO("Loading '%s'...", tokens[0].c_str()); 00154 Image< PixRGB<byte> > ima = Raster::ReadRGB(tokens[0]); 00155 00156 ImageSet< PixRGB<byte> > objects; 00157 for (uint i = 0; i < tokens.size()-1; ++i) 00158 { 00159 LINFO("Loading object %u/%"ZU": %s", i+1, 00160 tokens.size()-1, tokens[i].c_str()); 00161 Image< PixRGB<byte> > obj = Raster::ReadRGB(tokens[ii[i]]); 00162 objects.push_back(obj); 00163 } 00164 00165 // Prepare to display the image, and a random mask: 00166 Image< PixRGB<byte> > image(d->getDims(), NO_INIT); 00167 inplaceEmbed(image, ima, Rectangle(Point2D<int>(0, 0), image.getDims()), 00168 d->getGrey(), true); 00169 SDL_Surface *surf = d->makeBlittableSurface(image, true); 00170 00171 Image< PixRGB<byte> > mask(d->getWidth()/8, d->getHeight()/8, NO_INIT); 00172 for (int i = 0; i < mask.getSize(); i ++) 00173 mask.setVal(i, PixRGB<byte>(byte(randomUpToNotIncluding(256)), 00174 byte(randomUpToNotIncluding(256)), 00175 byte(randomUpToNotIncluding(256)))); 00176 mask = zoomXY(mask, 8, 8); 00177 SDL_Surface *msurf = d->makeBlittableSurface(mask, true); 00178 LINFO("%s ready.", tokens[0].c_str()); 00179 00180 // ready to go whenever the user is ready: 00181 d->displayFixation(); 00182 d->waitForKey(); 00183 d->pushEvent(std::string("===== Showing image: ") + 00184 tokens[0] + " ====="); 00185 00186 // start the eye tracker: 00187 et->track(true); 00188 00189 // blink the fixation: 00190 d->displayFixationBlink(); 00191 00192 // show the image: 00193 d->displaySurface(surf, -2); 00194 00195 // fixed presentation time: 00196 usleep(2000000); 00197 00198 // Display mask: 00199 d->displaySurface(msurf, -2); 00200 usleep(150000); 00201 00202 // make sure display if off before we stop the tracker: 00203 d->clearScreen(); 00204 00205 // stop the eye tracker: 00206 usleep(50000); 00207 et->track(false); 00208 SDL_FreeSurface(surf); 00209 SDL_FreeSurface(msurf); 00210 00211 // Allow the user to mark some objects: 00212 for (uint i = 0; i < tokens.size()-1; ++i) 00213 { 00214 // create an image with the object: 00215 Image< PixRGB<byte> > obj(d->getDims(), NO_INIT); 00216 obj.clear(d->getGrey()); 00217 inplacePaste(obj, objects[i], 00218 Point2D<int>((d->getWidth() - objects[i].getWidth())/2, 00219 (d->getHeight() - objects[i].getHeight())/2)); 00220 // show the object: 00221 SDL_Surface *surf2 = d->makeBlittableSurface(obj, true); 00222 d->displaySurface(surf2, -2); 00223 00224 int c = d->waitForKey(); 00225 d->pushEvent(sformat("===== Object %s / %u: '%c' (%d) =====", 00226 tokens[ii[i]].c_str(), i, c, c)); 00227 SDL_FreeSurface(surf2); 00228 } 00229 00230 // get ready for next one or end: 00231 d->clearScreen(); 00232 delete [] ii; 00233 } 00234 00235 d->clearScreen(); 00236 d->displayText("Experiment complete. Thank you!"); 00237 d->waitForKey(); 00238 00239 // stop all our ModelComponents 00240 manager.stop(); 00241 00242 delete [] idx; 00243 00244 // all done! 00245 return 0; 00246 } 00247 00248 // ###################################################################### 00249 extern "C" int main(const int argc, char** argv) 00250 { 00251 // simple wrapper around submain() to catch exceptions (because we 00252 // want to allow PsychoDisplay to shut down cleanly; otherwise if we 00253 // abort while SDL is in fullscreen mode, the X server won't return 00254 // to its original resolution) 00255 try 00256 { 00257 return submain(argc, argv); 00258 } 00259 catch (...) 00260 { 00261 REPORT_CURRENT_EXCEPTION; 00262 } 00263 00264 return 1; 00265 } 00266 00267 // ###################################################################### 00268 /* So things look consistent in everyone's emacs... */ 00269 /* Local Variables: */ 00270 /* indent-tabs-mode: nil */ 00271 /* End: */