fzvisionTCP3-master.C

Go to the documentation of this file.
00001 /*!@file VFAT/fzvisionTCP3-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: T. Nathan Mundhenk<mundhenk@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/VFAT/fzvisionTCP3-master.C $
00035 // $Id: fzvisionTCP3-master.C 9412 2008-03-10 23:10:15Z farhan $
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 "GUI/XWindow.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/ImageSet.H"
00056 #include "Image/ShapeOps.H"        // for decX() etc.
00057 #include "Media/FrameSeries.H"
00058 #include "Neuro/NeuroOpts.H"
00059 #include "Neuro/SaccadeController.H"
00060 #include "Neuro/SaccadeControllerConfigurator.H"
00061 #include "Simulation/SimEventQueue.H"
00062 #include "Simulation/SimEventQueueConfigurator.H"
00063 #include "Transport/FrameIstream.H"
00064 #ifdef HAVE_SDL_SDL_H
00065 #include "Psycho/PsychoDisplay.H"
00066 #endif
00067 #include "Util/Assert.H"
00068 #include "Util/Timer.H"
00069 #include "VFAT/featureClusterVision.H"
00070 #include "Video/RgbConversion.H" // for toVideoYUV422()
00071 
00072 #include <signal.h>
00073 #include <unistd.h>
00074 
00075 
00076 // the following beowulf action definitions are used by pvisionTCP:
00077 #define BEO_RETINA     1
00078 #define BEO_WINNER     2
00079 #define BEO_LUMINANCE  3
00080 #define BEO_REDGREEN   4
00081 #define BEO_BLUEYELLOW 5
00082 #define BEO_ORI0       6
00083 #define BEO_ORI45      7
00084 #define BEO_ORI90      8
00085 #define BEO_ORI135     9
00086 #define BEO_CMAP       10
00087 #define BEO_FLICKER    11
00088 
00089 //! Number of conspicuity maps for pvisionTCP
00090 #define NBCMAP 7
00091 
00092 //! Number of conspicuity maps fo pvisionTCP2
00093 #define NBCMAP2 8
00094 
00095 //! Node offset for the two processing streams:
00096 #define POFFSET 8
00097 
00098 //! Number of frames over which average framerate is computed
00099 #define NAVG 20
00100 
00101 //! prescale level by which we downsize images before sending them off
00102 #define PRESCALE 2
00103 
00104 static bool goforever = true;  //!< Will turn false on interrupt signal
00105 
00106 //! Signal handler (e.g., for control-C)
00107 void terminate(int s)
00108 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); }
00109 
00110 //! function to receive results from slaves
00111 void receiveCMAPS(nub::soft_ref<Beowulf>& beo, std::vector<Image<float> > *cmap,
00112                   int32 *cmapframe);
00113 
00114 // ######################################################################
00115 extern "C" int main(const int argc, char** argv)
00116 {
00117 #ifndef HAVE_SDL_SDL_H
00118 
00119   LFATAL("<SDL/SDL.h> must be installed to use this program");
00120 
00121 #else
00122 
00123   MYLOGVERB = LOG_INFO;
00124 
00125   // instantiate a model manager:
00126   ModelManager manager("Parallel Vision TCP Version 3");
00127 
00128   // Instantiate our various ModelComponents:
00129   nub::soft_ref<SimEventQueueConfigurator>
00130     seqc(new SimEventQueueConfigurator(manager));
00131   manager.addSubComponent(seqc);
00132 
00133   nub::soft_ref<FrameGrabberConfigurator>
00134     gbc(new FrameGrabberConfigurator(manager));
00135   manager.addSubComponent(gbc);
00136 
00137   nub::soft_ref<Beowulf>
00138     beo(new Beowulf(manager, "Beowulf Master", "BeowulfMaster", true));
00139   manager.addSubComponent(beo);
00140 
00141   nub::soft_ref<PsychoDisplay>
00142     d(new PsychoDisplay(manager));
00143   manager.addSubComponent(d);
00144 
00145   // Instantiate our various ModelComponents (for compatability)
00146   nub::soft_ref<InputFrameSeries> ifs(new InputFrameSeries(manager));
00147   manager.addSubComponent(ifs);
00148 
00149   //  nub::soft_ref<ThresholdFrictionSaccadeController>
00150   //  sc(new ThresholdFrictionSaccadeController(manager));
00151   nub::soft_ref<SaccadeControllerEyeConfigurator>
00152     scc(new SaccadeControllerEyeConfigurator(manager));
00153   manager.addSubComponent(scc);
00154 
00155   // let's set a bunch of defauls:
00156   manager.setOptionValString(&OPT_SaccadeControllerEyeType, "Threshfric");
00157   manager.setOptionValString(&OPT_FrameGrabberType, "V4L");
00158   manager.setOptionValString(&OPT_SCeyeMaxIdleSecs, "1000.0");
00159   manager.setOptionValString(&OPT_SCeyeThreshMinOvert, "4.0");
00160   manager.setOptionValString(&OPT_SCeyeThreshMaxCovert, "3.0");
00161   //  manager.setOptionValString(&OPT_SCeyeSpringK, "1000000.0");
00162 
00163   // Parse command-line:
00164   if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1);
00165 
00166   // do post-command-line configs:
00167   nub::soft_ref<SimEventQueue> seq = seqc->getQ();
00168 
00169   nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00170   if (gb.isInvalid())
00171     LFATAL("You need to select a frame grabber type via the "
00172            "--fg-type=XX command-line option for this program "
00173            "to be useful");
00174   int w = gb->getWidth(), h = gb->getHeight();
00175 
00176   nub::ref<SaccadeController> sc = scc->getSC();
00177 
00178   int foa_size = std::min(w, h) / 12;
00179   manager.setModelParamVal("InputFrameDims", Dims(w, h),
00180                            MC_RECURSE | MC_IGNORE_MISSING);
00181   manager.setModelParamVal("SCeyeStartAtIP", true,
00182                            MC_RECURSE | MC_IGNORE_MISSING);
00183   manager.setModelParamVal("SCeyeInitialPosition",Point2D<int>(w/2,h/2),
00184                            MC_RECURSE | MC_IGNORE_MISSING);
00185   manager.setModelParamVal("FOAradius", foa_size,
00186                            MC_RECURSE | MC_IGNORE_MISSING);
00187   manager.setModelParamVal("FoveaRadius", foa_size,
00188                            MC_RECURSE | MC_IGNORE_MISSING);
00189 
00190   // catch signals and redirect them to terminate for clean exit:
00191   signal(SIGHUP, terminate); signal(SIGINT, terminate);
00192   signal(SIGQUIT, terminate); signal(SIGTERM, terminate);
00193   signal(SIGALRM, terminate);
00194 
00195   // get prepared to grab, communicate, display, etc:
00196   int32 frame = 0;                  // count the frames
00197   PixRGB<byte> pix(255, 255, 0);    // yellow color for fixations
00198   TCPmessage smsg;                  // buffer to send messages to nodes
00199 
00200   uint64 avgtime = 0; int avgn = 0; // for average framerate
00201   float fps = 0.0F;                 // to display framerate
00202   Timer tim;                        // for computation of framerate
00203   Timer masterclock;                // master clock for simulations
00204 
00205   Image<float> bimage;
00206   std::vector<Image<float> > cmap(NBCMAP2,bimage); // vec of conspicuity maps
00207   int32 cmapframe[NBCMAP2];         // array of cmap frame numbers
00208   for (int i = 0; i < NBCMAP2; i ++) cmapframe[i] = -1;
00209   int sml = 4;                      // pyramid level of saliency map
00210   Image<float> sm(w >> sml, h >> sml, ZEROS); // saliency map
00211   Point2D<int> fixation(-1, -1);         // coordinates of eye fixation
00212   const std::string name = "featureCluster";
00213   const std::string tag  = "fCV";
00214 
00215   featureClusterVision<float> fCVout(manager,name,tag,&sm,&cmap,ifs,
00216                                      manager.getExtraArg(0));
00217 
00218   nub::soft_ref<featureClusterVision<float> >
00219     fCV(&fCVout);
00220   manager.addSubComponent(fCV);
00221 
00222 
00223   // image buffer for display:
00224   Image<PixRGB<byte> > disp(w * 2, h + 20, ZEROS);
00225   disp += d->getGrey();
00226   int dw = d->getDims().w(), dh = d->getDims().h();
00227   ASSERT(dw == w * 2); ASSERT(dh >= disp.getHeight());
00228   int ovlyoff = (w * 2) * ((dh - disp.getHeight()) / 2);
00229   int ovluvoff = ovlyoff / 4;
00230 
00231   char info[1000];  // general text buffer for various info messages
00232 
00233   // let's get all our ModelComponent instances started:
00234   manager.start();
00235 
00236   // clear screen
00237   d->clearScreen();
00238   d->displayText("<SPACE> to start - <SPACE> again to quit");
00239   while(d->waitForKey() != ' ') ;
00240   d->clearScreen();
00241 
00242   // create an overlay:
00243   d->createYUVoverlay(SDL_YV12_OVERLAY);
00244 
00245   // get the frame grabber to start streaming:
00246   gb->startStream();
00247 
00248   // initialize the timers:
00249 
00250   tim.reset(); masterclock.reset();
00251   XWindow win1(Dims(720, 480), 0, 0, "CLASSES");
00252   Image<PixRGB<float> > fima1; Image<PixRGB<byte> > bima1;
00253   XWindow win2(Dims(720, 480), 0, 0, "CLASSES TEMPORAL");
00254   Image<PixRGB<float> > fima2; Image<PixRGB<byte> > bima2;
00255   XWindow win3(Dims(720, 480), 0, 0, "TARGETS TEMPORAL");
00256   Image<PixRGB<float> > fima3; Image<PixRGB<byte> > bima3;
00257   XWindow win4(Dims(720, 480), 0, 0, "SALIENCY MAP");
00258   Image<float> fima4; Image<PixRGB<byte> > bima4;
00259 
00260   // ########## MAIN LOOP: grab, process, display:
00261   while(goforever)
00262     {
00263       // receive conspicuity maps:
00264       receiveCMAPS(beo, &cmap, cmapframe);
00265 
00266       // grab an image:
00267       Image< PixRGB<byte> > ima = gb->readRGB();
00268       std::string myname;
00269       myname = "Beowulf." + frame;
00270       fCVout.fCVuploadImage(ima,myname);
00271 
00272       // display image in window:
00273       inplacePaste(disp, ima, Point2D<int>(0, 0));
00274       Image<float> dispsm(sm); inplaceNormalize(dispsm, 0.0F, 255.0F);
00275       inplacePaste(disp,
00276                    Image<PixRGB<byte> >(toRGB(quickInterpolate(dispsm, 1 << sml))),
00277                    Point2D<int>(w, 0));
00278 
00279       sc->evolve(*seq);
00280       Point2D<int> eye = sc->getDecision(*seq);
00281       if (eye.i >= 0) fixation = eye;
00282       if (fixation.i >= 0)
00283         {
00284           drawPatch(disp, fixation, 2, pix);
00285           drawCircle(disp, fixation, foa_size, pix, 2);
00286         }
00287       sprintf(info, "%.1ffps", fps);
00288       writeText(disp, Point2D<int>(w, 0), info, PixRGB<byte>(255), PixRGB<byte>(0));
00289 
00290       SDL_Overlay* ovl = d->lockYUVoverlay();
00291       toVideoYUV422(disp, ovl->pixels[0] + ovlyoff,
00292                     ovl->pixels[2] + ovluvoff,
00293                     ovl->pixels[1] + ovluvoff);
00294       d->unlockYUVoverlay();
00295       d->displayYUVoverlay(-1, SDLdisplay::NO_WAIT);
00296 
00297       // check for space bar pressed; note: will abort us violently if
00298       // ESC is pressed instead:
00299       if (d->checkForKey() == ' ') goforever = false;
00300 
00301       // receive conspicuity maps:
00302       receiveCMAPS(beo, &cmap, cmapframe);
00303 
00304       // send every other frame to processing:
00305       if (frame & 1)
00306         {
00307           // prescale image:
00308           Image<PixRGB<byte> > ima2 =
00309             decY(lowPass5y(decX(lowPass5x(ima),1<<PRESCALE)),1<<PRESCALE);
00310 
00311           // we do the job of BEO_RETINA on the master to reduce latency:
00312           // compute luminance and send it off:
00313           Image<byte> lum = luminance(ima2);
00314 
00315           // first, send off luminance to orientation slaves:
00316           smsg.reset(frame, BEO_ORI0); smsg.addImage(lum); beo->send(smsg);
00317           smsg.setAction(BEO_ORI45); beo->send(smsg);
00318           smsg.setAction(BEO_ORI90); beo->send(smsg);
00319           smsg.setAction(BEO_ORI135); beo->send(smsg);
00320 
00321           // and also send to flicker slave:
00322           smsg.setAction(BEO_FLICKER); beo->send(smsg);
00323 
00324           // finally, send to luminance slave:
00325           smsg.setAction(BEO_LUMINANCE); beo->send(smsg);
00326 
00327           // compute RG and BY and send them off:
00328           Image<byte> r, g, b, y; getRGBY(ima2, r, g, b, y, (byte)25);
00329           smsg.reset(frame, BEO_REDGREEN);
00330           smsg.addImage(r); smsg.addImage(g); beo->send(smsg);
00331           smsg.reset(frame, BEO_BLUEYELLOW);
00332           smsg.addImage(b); smsg.addImage(y); beo->send(smsg);
00333         }
00334 
00335       // receive conspicuity maps:
00336       receiveCMAPS(beo, &cmap, cmapframe);
00337 
00338       // build our current saliency map:
00339       sprintf(info, "%06d / ", frame);
00340       Image<float> sminput;
00341       for (int i = 0; i < NBCMAP2; i ++)
00342         if (cmap[i].initialized())
00343           {
00344             if (sminput.initialized()) sminput += cmap[i];
00345             else sminput = cmap[i];
00346             char num[10]; sprintf(num, "%06d ", cmapframe[i]);
00347             strcat(info, num);
00348           }
00349         else
00350           strcat(info, "------ ");
00351       writeText(disp, Point2D<int>(0, h), info,
00352                 PixRGB<byte>(255), d->getGrey());
00353 
00354       // inject saliency map input into saliency map:
00355       if (sminput.initialized()) sm = sm * 0.7F + sminput * 0.3F;
00356 
00357       // evolve our saccade controller up to now:
00358       while(seq->now() < masterclock.getSimTime()) seq->evolve();
00359       sc->evolve(*seq);
00360 
00361       // find most salient location and feed saccade controller:
00362       float maxval; Point2D<int> currwin; findMax(sm, currwin, maxval);
00363       WTAwinner newwin =
00364         WTAwinner::buildFromSMcoords(currwin, sml, true,
00365                                      masterclock.getSimTime(),
00366                                      maxval, false);
00367       if (newwin.isValid()) sc->setPercept(newwin, *seq);
00368 
00369       fCVout.fCVgetClusterImages(&fima1,&fima2,&fima3,&fima4);
00370       bima1 = fima1; bima2 = fima2; bima3 = fima3;
00371       win1.drawImage(bima1);
00372       win2.drawImage(bima2);
00373       win3.drawImage(bima3);
00374 
00375       // receive conspicuity maps:
00376       receiveCMAPS(beo, &cmap, cmapframe);
00377 
00378       // compute and show framerate and stats over the last NAVG frames:
00379       avgtime += tim.getReset(); avgn ++;
00380       if (avgn == NAVG)
00381         {
00382           fps = 1000.0F / float(avgtime) * float(avgn);
00383           avgtime = 0; avgn = 0;
00384         }
00385 
00386       // ready for next frame:
00387       frame++;
00388       while(seq->now() < masterclock.getSimTime()) seq->evolve();
00389     }
00390 
00391   // got interrupted; let's cleanup and exit:
00392   d->destroyYUVoverlay();
00393   LINFO("Normal exit");
00394   manager.stop();
00395   return 0;
00396 
00397 #endif // HAVE_SDL_SDL_H
00398 
00399 }
00400 
00401 // ######################################################################
00402 void receiveCMAPS(nub::soft_ref<Beowulf>& beo, std::vector<Image<float> > *cmap,
00403                   int32 *cmapframe)
00404 {
00405   TCPmessage rmsg;      // buffer to receive messages from nodes
00406   int32 rframe, raction, rnode = -1, recnb=0; // receive from any node
00407   while(beo->receive(rnode, rmsg, rframe, raction)) // no wait
00408     {
00409       //LINFO("received %d/%d from %d while at %d",
00410       //    rframe, raction, rnode, frame);
00411       switch(raction & 0xffff)
00412         {
00413         case BEO_CMAP: // ##############################
00414           {
00415             // get the map:
00416             Image<float> ima = rmsg.getElementFloatIma();
00417 
00418             // the map number is stored in the high 16 bits of the
00419             // raction field:
00420             int32 mapn = raction >> 16;
00421             if (mapn < 0 || mapn >= NBCMAP2) {
00422               LERROR("Bogus cmap number ignored");
00423               break;
00424             }
00425 
00426             // here is a totally asynchronous system example: we
00427             // just update our current value of a given cmap if
00428             // the one we just received is more recent than the
00429             // one we had so far:
00430             if (cmapframe[mapn] < rframe)
00431               { cmap->at(mapn) = ima; cmapframe[mapn] = rframe; }
00432           }
00433 
00434           break;
00435         default: // ##############################
00436           LERROR("Bogus action %d -- IGNORING.", raction);
00437           break;
00438         }
00439       // limit number of receives, so we don't hold CPU too long:
00440       recnb ++; if (recnb > NBCMAP2 * 2) break;
00441     }
00442 }
00443 
00444 // ######################################################################
00445 /* So things look consistent in everyone's emacs... */
00446 /* Local Variables: */
00447 /* indent-tabs-mode: nil */
00448 /* End: */
Generated on Sun May 8 08:07:03 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3