psycho-web.C

Go to the documentation of this file.
00001 /*!@file AppPsycho/psycho-web.C displays a text message, and then
00002    opens a web page where the subjects eyes are tracked., afterwords,
00003    displays a question? The web browser must be opened and
00004    appropriately sized first. */
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-web.C $
00038 
00039 #include "Component/ModelManager.H"
00040 #include "Image/Image.H"
00041 #include "Image/DrawOps.H"
00042 #include "Image/SimpleFont.H"
00043 #include "Raster/Raster.H"
00044 #include "Psycho/PsychoDisplay.H"
00045 #include "Psycho/EyeTrackerConfigurator.H"
00046 #include "Psycho/EyeTracker.H"
00047 #include "Psycho/PsychoOpts.H"
00048 #include "Component/EventLog.H"
00049 #include "Component/ComponentOpts.H"
00050 #include "Util/Types.H"
00051 #include "Util/StringConversions.H"
00052 #include "Util/StringUtil.H"
00053 #include "rutz/pipe.h"
00054 
00055 #include <fstream>
00056 #include <X11/X.h>
00057 #include <X11/Xlib.h>
00058 #include <X11/Intrinsic.h>
00059 #include <X11/StringDefs.h>
00060 #include <X11/Xutil.h>
00061 #include <X11/Shell.h>
00062 
00063 #define HDEG 54.9
00064 #define KEY_BUFF_SIZE 256
00065 
00066 
00067 // #####################################################################
00068 // some code to collect clicks from all xwindows
00069 // ######################################################################
00070 void TranslateKeyCode(XEvent *ev, char* key_buff)
00071 {
00072   int count;
00073   KeySym ks;
00074 
00075   if (ev)
00076    {
00077      count = XLookupString((XKeyEvent *)ev, key_buff, KEY_BUFF_SIZE, &ks,NULL);
00078      key_buff[count] = '\0';
00079 
00080      if (count == 0)
00081        {
00082          char *tmp = key_buff = XKeysymToString(ks);
00083          if (tmp)
00084            strcpy(key_buff, tmp);
00085          else
00086            key_buff[0] = '\0';
00087        }
00088    }
00089   else
00090     key_buff[0] = '\0';
00091 }
00092 
00093 // ######################################################################
00094 void snoop_all_windows(Window root, unsigned long type, Display* d)
00095 {
00096   static int level = 0;
00097   Window parent, *children;
00098   unsigned int nchildren;
00099   int stat;
00100 
00101   level++;
00102 
00103   stat = XQueryTree(d, root, &root, &parent, &children, &nchildren);
00104   if (stat == FALSE)
00105    {
00106      LINFO("Can't query window tree...\n");
00107      return;
00108    }
00109 
00110   if (nchildren == 0)
00111     return;
00112 
00113   /* For a more drastic inidication of the problem being exploited
00114    * here, you can change these calls to XSelectInput() to something
00115    * like XClearWindow(d, children[i]) or if you want to be real
00116    * nasty, do XKillWindow(d, children[i]).  Of course if you do that,
00117    * then you'll want to remove the loop in main().
00118    *
00119    * The whole point of this exercise being that I shouldn't be
00120    * allowed to manipulate resources which do not belong to me.
00121    */
00122   XSelectInput(d, root, type);
00123 
00124   for(uint i=0; i < nchildren; i++)
00125    {
00126      XSelectInput(d, children[i], type);
00127      snoop_all_windows(children[i], type, d);
00128    }
00129 
00130   XFree((char *)children);
00131 }
00132 
00133 // ######################################################################
00134 void waitXKeyPress(char *hostname)
00135 {
00136   XEvent xev;
00137   char key_buff[KEY_BUFF_SIZE];
00138   key_buff[0] = '\0';
00139 
00140   Display *d = NULL;
00141   d = XOpenDisplay(hostname);
00142   if (d == NULL)
00143    {
00144      LFATAL("Blah, can't open display: %s\n", hostname);
00145    }
00146 
00147   snoop_all_windows(DefaultRootWindow(d), KeyPressMask, d);
00148 
00149   while(1)
00150    {
00151      XNextEvent(d, &xev);
00152      TranslateKeyCode(&xev, key_buff);
00153      LINFO("polling");
00154      if (strlen(key_buff)>0)
00155        break;
00156    }
00157 }
00158 
00159 // ######################################################################
00160 extern "C" int main(const int argc, char** argv)
00161 {
00162   MYLOGVERB = LOG_INFO;  // suppress debug messages
00163   // Instantiate a ModelManager:
00164   ModelManager manager("Psycho Text");
00165 
00166   // Instantiate our various ModelComponents:
00167   nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00168   manager.addSubComponent(d);
00169 
00170   nub::soft_ref<EyeTrackerConfigurator>
00171     etc(new EyeTrackerConfigurator(manager));
00172   manager.addSubComponent(etc);
00173 
00174   nub::soft_ref<EventLog> el(new EventLog(manager));
00175   manager.addSubComponent(el);
00176 
00177   manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00178   manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00179 
00180   // Parse command-line:
00181   if (manager.parseCommandLine(argc, argv,
00182                                "<textfile> <webpage> "
00183                                "<visual-angle-of-single-character>",
00184                                3, 3)==false)
00185     return(1);
00186 
00187   //get degrees
00188   double fontsize = fromStr<double>(manager.getExtraArg(2));
00189   //get webpage
00190   std::string itsWeb = manager.getExtraArg(1);
00191 
00192   // hook our various babies up and do post-command-line configs:
00193   nub::soft_ref<EyeTracker> et = etc->getET();
00194   d->setEyeTracker(et);
00195   d->setEventLog(el);
00196   et->setEventLog(el);
00197 
00198   // let's get all our ModelComponent instances started:
00199   manager.start();
00200 
00201   // let's do an eye tracker calibration:
00202   et->calibrate(d);
00203 
00204   d->clearScreen();
00205   d->displayText("<space> for random order, other key for ordered play.");
00206   int c = d->waitForKey();
00207   d->clearScreen();
00208 
00209   // create an image frame for each sentence in our text file and store
00210   // it in a vector before we start the experiment, then we can just
00211   // present each frame like in psycho still
00212   //
00213   //First read the text file and all the sentences
00214   //load our file
00215   std::ifstream *itsFile;
00216   itsFile = new std::ifstream(manager.getExtraArg(0).c_str());
00217 
00218   //error if no file
00219   if (itsFile->is_open() == false)
00220     LFATAL("Cannot open '%s' for reading",manager.getExtraArg(0).c_str());
00221 
00222   //some storage variables
00223   std::string line;
00224   std::vector<std::vector<std::string> > lines;
00225   std::vector<uint> itsType;
00226   uint scount = 0;
00227 
00228   //loop through lines of file
00229   while (!itsFile->eof())
00230     {
00231       getline(*itsFile, line);
00232 
00233       std::vector<std::string> temp;
00234       //store the sentence and type (question or statement)
00235       if (line[0] == '#')//question
00236         {
00237           line.erase(0,1);
00238           temp.push_back(line);
00239           lines.push_back(temp);
00240           itsType.push_back(1);
00241           scount++;
00242         }
00243       else if (line[0] =='!')//sentence
00244         {
00245           line.erase(0,1);
00246           temp.push_back(line);
00247           lines.push_back(temp);
00248           itsType.push_back(0);
00249           scount++;
00250         }
00251       else
00252         {
00253           if (line.size() > 1)
00254             {
00255               scount--;
00256               lines[scount].push_back(line);
00257               scount++;
00258             }
00259         }
00260     }
00261   itsFile->close();
00262 
00263   //now we have stored all of our sentences, lets create our images
00264   int w = d->getWidth();//width and height of SDL surface
00265   int h = d->getHeight();
00266   uint fontwidth = uint(fontsize * w / HDEG);
00267   SimpleFont fnt = SimpleFont::fixedMaxWidth(fontwidth); //font
00268   std::vector<Image<PixRGB<byte> > > itsSImage; //store sentences
00269   std::vector<Image<PixRGB<byte> > > itsQImage; //store images
00270 
00271   for (uint i = 0; i < lines.size(); i++)
00272     {
00273       int space = 0;
00274       int hanchor = int(h/2) - int(fnt.h()/2);
00275       Image<PixRGB<byte> > timage(w,h,ZEROS);
00276       timage += d->getGrey();
00277 
00278       for (uint j = 0; j < lines[i].size(); j++)
00279         {
00280           if (j < 1)
00281             space = int( double(w - fnt.w() * lines[i][j].size()) / 2.0 );
00282           if (j > 0)
00283             hanchor = hanchor + fnt.h();
00284           Point2D<int> tanchor(space, hanchor);
00285           writeText(timage,tanchor,lines[i][j].c_str(),
00286                     PixRGB<byte>(0,0,0),
00287                     d->getGrey(),
00288                     fnt);
00289         }
00290       if (itsType[i] == 0)
00291         itsSImage.push_back(timage);
00292       else
00293         itsQImage.push_back(timage);
00294     }
00295 
00296   uint count = scount/2;
00297   int index[count];
00298   for (uint i = 0; i < count; i ++)
00299     {
00300       index[i] = i;
00301     }
00302 
00303   if (c == ' ')
00304     {
00305       LINFO("Randomizing images...");
00306       randShuffle(index, count);
00307     }
00308 
00309   char* display = getenv((char*)"DISPLAY");
00310   // main loop:
00311   for (uint i = 0; i < count; i ++)
00312     {
00313       // load up the frame and show a fixation cross on a blank screen:
00314        d->clearScreen();
00315 
00316        //seutp sdl surfaces
00317       Image< PixRGB<byte> > imageS = itsSImage[index[i]];
00318       SDL_Surface *surf = d->makeBlittableSurface(imageS, true);
00319 
00320       Image< PixRGB<byte> > imageQ = itsQImage[index[i]];
00321       SDL_Surface *surfq = d->makeBlittableSurface(imageQ, true);
00322 
00323       // ready to go whenever the user is ready:
00324       d->displayFixation();
00325       d->waitForKey();
00326       d->waitNextRequestedVsync(false, true);
00327 
00328       d->pushEvent(std::string("===== Showing Sentence: ") +
00329                    toStr<int>(index[i])  + " =====");
00330 
00331       // show the image:
00332       d->displaySurface(surf, -2);
00333       d->waitForKey();
00334       // free the image:
00335       SDL_FreeSurface(surf);
00336       d->clearScreen();
00337       d->waitNextRequestedVsync(false, true);
00338 
00339       rutz::exec_pipe open("r","/usr/bin/mozilla-firefox",
00340                            itsWeb.c_str(), NULL);
00341 
00342       // start the eye tracker:
00343       et->track(true);
00344 
00345       // blink the fixation:
00346       d->displayFixationBlink();
00347 
00348       //open webpage - close sdl
00349       d->closeDisplay();
00350       d->pushEvent(std::string("===== Showing web page: ") +
00351                 toStr<int>(index[i])  + " =====");
00352 
00353       //wait for a key in any window to be pressed
00354       waitXKeyPress(display);
00355 
00356       // stop the eye tracker:
00357       usleep(50000);
00358       et->track(false);
00359       d->pushEvent(std::string("=====  Destroying web page: ") +
00360                 toStr<int>(index[i])  + " =====");
00361 
00362       //open sdl again
00363       d->openDisplay();
00364 
00365       //display the question
00366       d->pushEvent(std::string("===== Showing Question: ") +
00367                    toStr<int>(index[i])  + " =====");
00368 
00369       // show the image:
00370       d->displaySurface(surfq, -2);
00371       d->waitForKey();
00372       // free the image:
00373       SDL_FreeSurface(surfq);
00374     }
00375 
00376   d->clearScreen();
00377   d->displayText("Experiment complete. Thank you!");
00378   d->waitForKey();
00379 
00380   // stop all our ModelComponents
00381   manager.stop();
00382 
00383   // all done!
00384   return 0;
00385 }
00386 
00387 // ######################################################################
00388 /* So things look consistent in everyone's emacs... */
00389 /* Local Variables: */
00390 /* indent-tabs-mode: nil */
00391 /* End: */
Generated on Sun May 8 08:40:10 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3