psycho-movie-fixicon2.C

00001 /*!@file AppPsycho/psycho-movie.C Psychophysics display of movies */
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: Po-He Tseng <ptseng@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-movie-fixicon.C $
00035 // $Id: psycho-movie-fixicon.C 13712 2010-07-28 21:00:40Z itti $
00036 
00037 #include "Component/ModelManager.H"
00038 #include "Image/Image.H"
00039 #include "Raster/Raster.H"
00040 #include "Media/MPEGStream.H"
00041 #include "Media/MediaOpts.H"
00042 #include "Psycho/PsychoDisplay.H"
00043 #include "Psycho/EyeTrackerConfigurator.H"
00044 #include "Psycho/EyeTracker.H"
00045 #include "Psycho/PsychoOpts.H"
00046 #include "Component/EventLog.H"
00047 #include "Component/ComponentOpts.H"
00048 #include "Util/MathFunctions.H"
00049 #include "Util/Types.H"
00050 #include "Video/VideoFrame.H"
00051 #include "rutz/time.h"
00052 
00053 #include <deque>
00054 
00055 #define CACHELEN 150
00056 
00057 // ######################################################################
00058 static bool cacheFrame(nub::soft_ref<InputMPEGStream>& mp,
00059                        std::deque<VideoFrame>& cache)
00060 {
00061   const VideoFrame frame = mp->readVideoFrame();
00062   if (!frame.initialized()) return false; // end of stream
00063 
00064   cache.push_front(frame);
00065   return true;
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("Psycho Movie");
00075 
00076   // Instantiate our various ModelComponents:
00077   nub::soft_ref<InputMPEGStream> mp
00078     (new InputMPEGStream(manager, "Input MPEG Stream", "InputMPEGStream"));
00079   manager.addSubComponent(mp);
00080 
00081   nub::soft_ref<EventLog> el(new EventLog(manager));
00082   manager.addSubComponent(el);
00083 
00084   nub::soft_ref<EyeTrackerConfigurator>
00085     etc(new EyeTrackerConfigurator(manager));
00086   manager.addSubComponent(etc);
00087 
00088   nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00089   manager.addSubComponent(d);
00090 
00091   manager.setOptionValString(&OPT_InputMPEGStreamPreload, "true");
00092   manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00093   manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00094 
00095   // Parse command-line:
00096   if (manager.parseCommandLine(argc, argv,
00097                                "<movie1.mpg> ... <movieN.mpg>", 1, -1)==false)
00098     return(1);
00099 
00100   // hook our various babies up and do post-command-line configs:
00101   nub::soft_ref<EyeTracker> et = etc->getET();
00102   d->setEyeTracker(et);
00103   d->setEventLog(el);
00104   et->setEventLog(el);
00105 
00106   // EyeLink opens the screen for us, so make sure SDLdisplay is slave:
00107   if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0)
00108     d->setModelParamVal("SDLslaveMode", true);
00109 
00110   // let's get all our ModelComponent instances started:
00111   manager.start();
00112 
00113   // vision test (generate random letters again if pressing 'r')
00114         LINFO("*****************************************************************************");
00115         LINFO("visual acuity test: [r] to regenerate another string; other keys to continue.");
00116         int key;
00117         do {
00118                 d->displayRandomText(7, 6);
00119         key = d->waitForKey(true);
00120         } while(key == 114 || key == 101 || key == 116 || key == 102);
00121 
00122         // let's do an eye tracker calibration:
00123         d->pushEventBegin("Calibration");
00124         et->calibrate(d);
00125         d->pushEventEnd("Calibration");
00126 
00127         // load fixation icon
00128         Image< PixRGB<byte> > fixicon =
00129                 Raster::ReadRGB(d->getModelParamString("PsychoDisplayFixationIcon"));
00130 
00131         // switching SDL from ilink to our SDL
00132         if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0){
00133                 et->closeSDL();
00134                 d->openDisplay();
00135                 LINFO("Switching SDL: Eyelink-->iLab");
00136         }else{
00137                 d->clearScreen();
00138         }
00139 
00140         LINFO("Press any key to start......");
00141   d->displayText("Press any key to start......");
00142   d->waitForKey(true);
00143 
00144   // setup array of movie indices:
00145   uint nbmovies = manager.numExtraArgs();
00146         uint nbmovses = 5; //number of movies per session
00147         int index[nbmovies], sindex[nbmovses];
00148   
00149         // only randomize order in its own session
00150         LINFO("Randomizing movies...");
00151         int iidx = 0;
00152         for (uint i=0; i<nbmovies; i++) {
00153                 sindex[i%nbmovses] = i;
00154                 if (i%nbmovses == nbmovses-1){
00155                         randShuffle(sindex, nbmovses);
00156                         for (uint j=0; j<nbmovses; j++) {
00157                                 index[iidx] = sindex[j];
00158                                 iidx++;
00159                         }
00160                 }
00161         }
00162 
00163   // main loop:
00164         int x, y, w, h;
00165   for (uint i = 0; i < nbmovies; i ++)
00166     {
00167       // cache initial movie frames:
00168       d->clearScreen();
00169       bool streaming = true;
00170       LINFO("Buffering '%s'...", manager.getExtraArg(index[i]).c_str());
00171       mp->setFileName(manager.getExtraArg(index[i]));
00172 
00173                         // get video display location
00174                         w = mp->getWidth();
00175                         h = mp->getHeight();
00176                         x = (d->getWidth()-w)/2;
00177                         y = (d->getHeight()-h)/2;
00178 
00179       std::deque<VideoFrame> cache;
00180       for (uint j = 0; j < CACHELEN; j ++)
00181         {
00182           streaming = cacheFrame(mp, cache);
00183           if (streaming == false) break;  // all movie frames got cached!
00184         }
00185       LINFO("'%s' ready.", manager.getExtraArg(index[i]).c_str());
00186                         LINFO("Video loaded (%i/%i).  Press [Space] to continue, or [ESC] to quit the program.", i+1, nbmovies);
00187 
00188       // give a chance to other processes (useful on single-CPU machines):
00189       sleep(1); if (system("/bin/sync")) LERROR("error in sync");
00190 
00191       // display fixation to indicate that we are ready:
00192       d->displayFixationIcon(fixicon);
00193 
00194       // ready to go whenever the user is ready:
00195       d->waitForKey(true); int frame = 0;
00196       d->waitNextRequestedVsync(false, true);
00197       d->pushEvent(std::string("===== Playing movie: ") +
00198                    manager.getExtraArg(index[i]) + " =====");
00199 
00200       // start the eye tracker:
00201       et->track(true);
00202 
00203       // blink the fixation:
00204       d->displayFixationIconBlink(fixicon);
00205 
00206       // create an overlay:
00207       d->createVideoOverlay(VIDFMT_YUV420P,mp->getWidth(),mp->getHeight()); // mpeg stream returns YUV420P
00208 
00209       // play the movie:
00210       rutz::time start = rutz::time::wall_clock_now();
00211       while(cache.size())
00212         {
00213           // let's first cache one more frame:
00214           if (streaming) streaming = cacheFrame(mp, cache);
00215 
00216           // get next frame to display and put it into our overlay:
00217           VideoFrame vidframe = cache.back();
00218           d->displayVideoOverlay_pos(vidframe, frame,
00219                                  SDLdisplay::NEXT_VSYNC,
00220                                                                                                                                  x, y, w, h);
00221           cache.pop_back();
00222 
00223           ++frame;
00224         }
00225       rutz::time stop = rutz::time::wall_clock_now();
00226       const double secs = (stop-start).sec();
00227       LINFO("%d frames in %.04f sec (~%.04f fps)", frame, secs, frame/secs);
00228 
00229       // destroy the overlay. Somehow, mixing overlay displays and
00230       // normal displays does not work. With a single overlay created
00231       // before this loop and never destroyed, the first movie plays
00232       // ok but the other ones don't show up:
00233       d->destroyYUVoverlay();
00234       d->clearScreen();  // sometimes 2 clearScreen() are necessary
00235 
00236       // stop the eye tracker:
00237       usleep(50000);
00238       et->track(false);
00239 
00240                         // take a break for every 5 clips, or do a quick drift correction
00241       if (i<nbmovies-1){
00242               if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0){
00243               d->closeDisplay();
00244           et->openSDL();
00245                                         if ((i+1)%5 == 0){
00246                                                 //5 clips, take a break
00247                                         d->clearScreen();
00248                                         d->displayText("Please Take a Break");
00249                                                 LINFO("Break time.  Press [Space] to continue, or [ESC] to terminate the experiment.");
00250                                         d->waitForKey(true);
00251                                         d->displayText("Calibration");
00252             d->pushEventBegin("Calibration");
00253             et->calibrate(d);
00254             d->pushEventEnd("Calibration");
00255           }else{
00256                                                 LINFO("Drift Correction.  Press [Space] to continue, or [ESC] to calibrate.");
00257             et->recalibrate(d,13);
00258           }
00259           LINFO("Switching SDL for Calibration ");
00260         }else{
00261                 // let's do a quickie eye tracker recalibration:
00262                 et->recalibrate(d,13);
00263         }
00264                 }
00265     }
00266 
00267   d->clearScreen();
00268   d->displayText("Experiment complete. Thank you!");
00269   d->waitForKey(true);
00270 
00271   // stop all our ModelComponents
00272   manager.stop();
00273 
00274   // all done!
00275   return 0;
00276 }
00277 
00278 // ######################################################################
00279 extern "C" int main(const int argc, char** argv)
00280 {
00281   // simple wrapper around submain() to catch exceptions (because we
00282   // want to allow PsychoDisplay to shut down cleanly; otherwise if we
00283   // abort while SDL is in fullscreen mode, the X server won't return
00284   // to its original resolution)
00285   try
00286     {
00287       return submain(argc, argv);
00288     }
00289   catch (...)
00290     {
00291       REPORT_CURRENT_EXCEPTION;
00292     }
00293 
00294   return 1;
00295 }
00296 
00297 // ######################################################################
00298 /* So things look consistent in everyone's emacs... */
00299 /* Local Variables: */
00300 /* indent-tabs-mode: nil */
00301 /* End: */
Generated on Sun May 8 08:40:09 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3