psycho-monkey.C

Go to the documentation of this file.
00001 /*!@file AppPsycho/psycho-monkey.C Psychophysics display of movies for monkeys */
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-monkey.C $
00035 // $Id: psycho-monkey.C 13795 2010-08-17 16:47:41Z beobot $
00036 //
00037 
00038 #include "Component/ModelManager.H"
00039 #include "Component/ModelOptionDef.H"
00040 #include "Transport/TransportOpts.H"
00041 #include "Image/Image.H"
00042 #include "Image/Range.H"
00043 #include "Media/MPEGStream.H"
00044 #include "Media/MediaOpts.H"
00045 #include "Psycho/PsychoDisplay.H"
00046 #include "Psycho/EyeTrackerConfigurator.H"
00047 #include "Psycho/EyeTracker.H"
00048 #include "Psycho/PsychoOpts.H"
00049 #include "Component/EventLog.H"
00050 #include "Component/ComponentOpts.H"
00051 #include "GUI/SDLdisplay.H"
00052 #include "Util/MathFunctions.H"
00053 #include "Util/Types.H"
00054 #include "Util/SimTime.H"
00055 #include "Video/VideoFrame.H"
00056 #include "rutz/rand.h"
00057 
00058 #include <deque>
00059 #include <sys/time.h>
00060 #include <unistd.h>
00061 
00062 #define CACHELEN 500
00063 
00064 
00065 // ######################################################################
00066 static bool cacheFrame(nub::soft_ref<InputMPEGStream>& mp,
00067                        std::deque<VideoFrame>& cache,
00068                        const bool flip)
00069 {
00070   const VideoFrame frame = mp->readVideoFrame();
00071   if (!frame.initialized()) return false; // end of stream
00072 
00073   if (flip) cache.push_front(frame.getFlippedHoriz());
00074   else cache.push_front(frame);
00075 
00076   return true;
00077 }
00078 
00079 // ######################################################################
00080 extern "C" int main(const int argc, char** argv)
00081 {
00082   MYLOGVERB = LOG_INFO;  // suppress debug messages
00083 
00084   // Instantiate a ModelManager:
00085   ModelManager manager("Psycho Monkey");
00086   OModelParam<bool> hflip(&OPT_Hflip, &manager);
00087   OModelParam<bool> keepfix(&OPT_KeepFix, &manager);
00088   OModelParam<float> fixsize(&OPT_FixSize, &manager);
00089   OModelParam<float> ppd(&OPT_Ppd, &manager);
00090   OModelParam<Range<int> > itsWait(&OPT_TrialWait, &manager);
00091   OModelParam<bool> testrun(&OPT_Testrun, &manager);
00092   OModelParam<int> itsPercent(&OPT_GrayFramePrcnt, &manager);
00093   OModelParam<Range<int> > itsRange(&OPT_GrayFrameRange, &manager);
00094 
00095   // Instantiate our various ModelComponents:
00096   nub::soft_ref<InputMPEGStream> mp
00097     (new InputMPEGStream(manager, "Input MPEG Stream", "InputMPEGStream"));
00098   manager.addSubComponent(mp);
00099 
00100   nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00101   manager.addSubComponent(d);
00102 
00103   nub::soft_ref<EyeTrackerConfigurator>
00104     etc(new EyeTrackerConfigurator(manager));
00105   manager.addSubComponent(etc);
00106 
00107   nub::soft_ref<EventLog> el(new EventLog(manager));
00108   manager.addSubComponent(el);
00109 
00110   manager.setOptionValString(&OPT_InputMPEGStreamPreload, "true");
00111   manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00112   manager.setOptionValString(&OPT_EyeTrackerType, "DML");
00113 
00114   // Parse command-line:
00115   if (manager.parseCommandLine(argc, argv,
00116                                "<movie1.mpg> ... <movieN.mpg>", 1, -1)==false)
00117     return(1);
00118 
00119   // hook our various babies up and do post-command-line configs:
00120   nub::soft_ref<EyeTracker> et = etc->getET();
00121   d->setEyeTracker(et);
00122   d->setEventLog(el);
00123   et->setEventLog(el);
00124 
00125   //screen center and fixation point
00126   int fixrad = int(ppd.getVal() * fixsize.getVal());
00127   if ((fixrad % 2) != 0)
00128     --fixrad;
00129   d->setFixationSize(fixrad*2);
00130 
00131   const int cx = d->getWidth() /2 - 1 - (fixrad/2 -1);
00132   const int cy = d->getHeight()/2 - 1 - (fixrad/2 -1);
00133 
00134   //create a fixation patch
00135   Image<PixRGB<byte> > patch(fixrad,fixrad,ZEROS);
00136   patch += PixRGB<byte>(255,0,0);
00137 
00138   std::deque<VideoFrame> cache;
00139   initRandomNumbers();
00140 
00141   // let's get all our ModelComponent instances started:
00142   manager.start();
00143   d->clearScreen();
00144 
00145   // setup array of movie indices:
00146   const uint nbmovies = manager.numExtraArgs(); 
00147   const float percentage = (float)itsPercent.getVal() * 0.01F;
00148   const float factor = percentage/(1 - percentage);
00149   const uint graycount = uint(factor * (float)nbmovies);
00150   const uint nbtotal = nbmovies + graycount;
00151 
00152   LINFO("Randomizing movies...");
00153   int index[nbtotal];
00154   std::string fnames[nbtotal];
00155   for (uint i = 0; i < nbmovies; ++i) index[i] = i;
00156   for (uint i = nbmovies; i < nbtotal; ++i) index[i] = -1;
00157   randShuffle(index, nbtotal);
00158   for (uint i = 0; i < nbtotal; ++i) 
00159     fnames[i] = (index[i] < 0) ? "Gray image" :  manager.getExtraArg(index[i]);
00160   
00161   try {
00162     // main loop:
00163     for (uint i = 0; i < nbtotal; i ++)
00164       {
00165         // cache initial movie frames:
00166         d->clearScreen();
00167         if (cache.size()) LFATAL("ooops, cache not empty?");
00168         bool streaming = true;
00169         LINFO("Buffering '%s'...", fnames[i].c_str());
00170 
00171         // NOTE: we now specify --preload-mpeg=true with a
00172         // setOptionValString() a few lines up from here
00173         if (index[i] > -1)
00174           {
00175             mp->setFileName(fnames[i]);
00176             for (uint j = 0; j < CACHELEN; j ++)
00177               {
00178                 streaming = cacheFrame(mp, cache, hflip.getVal());
00179                 if (streaming == false) break;  // all movie frames got cached!
00180               }
00181           }
00182 
00183         LINFO("'%s' ready.", fnames[i].c_str());
00184 
00185         //wait for requested time till next trial
00186         usleep(rutz::rand_range<int>(itsWait.getVal().min(), 
00187                                      itsWait.getVal().max()) * 1000);
00188 
00189 
00190         // give a chance to other processes (useful on single-CPU machines):
00191         sleep(1); if (system("/bin/sync")) LERROR("Cannot sync()");
00192         LINFO("/bin/sync complete");
00193 
00194         // eat up any extra fixation codes and keys before we start
00195         // the next fixation round:
00196         while(et->isFixating()) ;
00197         while(d->checkForKey() != -1) ;
00198 
00199         // display fixation to indicate that we are ready:
00200         d->displayRedDotFixation();
00201 
00202         // give us a chance to abort
00203         d->checkForKey();
00204 
00205         // ready to go whenever the monkey is ready (pulse on parallel port):
00206         if (!testrun.getVal())
00207           while(true)
00208             {
00209               if (et->isFixating()) break;
00210               if (d->checkForKey() != -1) break; // allow force start by key
00211             }
00212 
00213         int frame = 0;
00214         if (index[i] > -1) d->waitNextRequestedVsync(false, true);
00215         d->pushEvent(std::string("===== Playing movie: ") +
00216                      fnames[i] + " =====");
00217 
00218         // start the eye tracker:
00219         et->track(true);
00220 
00221         if (index[i] > -1) 
00222           {
00223             // create an overlay:
00224             d->createVideoOverlay(VIDFMT_YUV420P); // mpeg stream uses YUV420P
00225             
00226             // play the movie:
00227             while(cache.size())
00228               {
00229                 // let's first cache one more frame:
00230                 if (streaming) streaming = cacheFrame(mp, cache, hflip.getVal());
00231                 
00232                 // get next frame to display and put it into our overlay:
00233                 VideoFrame vidframe = cache.back();
00234                 if (keepfix.getVal())
00235                   d->displayVideoOverlay_patch(vidframe, frame,
00236                                                SDLdisplay::NEXT_VSYNC, cx, cy,
00237                                                patch);
00238                 else
00239                   d->displayVideoOverlay(vidframe, frame,
00240                                          SDLdisplay::NEXT_VSYNC);
00241                 
00242                 cache.pop_back();
00243                 ++frame;
00244               }
00245             
00246             // destroy the overlay. Somehow, mixing overlay displays and
00247             // normal displays does not work. With a single overlay created
00248             // before this loop and never destroyed, the first movie plays
00249             // ok but the other ones don't show up:
00250             d->destroyYUVoverlay();
00251             d->clearScreen();  // sometimes 2 clearScreen() are necessary
00252           }
00253         else
00254           {
00255             d->clearScreen();  
00256             usleep(rutz::rand_range<int>(itsRange.getVal().min(), 
00257                                          itsRange.getVal().max()) * 1000);
00258           }
00259 
00260 
00261         // stop the eye tracker:
00262         usleep(50000);
00263         et->track(false);
00264       }
00265 
00266     d->clearScreen();
00267     LINFO("Experiment complete");
00268   }
00269   catch (...)
00270     {
00271       REPORT_CURRENT_EXCEPTION;
00272     };
00273 
00274   // stop all our ModelComponents
00275   manager.stop();
00276 
00277   // all done!
00278   return 0;
00279 }
00280 
00281 // ######################################################################
00282 /* So things look consistent in everyone's emacs... */
00283 /* Local Variables: */
00284 /* indent-tabs-mode: nil */
00285 /* End: */
Generated on Sun May 8 08:40:08 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3