psycho-video.C

Go to the documentation of this file.
00001 /*!@file AppPsycho/psycho-video.C Psychophysics display and grabbing of video feeds */
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-video.C $
00035 // $Id: psycho-video.C 13539 2010-06-09 22:43:26Z ilab19 $
00036 //
00037 
00038 #include "Component/ModelManager.H"
00039 #include "Devices/DeviceOpts.H"
00040 #include "Devices/DiskDataStream.H"
00041 #include "Devices/FrameGrabberConfigurator.H"
00042 #include "Image/Image.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 "GUI/SDLdisplay.H"
00050 #include "GUI/GUIOpts.H"
00051 #include "Raster/GenericFrame.H"
00052 #include "Transport/FrameIstream.H"
00053 #include "Util/FileUtil.H"
00054 #include "Util/StringUtil.H" // for split() and join()
00055 #include "Util/Types.H"
00056 #include "Util/csignals.H"
00057 #include "Util/sformat.H"
00058 #include "Video/VideoFrame.H"
00059 
00060 #include <SDL/SDL.h>
00061 #include <iterator> // for back_inserter()
00062 #include <unistd.h> // for sync()
00063 #include <time.h>
00064 
00065 namespace
00066 {
00067   class DiskDataStreamListener : public FrameListener
00068   {
00069   public:
00070     DiskDataStreamListener(nub::ref<DiskDataStream> stream)
00071       :
00072       itsStream(stream)
00073     {}
00074 
00075     virtual ~DiskDataStreamListener() {}
00076 
00077     virtual void onRawFrame(const GenericFrame& frame)
00078     {
00079       itsStream->writeFrame(frame, "frame");
00080     }
00081 
00082   private:
00083     nub::ref<DiskDataStream> itsStream;
00084   };
00085 }
00086 
00087 //! Psychophysics display and grabbing of video feeds
00088 /*! This displays and grabs video feeds to disk, with added machinery
00089   for eye-tracking. To save time, we grab raw data (in whatever native
00090   grab mode has been selected, without converting to RGB) then feed
00091   them to an SDL YUV overlay and save them to disk. For this to work,
00092   you need to configure your grabber in YUV420P mode, which is what is
00093   used for displays. The saved files are pure raw YUV420P data and will
00094   need to be converted, e.g., to RGB, later and in a different
00095   program (or you can use the YUV input mode of mpeg_encode to create
00096   MPEG movies from your saved files). */
00097 int submain(const int argc, char** argv)
00098 {
00099   MYLOGVERB = LOG_DEBUG;  // suppress debug messages
00100 
00101   // 'volatile' because we will modify this from signal handlers
00102   volatile int signum = 0;
00103   catchsignals(&signum);
00104 
00105   // Instantiate a ModelManager:
00106   ModelManager manager("Psycho Video");
00107 
00108   // Instantiate our various ModelComponents:
00109   nub::ref<FrameGrabberConfigurator>
00110     fgc(new FrameGrabberConfigurator(manager));
00111   manager.addSubComponent(fgc);
00112 
00113   nub::ref<PsychoDisplay> d(new PsychoDisplay(manager));
00114   manager.addSubComponent(d);
00115 
00116   nub::ref<DiskDataStream> ds(new DiskDataStream(manager));
00117   manager.addSubComponent(ds);
00118 
00119   nub::soft_ref<EyeTrackerConfigurator>
00120     etc(new EyeTrackerConfigurator(manager));
00121   manager.addSubComponent(etc);
00122 
00123   nub::soft_ref<EventLog> el(new EventLog(manager));
00124   manager.addSubComponent(el);
00125 
00126   // select a V4L grabber in 640x480 YUV420P by default:
00127   manager.exportOptions(MC_RECURSE);
00128   manager.setOptionValString(&OPT_FrameGrabberType, "V4L");
00129   manager.setOptionValString(&OPT_FrameGrabberMode, "UYVY");
00130   manager.setOptionValString(&OPT_FrameGrabberDims, "640x480");
00131   manager.setOptionValString(&OPT_DeinterlacerType, "Bob");
00132 
00133   manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00134 
00135   manager.setOptionValString(&OPT_DiskDataStreamSleepUsecs, "10000");
00136   manager.setOptionValString(&OPT_SDLdisplayDims, "640x480" );
00137 
00138   // Parse command-line:
00139   if (manager.parseCommandLine
00140       (argc, argv, "<dir1:dir2:dir3> <nframes> <subject>", 3, 3)
00141       == false)
00142     return(1);
00143 
00144   std::string Sub=manager.getExtraArg(2);
00145   manager.setOptionValString(&OPT_EventLogFileName, Sub);
00146 
00147   // hook our various babies up and do post-command-line configs:
00148   nub::soft_ref<EyeTracker> et = etc->getET();
00149   d->setEyeTracker(et);
00150   d->setEventLog(el);
00151   et->setEventLog(el);
00152 
00153   const std::string dirpath = manager.getExtraArg(0);
00154   const int maxframe = manager.getExtraArgAs<int>(1);
00155 
00156   std::vector<std::string> stems;
00157   split(dirpath, ":", std::back_inserter(stems));
00158 
00159   if (stems.size() == 0)
00160     LFATAL("expected at least one entry in the directory path");
00161 
00162   el->setModelParamString("EventLogFileName",
00163                           stems[0] + "/" + Sub);
00164 
00165   for (size_t i = 0; i < stems.size(); ++i)
00166     {
00167       makeDirectory(stems[i]);
00168       makeDirectory(stems[i] + "/frames");
00169 
00170       stems[i] = stems[i] + "/frames/";
00171     }
00172 
00173   ds->setModelParamString("DiskDataStreamSavePath",
00174                           join(stems.begin(), stems.end(), ","));
00175 
00176   nub::ref<FrameIstream> gb = fgc->getFrameGrabber();
00177 
00178   gb->setListener(rutz::shared_ptr<FrameListener>(new DiskDataStreamListener(ds)));
00179 
00180   // let's get all our ModelComponent instances started:
00181   manager.start();
00182 
00183   d->setDesiredRefreshDelayUsec(gb->getNaturalFrameTime().usecs(), 0.2F);
00184 
00185   // let's display an ISCAN calibration grid:
00186   d->clearScreen();
00187   d->displayISCANcalib();
00188   d->waitForKey();
00189 
00190   // let's do an eye tracker calibration:
00191   d->displayText("<SPACE> to calibrate; other key to skip");
00192   int c = d->waitForKey();
00193   if (c == ' ') d->displayEyeTrackerCalibration(3, 3, 2);
00194   d->clearScreen();
00195 
00196   // give a chance to other processes (useful on single-CPU machines):
00197   sleep(1);
00198   sync();
00199 
00200   // ready for action:
00201   d->displayText("<SPACE> to start experiment");
00202   d->waitForKey();
00203 
00204   // display fixation to indicate that we are ready:
00205   d->clearScreen();
00206   d->displayFixation();
00207 
00208   // create an overlay:
00209   d->createVideoOverlay(gb->peekFrameSpec().videoFormat);
00210 
00211 
00212 
00213   // ready to go whenever the user is ready:
00214   d->waitForKey();
00215   d->waitNextRequestedVsync(false, true);
00216   d->pushEvent("===== START =====");
00217 
00218   // get wall time:
00219   struct timeval tv;
00220   struct timezone tz;
00221   struct tm *tm;
00222   gettimeofday(&tv, &tz);
00223   tm = localtime(&tv.tv_sec); char msg[300];
00224   snprintf(msg, 300, "== WALL TIME: %d:%02d:%02d.%03"ZU".%03"ZU" ==",
00225            tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000,
00226            tv.tv_usec % 1000);
00227   d->pushEvent(msg);
00228 
00229   d->pushEvent(std::string("===== Playing movie: ") + Sub.c_str() + " =====");
00230 
00231   // start the eye tracker:
00232   et->track(true);
00233 
00234   // blink the fixation:
00235   d->displayFixationBlink();
00236 
00237   // grab, display and save:
00238   int framenum = 0;
00239   while (framenum < maxframe)
00240     {
00241       if (signum != 0)
00242         {
00243           LINFO("quitting because %s was caught", signame(signum));
00244           return -1;
00245         }
00246 
00247       // grab a raw buffer:
00248       const VideoFrame frame = gb->readFrame().asVideo();
00249 
00250       // display the frame as an overlay
00251       d->displayVideoOverlay(frame, framenum, SDLdisplay::NO_WAIT);
00252 
00253       ++framenum;
00254 
00255       // check for a keypress to see if the user wants to quit the
00256       // experiment; pressing '.' will give a graceful exit and normal
00257       // shutdown, while pressing <ESC> will trigger an LFATAL() and
00258       // an urgent shutdown:
00259       if (d->checkForKey() == '.')
00260         break;
00261     }
00262 
00263   // destroy the overlay. Somehow, mixing overlay displays and
00264   // normal displays does not work. With a single overlay created
00265   // before this loop and never destroyed, the first movie plays
00266   // ok but the other ones don't show up:
00267   d->destroyYUVoverlay();
00268   d->clearScreen();  // sometimes 2 clearScreen() are necessary
00269   d->clearScreen();  // sometimes 2 clearScreen() are necessary
00270 
00271   // stop the eye tracker:
00272   usleep(50000);
00273   et->track(false);
00274 
00275   d->clearScreen();
00276 
00277   // no need to explicit clear DiskDataStream's queue here; that
00278   // happens automatically in DiskDataStream::stop(), called from
00279   // manager.stop()
00280 
00281   d->displayText("Experiment complete. Thank you!");
00282   d->waitForKey();
00283 
00284   // stop all our ModelComponents
00285   manager.stop();
00286 
00287   // all done!
00288   return 0;
00289 }
00290 
00291 extern "C" int main(const int argc, char** argv)
00292 {
00293   try
00294     {
00295       return submain(argc, argv);
00296     }
00297   catch (...)
00298     {
00299       REPORT_CURRENT_EXCEPTION;
00300     }
00301 
00302   return 1;
00303 }
00304 
00305 // ######################################################################
00306 /* So things look consistent in everyone's emacs... */
00307 /* Local Variables: */
00308 /* indent-tabs-mode: nil */
00309 /* End: */
Generated on Sun May 8 08:04:21 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3