pvisionTCP3-master.C

Go to the documentation of this file.
00001 /*!@file Parallel/pvisionTCP3-master.C Grab & process over beowulf w/ pvisionTCP3 */
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/Parallel/pvisionTCP3-master.C $
00035 // $Id: pvisionTCP3-master.C 10538 2008-12-17 08:49:27Z itti $
00036 //
00037 
00038 /*! This parallel vision processing master is for use with
00039   pvisionTCP3.  See the pvisionTCP3go script in bin/ for how to launch
00040   the slaves. The main difference between the TCP2 and TCP3 versions
00041   is that TCP3 uses load-balancing to send images to the slaves, and
00042   the master node is not only in charge of grabbing the video and
00043   displaying the results, but also of collecting the various
00044   conspicuity maps and assembling them into the saliency map. */
00045 
00046 #include "Beowulf/Beowulf.H"
00047 #include "Component/ModelManager.H"
00048 #include "Devices/DeviceOpts.H"
00049 #include "Devices/FrameGrabberConfigurator.H"
00050 #include "Image/ColorOps.H"
00051 #include "Image/CutPaste.H"     // for inplacePaste()
00052 #include "Image/DrawOps.H"
00053 #include "Image/FilterOps.H"
00054 #include "Image/Image.H"
00055 #include "Image/Image.H"
00056 #include "Image/ImageSet.H"
00057 #include "Image/MathOps.H"
00058 #include "Image/Pixels.H"
00059 #include "Image/ShapeOps.H"     // for decX() etc.
00060 #include "Image/Transforms.H"
00061 #include "Neuro/NeuroOpts.H"
00062 #include "Neuro/SaccadeControllerConfigurator.H"
00063 #include "Neuro/SaccadeController.H"
00064 #include "Parallel/pvisionTCP-defs.H"
00065 #include "Simulation/SimEventQueue.H"
00066 #include "Simulation/SimEventQueueConfigurator.H"
00067 #include "Transport/FrameIstream.H"
00068 #ifdef HAVE_SDL_SDL_H
00069 #include "GUI/SDLdisplay.H"
00070 #endif
00071 #include "Util/Assert.H"
00072 #include "Util/FpsTimer.H"
00073 #include "Util/Timer.H"
00074 #include "Util/sformat.H"
00075 #include "Video/RgbConversion.H" // for toVideoYUV422()
00076 
00077 #include <signal.h>
00078 #include <unistd.h>
00079 
00080 
00081 //! prescale level by which we downsize images before sending them off
00082 #define PRESCALE 2
00083 
00084 static bool goforever = true;  //!< Will turn false on interrupt signal
00085 
00086 //! Signal handler (e.g., for control-C)
00087 void terminate(int s)
00088 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); }
00089 
00090 //! function to receive results from slaves
00091 void receiveCMAPS(nub::soft_ref<Beowulf>& beo, Image<float> *cmap,
00092                   int32 *cmapframe);
00093 
00094 // ######################################################################
00095 int submain(int argc, char** argv)
00096 {
00097 #ifndef HAVE_SDL_SDL_H
00098   LFATAL("<SDL/SDL.h> must be installed to use this program");
00099 #else
00100   MYLOGVERB = LOG_INFO;
00101 
00102   // instantiate a model manager:
00103   ModelManager manager("Parallel Vision TCP Version 3");
00104 
00105   // Instantiate our various ModelComponents:
00106   nub::soft_ref<SimEventQueueConfigurator>
00107     seqc(new SimEventQueueConfigurator(manager));
00108   manager.addSubComponent(seqc);
00109 
00110   nub::soft_ref<FrameGrabberConfigurator>
00111     gbc(new FrameGrabberConfigurator(manager));
00112   manager.addSubComponent(gbc);
00113 
00114   nub::soft_ref<Beowulf>
00115     beo(new Beowulf(manager, "Beowulf Master", "BeowulfMaster", true));
00116   manager.addSubComponent(beo);
00117 
00118   nub::soft_ref<SDLdisplay>
00119     d(new SDLdisplay(manager));
00120   manager.addSubComponent(d);
00121 
00122   //  nub::soft_ref<ThresholdFrictionSaccadeController>
00123   //  sc(new ThresholdFrictionSaccadeController(manager));
00124   nub::soft_ref<SaccadeControllerEyeConfigurator>
00125     scc(new SaccadeControllerEyeConfigurator(manager));
00126   manager.addSubComponent(scc);
00127 
00128   // let's set a bunch of defauls:
00129   manager.setOptionValString(&OPT_SaccadeControllerEyeType, "Threshfric");
00130   manager.setOptionValString(&OPT_FrameGrabberType, "V4L");
00131   manager.setOptionValString(&OPT_SCeyeMaxIdleSecs, "1000.0");
00132   manager.setOptionValString(&OPT_SCeyeThreshMinOvert, "4.0");
00133   manager.setOptionValString(&OPT_SCeyeThreshMaxCovert, "3.0");
00134   //  manager.setOptionValString(&OPT_SCeyeSpringK, "1000000.0");
00135 
00136   // Parse command-line:
00137   if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1);
00138 
00139   // do post-command-line configs:
00140   nub::soft_ref<SimEventQueue> seq = seqc->getQ();
00141 
00142   nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00143   if (gb.isInvalid())
00144     LFATAL("You need to select a frame grabber type via the "
00145            "--fg-type=XX command-line option for this program "
00146            "to be useful");
00147   int w = gb->getWidth(), h = gb->getHeight();
00148 
00149   nub::ref<SaccadeController> sc = scc->getSC();
00150 
00151   const int foa_size = 64;
00152   manager.setModelParamVal("InputFrameDims", Dims(w, h),
00153                            MC_RECURSE | MC_IGNORE_MISSING);
00154   manager.setModelParamVal("SCeyeStartAtIP", true,
00155                            MC_RECURSE | MC_IGNORE_MISSING);
00156   manager.setModelParamVal("SCeyeInitialPosition",Point2D<int>(w/2,h/2),
00157                            MC_RECURSE | MC_IGNORE_MISSING);
00158   manager.setModelParamVal("FOAradius", foa_size,
00159                            MC_RECURSE | MC_IGNORE_MISSING);
00160   manager.setModelParamVal("FoveaRadius", foa_size,
00161                            MC_RECURSE | MC_IGNORE_MISSING);
00162   //manager.setModelParamVal("SimulationTimeStep", SimTime::MSECS(1.0),
00163   //                         MC_RECURSE | MC_IGNORE_MISSING);
00164 
00165   // catch signals and redirect them to terminate for clean exit:
00166   signal(SIGHUP, terminate); signal(SIGINT, terminate);
00167   signal(SIGQUIT, terminate); signal(SIGTERM, terminate);
00168   signal(SIGALRM, terminate);
00169 
00170   // get prepared to grab, communicate, display, etc:
00171   PixRGB<byte> pix(255, 255, 0);    // yellow color for fixations
00172   TCPmessage smsg;                  // buffer to send messages to nodes
00173   FpsTimer tim;                     // for computation of framerate
00174   Timer masterclock;                // master clock for simulations
00175 
00176   Image<float> cmap[NBCMAP2];       // array of conspicuity maps
00177   int32 cmapframe[NBCMAP2];         // array of cmap frame numbers
00178   for (int i = 0; i < NBCMAP2; i ++) cmapframe[i] = -1;
00179   int sml = 4;                      // pyramid level of saliency map
00180   Image<float> sm(w >> sml, h >> sml, ZEROS); // saliency map
00181   Point2D<int> fixation(-1, -1);         // coordinates of eye fixation
00182 
00183   // image buffer for display:
00184   const PixRGB<byte> grey(127);
00185   std::string info;
00186 
00187   // adjust SDL display size:
00188   d->setModelParamVal("SDLdisplayDims", gb->peekDims());
00189 
00190   // let's get all our ModelComponent instances started:
00191   manager.start();
00192 
00193   // clear screen
00194   d->clearScreen(grey);
00195   d->displayText("<SPACE> to start - <SPACE> again to quit", false,
00196                  PixRGB<byte>(0), grey);
00197   while(d->waitForKey() != ' ') ;
00198   d->clearScreen(grey);
00199 
00200   // create an overlay:
00201   d->createYUVoverlay(SDL_YV12_OVERLAY);
00202 
00203   // get the frame grabber to start streaming:
00204   gb->startStream();
00205 
00206   // initialize the timers:
00207   masterclock.reset();
00208 
00209   // ##### MAIN LOOP:
00210   while(goforever)
00211     {
00212       // receive conspicuity maps:
00213       receiveCMAPS(beo, cmap, cmapframe);
00214 
00215       // grab an image:
00216       Image< PixRGB<byte> > ima = gb->readRGB();
00217 
00218       // display image in window:
00219       Image<float> dispsm(sm); inplaceNormalize(dispsm, 0.0F, 255.0F);
00220       Image<byte> dispsmb = dispsm; dispsmb = quickInterpolate(dispsmb, 2);
00221       inplacePaste(ima, toRGB(dispsmb), Point2D<int>(w-dispsmb.getWidth(), 0));
00222       drawRect(ima, Rectangle(Point2D<int>(w-dispsmb.getWidth()-1, 0),
00223                               dispsmb.getDims()), pix);
00224 
00225       sc->evolve(*seq);
00226       Point2D<int> eye = sc->getDecision(*seq);
00227       if (eye.isValid()) fixation = eye;
00228       if (fixation.isValid())
00229         {
00230           drawPatch(ima, fixation, 2, pix);
00231           drawCircle(ima, fixation, foa_size, pix, 2);
00232         }
00233       writeText(ima, Point2D<int>(0, 0),
00234                 sformat(" %.1ffps ", tim.getRecentFps()).c_str(),
00235                 PixRGB<byte>(255), grey);
00236       writeText(ima, Point2D<int>(0, h-20), info.c_str(),
00237                 PixRGB<byte>(255), grey);
00238 
00239       SDL_Overlay* ovl = d->lockYUVoverlay();
00240       toVideoYUV422(ima, ovl->pixels[0], ovl->pixels[2], ovl->pixels[1]);
00241       d->unlockYUVoverlay();
00242       d->displayYUVoverlay(-1, SDLdisplay::NO_WAIT);
00243 
00244       // check for space bar pressed; note: will abort us violently if
00245       // ESC is pressed instead:
00246       if (d->checkForKey() == ' ') goforever = false;
00247 
00248       // receive conspicuity maps:
00249       receiveCMAPS(beo, cmap, cmapframe);
00250 
00251       // send every other frame to processing:
00252       if (tim.frameNumber() & 1)
00253         {
00254           const int32 frame = int32(tim.frameNumber());
00255 
00256           // prescale image:
00257           Image<PixRGB<byte> > ima2 =
00258             decY(lowPass5y(decX(lowPass5x(ima),1<<PRESCALE)),1<<PRESCALE);
00259 
00260           // we do the job of BEO_RETINA on the master to reduce latency:
00261           // compute luminance and send it off:
00262           Image<byte> lum = luminance(ima2);
00263 
00264           // first, send off luminance to orientation slaves:
00265           smsg.reset(frame, BEO_ORI0); smsg.addImage(lum); beo->send(smsg);
00266           smsg.setAction(BEO_ORI45); beo->send(smsg);
00267           smsg.setAction(BEO_ORI90); beo->send(smsg);
00268           smsg.setAction(BEO_ORI135); beo->send(smsg);
00269 
00270           // and also send to flicker slave:
00271           smsg.setAction(BEO_FLICKER); beo->send(smsg);
00272 
00273           // finally, send to luminance slave:
00274           smsg.setAction(BEO_LUMINANCE); beo->send(smsg);
00275 
00276           // compute RG and BY and send them off:
00277           Image<byte> r, g, b, y; getRGBY(ima2, r, g, b, y, (byte)25);
00278           smsg.reset(frame, BEO_REDGREEN);
00279           smsg.addImage(r); smsg.addImage(g); beo->send(smsg);
00280           smsg.reset(frame, BEO_BLUEYELLOW);
00281           smsg.addImage(b); smsg.addImage(y); beo->send(smsg);
00282         }
00283 
00284       // receive conspicuity maps:
00285       receiveCMAPS(beo, cmap, cmapframe);
00286 
00287       // build our current saliency map:
00288       info = sformat("%06d / ", tim.frameNumber());
00289       Image<float> sminput;
00290       for (int i = 0; i < NBCMAP2; i ++)
00291         if (cmap[i].initialized())
00292           {
00293             if (sminput.initialized()) sminput += cmap[i];
00294             else sminput = cmap[i];
00295             info += sformat("%06d ", cmapframe[i]);
00296           }
00297         else
00298           info += "------ ";
00299 
00300       // inject saliency map input into saliency map:
00301       if (sminput.initialized()) sm = sm * 0.7F + sminput * 0.3F;
00302 
00303       // evolve our saccade controller up to now:
00304       while(seq->now() < masterclock.getSimTime()) seq->evolve();
00305       sc->evolve(*seq);
00306 
00307       // find most salient location and feed saccade controller:
00308       float maxval; Point2D<int> currwin; findMax(sm, currwin, maxval);
00309       WTAwinner newwin =
00310         WTAwinner::buildFromSMcoords(currwin, sml, true,
00311                                      masterclock.getSimTime(),
00312                                      maxval, false);
00313       if (newwin.isValid()) sc->setPercept(newwin, *seq);
00314 
00315       // receive conspicuity maps:
00316       receiveCMAPS(beo, cmap, cmapframe);
00317 
00318       // ready for next frame:
00319       tim.nextFrame();
00320       while(seq->now() < masterclock.getSimTime()) seq->evolve();
00321     }
00322 
00323   // got interrupted; let's cleanup and exit:
00324   d->destroyYUVoverlay();
00325   LINFO("Normal exit");
00326   manager.stop();
00327 #endif
00328   return 0;
00329 }
00330 
00331 // ######################################################################
00332 void receiveCMAPS(nub::soft_ref<Beowulf>& beo, Image<float> *cmap,
00333                   int32 *cmapframe)
00334 {
00335   TCPmessage rmsg;      // buffer to receive messages from nodes
00336   int32 rframe, raction, rnode = -1, recnb=0; // receive from any node
00337   while(beo->receive(rnode, rmsg, rframe, raction)) // no wait
00338     {
00339       //LINFO("received %d/%d from %d while at %d",
00340       //    rframe, raction, rnode, frame);
00341       switch(raction & 0xffff)
00342         {
00343         case BEO_CMAP: // ##############################
00344           {
00345             // get the map:
00346             Image<float> ima = rmsg.getElementFloatIma();
00347 
00348             // the map number is stored in the high 16 bits of the
00349             // raction field:
00350             int32 mapn = raction >> 16;
00351             if (mapn < 0 || mapn >= NBCMAP2) {
00352               LERROR("Bogus cmap number ignored");
00353               break;
00354             }
00355 
00356             // here is a totally asynchronous system example: we
00357             // just update our current value of a given cmap if
00358             // the one we just received is more recent than the
00359             // one we had so far:
00360             if (cmapframe[mapn] < rframe)
00361               { cmap[mapn] = ima; cmapframe[mapn] = rframe; }
00362           }
00363 
00364           break;
00365         default: // ##############################
00366           LERROR("Bogus action %d -- IGNORING.", raction);
00367           break;
00368         }
00369       // limit number of receives, so we don't hold CPU too long:
00370       recnb ++; if (recnb > NBCMAP2 * 2) break;
00371     }
00372 }
00373 
00374 // ######################################################################
00375 extern "C" int main(int argc, char** argv)
00376 {
00377   try
00378     {
00379       return submain(argc, argv);
00380     }
00381   catch (...)
00382     {
00383       REPORT_CURRENT_EXCEPTION;
00384       return 1;
00385     }
00386   return 0;
00387 }
00388 
00389 // ######################################################################
00390 /* So things look consistent in everyone's emacs... */
00391 /* Local Variables: */
00392 /* indent-tabs-mode: nil */
00393 /* End: */
Generated on Sun May 8 08:41:08 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3