psycho-corner-movie.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: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-corner-movie.C $
00035 // $Id: psycho-corner-movie.C 13712 2010-07-28 21:00:40Z itti $
00036 //
00037 
00038 #include "Component/ModelManager.H"
00039 #include "Image/Image.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 #include <string>
00055 #include <fstream>
00056 #include <vector>
00057 #include <iostream>
00058 #include <algorithm>
00059 #include <assert.h>
00060 
00061 #define CACHELEN 150
00062 
00063 // ######################################################################
00064 static bool cacheFrame(nub::soft_ref<InputMPEGStream>& mp,
00065                        std::deque<VideoFrame>& cache)
00066 {
00067   const VideoFrame frame = mp->readVideoFrame();
00068   if (!frame.initialized()) return false; // end of stream
00069 
00070   cache.push_front(frame);
00071   return true;
00072 }
00073 
00074 // ######################################################################
00075 void Tokenize(const std::string& str,
00076               std::vector<std::string>& tokens,
00077               const std::string& delimiters = " ")
00078 {
00079   std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
00080   std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
00081   while (std::string::npos != pos || std::string::npos != lastPos)
00082   {
00083     tokens.push_back(str.substr(lastPos, pos - lastPos));
00084     lastPos = str.find_first_not_of(delimiters, pos);
00085     pos = str.find_first_of(delimiters, lastPos);
00086   }
00087 }
00088 
00089 // ######################################################################
00090 static int submain(const int argc, char** argv)
00091 {
00092   MYLOGVERB = LOG_INFO;  // suppress debug messages
00093 
00094   // Instantiate a ModelManager:
00095   ModelManager manager("Psycho Movie");
00096 
00097   // Instantiate our various ModelComponents:
00098   nub::soft_ref<InputMPEGStream> mp
00099     (new InputMPEGStream(manager, "Input MPEG Stream", "InputMPEGStream"));
00100   manager.addSubComponent(mp);
00101 
00102   nub::soft_ref<EventLog> el(new EventLog(manager));
00103   manager.addSubComponent(el);
00104 
00105   nub::soft_ref<EyeTrackerConfigurator>
00106     etc(new EyeTrackerConfigurator(manager));
00107   manager.addSubComponent(etc);
00108 
00109   nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00110   manager.addSubComponent(d);
00111 
00112   manager.setOptionValString(&OPT_InputMPEGStreamPreload, "true");
00113   manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00114   manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00115 
00116   // Parse command-line:
00117   if (manager.parseCommandLine(argc, argv,
00118                                "<display_loc.txt> <movie1.mpg> ... <movieN.mpg>", 2, -1)==false)
00119     return(1);
00120 
00121   // hook our various babies up and do post-command-line configs:
00122   nub::soft_ref<EyeTracker> et = etc->getET();
00123   d->setEyeTracker(et);
00124   d->setEventLog(el);
00125   et->setEventLog(el);
00126 
00127   // EyeLink opens the screen for us, so make sure SDLdisplay is slave:
00128   if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0)
00129     d->setModelParamVal("SDLslaveMode", true);
00130 
00131   // let's get all our ModelComponent instances started:
00132   manager.start();
00133 
00134   // read the display_loc.txt
00135   const char * display_loc = manager.getExtraArg(0).c_str();
00136   std::ifstream in( display_loc );
00137 
00138   if (! in) {
00139     LINFO("error: unable to open display_loc file: %s", display_loc);
00140     return -1;
00141   }
00142 
00143   std::vector< std::vector<std::string> > cdl; //cdl = clip display location
00144   std::string line;
00145   while( !getline(in, line).eof()){
00146     std::vector<std::string> tokens;
00147     Tokenize(line, tokens);
00148     cdl.push_back(tokens);
00149   }
00150   in.close();
00151 
00152   // setup array of movie indices:
00153   uint nbmovies = manager.numExtraArgs()-1;
00154   int index[nbmovies];
00155   for (uint i = 0; i < nbmovies; i ++) index[i] = i;
00156   LINFO("Randomizing movies..."); randShuffle(index,nbmovies);
00157 
00158   // calibration
00159   et->calibrate(d);
00160 
00161   if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0){
00162                 et->closeSDL();
00163                 d->openDisplay();
00164                 LINFO("Switching SDL: EyeLink-->iLab");
00165         }else{
00166           d->clearScreen();
00167         }
00168 
00169   d->displayText("<SPACE> to start watching movies");
00170   d->waitForKey();
00171 
00172   // get background color
00173   PixRGB<byte> ori_bgcolor = d->getGrey();
00174   PixRGB<byte> black_bgcolor = PixRGB<byte>(0,0,0);
00175 
00176   // main loop:
00177   for (uint i = 0; i < nbmovies; i ++)
00178   {
00179       // obtain display location
00180       int x = 100, y = 100, w = 1280, h = 1024; //w = 1233, h = 856;
00181       int sw = d->getWidth(), sh = d->getHeight();
00182       std::string playmovie = manager.getExtraArg(index[i]+1).c_str();
00183       std::vector< std::vector<std::string> >::iterator iter_ii;
00184       std::vector<std::string>::iterator iter_jj;
00185       std::string loc = "default";
00186       for(iter_ii=cdl.begin(); iter_ii!=cdl.end(); iter_ii++)
00187       {
00188           iter_jj = (*iter_ii).begin();
00189           if(playmovie.find(*iter_jj, 0) != std::string::npos){
00190               iter_jj++;
00191               loc = *iter_jj;
00192               if(loc.compare("0") == 0){ //center
00193                   x = sw/2 - w/2;
00194                   y = sh/2 - h/2;
00195               }else if(loc.compare("1") == 0){ //upper right
00196                   x = sw - w; y = 0;
00197               }else if(loc.compare("2") == 0){ //upper left
00198                   x = 0; y = 0;
00199               }else if(loc.compare("3") == 0){ //lower right
00200                   x = sw - w; y = sh - h;
00201               }else if(loc.compare("4") == 0){ //lower left
00202                   x = 0; y = sh - h;
00203               }else{ //default, display at the center
00204                   x = sw/2 - w/2;
00205                   y = sh/2 - h/2;
00206               }
00207           }
00208       }
00209 
00210       d->changeBackgroundColor(black_bgcolor);
00211       // cache initial movie frames:
00212       d->clearScreen();
00213       bool streaming = true;
00214       LINFO("Buffering '%s'...", manager.getExtraArg(index[i]+1).c_str());
00215       mp->setFileName(manager.getExtraArg(index[i]+1));
00216 
00217       std::deque<VideoFrame> cache;
00218       for (uint j = 0; j < CACHELEN; j ++)
00219         {
00220           streaming = cacheFrame(mp, cache);
00221           if (streaming == false) break;  // all movie frames got cached!
00222         }
00223       LINFO("'%s' ready.", manager.getExtraArg(index[i]).c_str());
00224 
00225       // give a chance to other processes (useful on single-CPU machines):
00226       sleep(1); if (system("/bin/sync")) LERROR("error in sync");
00227 
00228       // display fixation to indicate that we are ready:
00229       d->displayRedDotFixation();
00230 
00231       // ready to go whenever the user is ready:
00232       d->waitForKey(); int frame = 0;
00233       d->waitNextRequestedVsync(false, true);
00234       d->pushEvent(std::string("===== Playing movie: ") +
00235                    manager.getExtraArg(index[i]+1) + " =====");
00236       d->pushEvent(std::string("movie is displayed at location: ") + loc);
00237 
00238       // start the eye tracker:
00239       et->track(true);
00240 
00241       // blink the fixation:
00242       d->clearScreen();
00243       d->displayRedDotFixationBlink(x+w/2, y+h/2);
00244 
00245       // create an overlay:
00246       d->createVideoOverlay(VIDFMT_YUV420P, mp->getWidth(), mp->getHeight());
00247 
00248       // play the movie:
00249       d->changeBackgroundColor(PixRGB<byte>(0,0,0));
00250       rutz::time start = rutz::time::wall_clock_now();
00251       while(cache.size())
00252         {
00253           // let's first cache one more frame:
00254           if (streaming) streaming = cacheFrame(mp, cache);
00255 
00256           // get next frame to display and put it into our overlay:
00257           VideoFrame vidframe = cache.back();
00258           d->displayVideoOverlay_pos(vidframe, frame,
00259                                  SDLdisplay::NEXT_VSYNC,
00260                                  x, y, w, h);
00261           cache.pop_back();
00262 
00263           ++frame;
00264         }
00265       rutz::time stop = rutz::time::wall_clock_now();
00266       const double secs = (stop-start).sec();
00267       LINFO("%d frames in %.02f sec (~%.02f fps)", frame, secs, frame/secs);
00268 
00269       // destroy the overlay. Somehow, mixing overlay displays and
00270       // normal displays does not work. With a single overlay created
00271       // before this loop and never destroyed, the first movie plays
00272       // ok but the other ones don't show up:
00273       d->destroyYUVoverlay();
00274       d->clearScreen();  // sometimes 2 clearScreen() are necessary
00275 
00276       // stop the eye tracker:
00277       usleep(50000);
00278       et->track(false);
00279 
00280                         if(i%10 == 0 && i> 0 && i<nbmovies-1) {
00281                                 // 5 minutes break, then do a full calibration
00282         d->changeBackgroundColor(ori_bgcolor);
00283         d->displayText("Please take a break, press <SPACE> to continue");
00284         d->waitForKey();
00285 
00286         if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0){
00287                 d->closeDisplay();
00288                 et->openSDL();
00289                 et->calibrate(d);
00290           et->closeSDL();
00291           d->openDisplay();
00292           LINFO("Switching SDL for quick calibration");
00293                                 }else{
00294           d->clearScreen();
00295                 d->displayISCANcalib();
00296                 d->waitForKey();
00297 
00298           d->displayText("<SPACE> for eye-tracker calibration");
00299                 d->waitForKey();
00300                 d->displayEyeTrackerCalibration(3, 3);
00301                 d->clearScreen();
00302                                 }
00303 
00304         d->displayText("<SPACE> to start watching movies");
00305         d->waitForKey();
00306         d->changeBackgroundColor(black_bgcolor);
00307                         }
00308     }
00309 
00310   d->changeBackgroundColor(ori_bgcolor);
00311   d->clearScreen();
00312   d->displayText("Experiment complete. Thank you!");
00313   d->waitForKey();
00314 
00315   // stop all our ModelComponents
00316   manager.stop();
00317 
00318   // all done!
00319   return 0;
00320 }
00321 
00322 // ######################################################################
00323 extern "C" int main(const int argc, char** argv)
00324 {
00325   // simple wrapper around submain() to catch exceptions (because we
00326   // want to allow PsychoDisplay to shut down cleanly; otherwise if we
00327   // abort while SDL is in fullscreen mode, the X server won't return
00328   // to its original resolution)
00329   try
00330     {
00331       return submain(argc, argv);
00332     }
00333   catch (...)
00334     {
00335       REPORT_CURRENT_EXCEPTION;
00336     }
00337 
00338   return 1;
00339 }
00340 
00341 // ######################################################################
00342 /* So things look consistent in everyone's emacs... */
00343 /* Local Variables: */
00344 /* indent-tabs-mode: nil */
00345 /* End: */
Generated on Sun May 8 08:04:11 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3