00001 /*!@file AppPsycho/psycho-text.C Psychophysics display of text. Text 00002 elements are read in from a text file. Elements that require a 00003 response should be marked with a #at the beginning of the 00004 sentence. */ 00005 00006 // //////////////////////////////////////////////////////////////////// // 00007 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00008 // University of Southern California (USC) and the iLab at USC. // 00009 // See http://iLab.usc.edu for information about this project. // 00010 // //////////////////////////////////////////////////////////////////// // 00011 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00012 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00013 // in Visual Environments, and Applications'' by Christof Koch and // 00014 // Laurent Itti, California Institute of Technology, 2001 (patent // 00015 // pending; application number 09/912,225 filed July 23, 2001; see // 00016 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00017 // //////////////////////////////////////////////////////////////////// // 00018 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00019 // // 00020 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00021 // redistribute it and/or modify it under the terms of the GNU General // 00022 // Public License as published by the Free Software Foundation; either // 00023 // version 2 of the License, or (at your option) any later version. // 00024 // // 00025 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00026 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00027 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00028 // PURPOSE. See the GNU General Public License for more details. // 00029 // // 00030 // You should have received a copy of the GNU General Public License // 00031 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00032 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00033 // Boston, MA 02111-1307 USA. // 00034 // //////////////////////////////////////////////////////////////////// // 00035 // 00036 // Primary maintainer for this file: David J. Berg <dberg@usc.edu> 00037 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-text.C $ 00038 00039 #include "Component/ModelManager.H" 00040 #include "Image/Image.H" 00041 #include "Image/DrawOps.H" 00042 #include "Image/SimpleFont.H" 00043 #include "Psycho/PsychoDisplay.H" 00044 #include "Psycho/EyeTrackerConfigurator.H" 00045 #include "Psycho/EyeTracker.H" 00046 #include "Psycho/PsychoOpts.H" 00047 #include "Component/EventLog.H" 00048 #include "Component/ComponentOpts.H" 00049 #include "Util/Types.H" 00050 #include "Util/StringConversions.H" 00051 #include "Util/StringUtil.H" 00052 00053 #include <fstream> 00054 00055 #define HDEG 54.9 00056 // ###################################################################### 00057 extern "C" int main(const int argc, char** argv) 00058 { 00059 MYLOGVERB = LOG_INFO; // suppress debug messages 00060 00061 // Instantiate a ModelManager: 00062 ModelManager manager("Psycho Text"); 00063 00064 // Instantiate our various ModelComponents: 00065 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00066 manager.addSubComponent(d); 00067 00068 nub::soft_ref<EyeTrackerConfigurator> 00069 etc(new EyeTrackerConfigurator(manager)); 00070 manager.addSubComponent(etc); 00071 00072 nub::soft_ref<EventLog> el(new EventLog(manager)); 00073 manager.addSubComponent(el); 00074 00075 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy"); 00076 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00077 00078 // Parse command-line: 00079 if (manager.parseCommandLine(argc, argv, 00080 "<textfile> visual-angle-of-single-character", 00081 1, 2)==false) 00082 return(1); 00083 double fontsize = fromStr<double>(manager.getExtraArg(1)); 00084 00085 // hook our various babies up and do post-command-line configs: 00086 nub::soft_ref<EyeTracker> et = etc->getET(); 00087 d->setEyeTracker(et); 00088 d->setEventLog(el); 00089 et->setEventLog(el); 00090 00091 // let's get all our ModelComponent instances started: 00092 manager.start(); 00093 00094 // let's do an eye tracker calibration: 00095 et->calibrate(d); 00096 00097 d->clearScreen(); 00098 d->displayText("<space> for random order, other key for ordered play."); 00099 int c = d->waitForKey(); 00100 d->clearScreen(); 00101 00102 // create an image frame for each sentence in our text file and store 00103 // it in a vector before we start the experiment, then we can just 00104 // present each frame like in psycho still 00105 // 00106 //First read the text file and all the sentences 00107 //load our file 00108 std::ifstream *itsFile; 00109 itsFile = new std::ifstream(manager.getExtraArg(0).c_str()); 00110 00111 //error if no file 00112 if (itsFile->is_open() == false) 00113 LFATAL("Cannot open '%s' for reading",manager.getExtraArg(0).c_str()); 00114 00115 //some storage variables 00116 std::string line; 00117 std::vector<std::vector<std::string> > lines; 00118 std::vector<uint> itsType; 00119 uint scount = 0; 00120 00121 //loop through lines of file 00122 while (!itsFile->eof()) 00123 { 00124 getline(*itsFile, line); 00125 00126 std::vector<std::string> temp; 00127 //store the sentence and type (question or statement) 00128 if (line[0] == '#')//question 00129 { 00130 line.erase(0,1); 00131 temp.push_back(line); 00132 lines.push_back(temp); 00133 itsType.push_back(1); 00134 scount++; 00135 } 00136 else if (line[0] =='!')//sentence 00137 { 00138 line.erase(0,1); 00139 temp.push_back(line); 00140 lines.push_back(temp); 00141 itsType.push_back(0); 00142 scount++; 00143 } 00144 else 00145 { 00146 if (line.size() > 1) 00147 { 00148 scount--; 00149 lines[scount].push_back(line); 00150 scount++; 00151 } 00152 } 00153 } 00154 itsFile->close(); 00155 00156 //now we have stored all of our sentences, lets create our images 00157 int w = d->getWidth();//width and height of SDL surface 00158 int h = d->getHeight(); 00159 uint fontwidth = uint(fontsize * w / HDEG); 00160 SimpleFont fnt = SimpleFont::fixedMaxWidth(fontwidth); //font 00161 std::vector<Image<PixRGB<byte> > > itsSImage; //store sentences 00162 std::vector<Image<PixRGB<byte> > > itsQImage; //store images 00163 00164 for (uint i = 0; i < lines.size(); i++) 00165 { 00166 int space = 0; 00167 int hanchor = int(h/2) - int(fnt.h()/2); 00168 Image<PixRGB<byte> > timage(w,h,ZEROS); 00169 timage += d->getGrey(); 00170 00171 for (uint j = 0; j < lines[i].size(); j++) 00172 { 00173 if (j < 1) 00174 space = int( double(w - fnt.w() * lines[i][j].size()) / 2.0 ); 00175 if (j > 0) 00176 hanchor = hanchor + fnt.h(); 00177 Point2D<int> tanchor(space, hanchor); 00178 writeText(timage,tanchor,lines[i][j].c_str(), 00179 PixRGB<byte>(0,0,0), 00180 d->getGrey(), 00181 fnt); 00182 } 00183 if (itsType[i] == 0) 00184 itsSImage.push_back(timage); 00185 else 00186 itsQImage.push_back(timage); 00187 } 00188 00189 uint count = scount/2; 00190 int indexS[count]; 00191 int indexQ[count]; 00192 for (uint i = 0; i < count; i ++) 00193 { 00194 indexS[i] = i; 00195 indexQ[i] = i; 00196 } 00197 00198 if (c == ' ') 00199 { 00200 LINFO("Randomizing images..."); 00201 randShuffle(indexS, count); 00202 randShuffle(indexQ, count); 00203 } 00204 00205 bool nextSentence = true; 00206 uint ii =0; 00207 // main loop: 00208 for (uint i = 0; i < scount; i ++) 00209 { 00210 // load up the frame and show a fixation cross on a blank screen: 00211 d->clearScreen(); 00212 Image< PixRGB<byte> > image; 00213 if (nextSentence) 00214 image = itsSImage[indexS[ii]]; 00215 else 00216 image = itsQImage[indexQ[ii]]; 00217 00218 SDL_Surface *surf = d->makeBlittableSurface(image, true); 00219 00220 if (nextSentence) 00221 LINFO("sentence '%d' ready.", ii); 00222 else 00223 LINFO("question '%d' ready.", ii); 00224 d->displayFixation(); 00225 00226 // ready to go whenever the user is ready: 00227 d->waitForKey(); 00228 d->waitNextRequestedVsync(false, true); 00229 00230 if (nextSentence) 00231 d->pushEvent(std::string("===== Showing Sentence: ") + 00232 toStr<int>(indexS[ii]) + " ====="); 00233 else 00234 d->pushEvent(std::string("===== Showing Question: ") + 00235 toStr<int>(indexQ[ii]) + " ====="); 00236 00237 nextSentence = !nextSentence; 00238 if (i%2 != 0) 00239 ii++; 00240 00241 // start the eye tracker: 00242 et->track(true); 00243 00244 // blink the fixation: 00245 d->displayFixationBlink(); 00246 00247 // show the image: 00248 d->displaySurface(surf, -2); 00249 00250 // wait for key: 00251 c = d->waitForKey(); 00252 00253 // free the image: 00254 SDL_FreeSurface(surf); 00255 00256 // make sure display if off before we stop the tracker: 00257 d->clearScreen(); 00258 00259 // stop the eye tracker: 00260 usleep(50000); 00261 et->track(false); 00262 } 00263 00264 d->clearScreen(); 00265 d->displayText("Experiment complete. Thank you!"); 00266 d->waitForKey(); 00267 00268 // stop all our ModelComponents 00269 manager.stop(); 00270 00271 // all done! 00272 return 0; 00273 } 00274 00275 // ###################################################################### 00276 /* So things look consistent in everyone's emacs... */ 00277 /* Local Variables: */ 00278 /* indent-tabs-mode: nil */ 00279 /* End: */