pvisionTCP4-master.C

Go to the documentation of this file.
00001 /*!@file Parallel/pvisionTCP4-master.C Grab & process over beowulf w/ pvisionTCP3. Like pvisionTCP3 but with input and output FrameSeries */
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/pvisionTCP4-master.C $
00035 // $Id: $
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 #include "Media/FrameSeries.H"
00077 #include "Transport/FrameInfo.H"
00078 
00079 #include <signal.h>
00080 #include <unistd.h>
00081 
00082 
00083 //! prescale level by which we downsize images before sending them off
00084 #define PRESCALE            2
00085 
00086 //! averaging window
00087 #define NAVG               20
00088 #define TOTAL_FRAMES      100
00089 
00090 static bool goforever = true;  //!< Will turn false on interrupt signal
00091 
00092 //! Signal handler (e.g., for control-C)
00093 void terminate(int s)
00094 { LERROR("*** INTERRUPT ***"); goforever = false; }// exit(1); }
00095 
00096 //! function to receive results from slaves
00097 void receiveCMAPS(nub::soft_ref<Beowulf>& beo, Image<float> *cmap,
00098                   int32 *cmapframe);
00099 uint nCMAPSreceived;  
00100 // ######################################################################
00101 int submain(int argc, char** argv)
00102 {
00103 #ifndef HAVE_SDL_SDL_H
00104   LFATAL("<SDL/SDL.h> must be installed to use this program");
00105 #else
00106   MYLOGVERB = LOG_INFO;
00107 
00108   // instantiate a model manager:
00109   ModelManager manager("Parallel Vision TCP Version 3");
00110 
00111   // Instantiate our various ModelComponents:
00112   nub::soft_ref<SimEventQueueConfigurator>
00113     seqc(new SimEventQueueConfigurator(manager));
00114   manager.addSubComponent(seqc);
00115 
00116   nub::soft_ref<InputFrameSeries> ifs(new InputFrameSeries(manager));
00117   manager.addSubComponent(ifs);
00118 
00119   nub::soft_ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager));
00120   manager.addSubComponent(ofs);
00121 
00122   // nub::soft_ref<FrameGrabberConfigurator>
00123   //   gbc(new FrameGrabberConfigurator(manager));
00124   // manager.addSubComponent(gbc);
00125 
00126   nub::soft_ref<Beowulf>
00127     beo(new Beowulf(manager, "Beowulf Master", "BeowulfMaster", true));
00128   manager.addSubComponent(beo);
00129 
00130   // nub::soft_ref<SDLdisplay>
00131   //   d(new SDLdisplay(manager));
00132   // manager.addSubComponent(d);
00133 
00134   //  nub::soft_ref<ThresholdFrictionSaccadeController>
00135   //  sc(new ThresholdFrictionSaccadeController(manager));
00136   nub::soft_ref<SaccadeControllerEyeConfigurator>
00137     scc(new SaccadeControllerEyeConfigurator(manager));
00138   manager.addSubComponent(scc);
00139 
00140   // let's set a bunch of defauls:
00141   manager.setOptionValString(&OPT_SaccadeControllerEyeType, "Threshfric");
00142   manager.setOptionValString(&OPT_FrameGrabberType, "V4L");
00143   manager.setOptionValString(&OPT_SCeyeMaxIdleSecs, "1000.0");
00144   manager.setOptionValString(&OPT_SCeyeThreshMinOvert, "4.0");
00145   manager.setOptionValString(&OPT_SCeyeThreshMaxCovert, "3.0");
00146   //  manager.setOptionValString(&OPT_SCeyeSpringK, "1000000.0");
00147 
00148   // Parse command-line:
00149   if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1);
00150 
00151   // do post-command-line configs:
00152   nub::soft_ref<SimEventQueue> seq = seqc->getQ();
00153 
00154   // nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00155   // if (gb.isInvalid())
00156   //   LFATAL("You need to select a frame grabber type via the "
00157   //          "--fg-type=XX command-line option for this program "
00158   //          "to be useful");
00159   // int w = gb->getWidth(), h = gb->getHeight();
00160 
00161   int w = ifs->getWidth(),  h = ifs->getHeight();
00162   std::string dims = convertToString(Dims(w, h));
00163   LINFO("image size: [%dx%d]", w, h);
00164   //manager.setOptionValString(&OPT_InputFrameDims, dims);
00165 
00166   manager.setModelParamVal("InputFrameDims", Dims(w, h),
00167                            MC_RECURSE | MC_IGNORE_MISSING);
00168 
00169   nub::ref<SaccadeController> sc = scc->getSC();
00170 
00171   const int foa_size = 64;
00172   manager.setModelParamVal("InputFrameDims", Dims(w, h),
00173                            MC_RECURSE | MC_IGNORE_MISSING);
00174   manager.setModelParamVal("SCeyeStartAtIP", true,
00175                            MC_RECURSE | MC_IGNORE_MISSING);
00176   manager.setModelParamVal("SCeyeInitialPosition",Point2D<int>(w/2,h/2),
00177                            MC_RECURSE | MC_IGNORE_MISSING);
00178   manager.setModelParamVal("FOAradius", foa_size,
00179                            MC_RECURSE | MC_IGNORE_MISSING);
00180   manager.setModelParamVal("FoveaRadius", foa_size,
00181                            MC_RECURSE | MC_IGNORE_MISSING);
00182   //manager.setModelParamVal("SimulationTimeStep", SimTime::MSECS(1.0),
00183   //                         MC_RECURSE | MC_IGNORE_MISSING);
00184 
00185   // catch signals and redirect them to terminate for clean exit:
00186   signal(SIGHUP, terminate); signal(SIGINT, terminate);
00187   signal(SIGQUIT, terminate); signal(SIGTERM, terminate);
00188   signal(SIGALRM, terminate);
00189 
00190   // get prepared to grab, communicate, display, etc:
00191   PixRGB<byte> pix(255, 255, 0);    // yellow color for fixations
00192   TCPmessage smsg;                  // buffer to send messages to nodes
00193   FpsTimer tim;                     // for computation of framerate
00194   Timer masterclock;                // master clock for simulations
00195 
00196   Image<float> cmap[NBCMAP2];       // array of conspicuity maps
00197   int32 cmapframe[NBCMAP2];         // array of cmap frame numbers
00198   for (int i = 0; i < NBCMAP2; i ++) cmapframe[i] = -1;
00199   int sml = 4;                      // pyramid level of saliency map
00200   Image<float> sm(w >> sml, h >> sml, ZEROS); // saliency map
00201   Point2D<int> fixation(-1, -1);         // coordinates of eye fixation
00202 
00203   nCMAPSreceived = 0;
00204 
00205   // image buffer for display:
00206   const PixRGB<byte> grey(127);
00207   std::string info;
00208 
00209   // adjust SDL display size:
00210   //d->setModelParamVal("SDLdisplayDims", gb->peekDims());
00211 
00212   // let's get all our ModelComponent instances started:
00213   manager.start();
00214 
00215   // clear screen
00216   //d->clearScreen(grey);
00217   //d->displayText("<SPACE> to start - <SPACE> again to quit", false,
00218   //               PixRGB<byte>(0), grey);
00219   //while(d->waitForKey() != ' ') ;
00220   //d->clearScreen(grey);
00221 
00222   // create an overlay:
00223   //d->createYUVoverlay(SDL_YV12_OVERLAY);
00224 
00225   // get the frame grabber to start streaming:
00226   //gb->startStream();
00227 
00228   // initialize the timers:
00229   masterclock.reset();
00230   
00231   Timer timer(1000000);
00232   // ##### MAIN LOOP:
00233   uint fNum = 0;
00234   ifs->updateNext(); Image< PixRGB<byte> > ima = ifs->readRGB();
00235   if(!ima.initialized()) { goforever = false; }
00236   uint nCMAPSsent = 0;
00237   //while(goforever)
00238   while(nCMAPSreceived < TOTAL_FRAMES*8)
00239     {
00240       timer.reset();
00241       // receive conspicuity maps:
00242       receiveCMAPS(beo, cmap, cmapframe);
00243       uint64 t1 = timer.get();
00244       LINFO("time1[%d]: %f", fNum, t1/1000.0F);
00245 
00246       // grab an image:
00247       //Image< PixRGB<byte> > ima = gb->readRGB();
00248       //ifs->updateNext(); Image< PixRGB<byte> > ima = ifs->readRGB();
00249       //if(!ima.initialized()) { goforever = false; }
00250 
00251       // display image in window:
00252       //Image<float> dispsm(sm); inplaceNormalize(dispsm, 0.0F, 255.0F);
00253       //Image<byte> dispsmb = dispsm; dispsmb = quickInterpolate(dispsmb, 2);
00254       //inplacePaste(ima, toRGB(dispsmb), Point2D<int>(w-dispsmb.getWidth(), 0));
00255       //drawRect(ima, Rectangle(Point2D<int>(w-dispsmb.getWidth()-1, 0),
00256       //                        dispsmb.getDims()), pix);
00257 
00258       sc->evolve(*seq);
00259       Point2D<int> eye = sc->getDecision(*seq);
00260       if (eye.isValid()) fixation = eye;
00261       uint64 t2 = timer.get();
00262       LINFO("time2[%d]: %f", fNum, (t2-t1)/1000.0F);
00263 
00264       //if (fixation.isValid())
00265       //  {
00266       //    drawPatch(ima, fixation, 2, pix);
00267       //    drawCircle(ima, fixation, foa_size, pix, 2);
00268       //  }
00269       //writeText(ima, Point2D<int>(0, 0),
00270       //          sformat(" %.1ffps ", tim.getRecentFps()).c_str(),
00271       //          PixRGB<byte>(255), grey);
00272       //writeText(ima, Point2D<int>(0, h-20), info.c_str(),
00273       //          PixRGB<byte>(255), grey);
00274 
00275       // SDL_Overlay* ovl = d->lockYUVoverlay();
00276       // toVideoYUV422(ima, ovl->pixels[0], ovl->pixels[2], ovl->pixels[1]);
00277       // d->unlockYUVoverlay();
00278       //d->displayYUVoverlay(-1, SDLdisplay::NO_WAIT);
00279       //ofs->writeRGB(ima, "display", FrameInfo("display",SRC_POS));
00280       LINFO(" %.1ffps ", tim.getRecentFps());
00281 
00282       // check for space bar pressed; note: will abort us violently if
00283       // ESC is pressed instead:
00284       //if (d->checkForKey() == ' ') goforever = false;
00285 
00286       // receive conspicuity maps:
00287       receiveCMAPS(beo, cmap, cmapframe);
00288 
00289       // send every other frame to processing:
00290       //if (tim.frameNumber() & 1)
00291       if (nCMAPSsent < TOTAL_FRAMES)
00292         {
00293           nCMAPSsent++;
00294 
00295           const int32 frame = int32(tim.frameNumber());
00296 
00297           // prescale image:
00298           //Image<PixRGB<byte> > ima2 =
00299           //  decY(lowPass5y(decX(lowPass5x(ima),1<<PRESCALE)),1<<PRESCALE);
00300           Image<PixRGB<byte> > ima2 =
00301             decY(decX(ima,1<<PRESCALE),1<<PRESCALE);
00302 
00303           uint64 t3a = timer.get();
00304           LINFO("time3a[%d]: %f", fNum, (t3a-t2)/1000.0F);
00305 
00306           // we do the job of BEO_RETINA on the master to reduce latency:
00307           // compute luminance and send it off:
00308           Image<byte> lum = luminance(ima2);
00309           //Image<byte> lum = luminance(ima);
00310 
00311           uint64 t3b = timer.get();
00312           LINFO("time3b[%d]: %f", fNum, (t3b-t3a)/1000.0F);
00313 
00314           // first, send off luminance to orientation slaves:
00315           smsg.reset(frame, BEO_ORI0); smsg.addImage(lum); beo->send(smsg);
00316           smsg.setAction(BEO_ORI15); beo->send(smsg);
00317           smsg.setAction(BEO_ORI30); beo->send(smsg);
00318           smsg.setAction(BEO_ORI45); beo->send(smsg);
00319           smsg.setAction(BEO_ORI60); beo->send(smsg);
00320           smsg.setAction(BEO_ORI75); beo->send(smsg);
00321           smsg.setAction(BEO_ORI90); beo->send(smsg);
00322           smsg.setAction(BEO_ORI105); beo->send(smsg);
00323           smsg.setAction(BEO_ORI120); beo->send(smsg);
00324           smsg.setAction(BEO_ORI135); beo->send(smsg);
00325           smsg.setAction(BEO_ORI150); beo->send(smsg);
00326           smsg.setAction(BEO_ORI165); beo->send(smsg);
00327 
00328           // and also send to flicker slave:
00329           smsg.setAction(BEO_FLICKER); beo->send(smsg);
00330 
00331           // finally, send to luminance slave:
00332           smsg.setAction(BEO_LUMINANCE); beo->send(smsg);
00333 
00334           uint64 t3c = timer.get();
00335           LINFO("time3c[%d]: %f", fNum, (t3c-t3b)/1000.0F);
00336 
00337           // compute RG and BY and send them off:
00338           Image<byte> r, g, b, y; getRGBY(ima2, r, g, b, y, (byte)25);
00339           //Image<byte> r, g, b, y; getRGBY(ima, r, g, b, y, (byte)25);
00340           smsg.reset(frame, BEO_REDGREEN);
00341           smsg.addImage(r); smsg.addImage(g); beo->send(smsg);
00342           smsg.reset(frame, BEO_BLUEYELLOW);
00343           smsg.addImage(b); smsg.addImage(y); beo->send(smsg);
00344 
00345           uint64 t3d = timer.get();
00346           LINFO("time3d[%d]: %f", fNum, (t3d-t3c)/1000.0F);          
00347         }
00348 
00349       uint64 t3 = timer.get();
00350       LINFO("time3[%d]: %f", fNum, (t3-t2)/1000.0F);
00351 
00352       // receive conspicuity maps:
00353       receiveCMAPS(beo, cmap, cmapframe);
00354 
00355       // build our current saliency map:
00356       info = sformat("%06d / ", tim.frameNumber());
00357       Image<float> sminput;
00358       for (int i = 0; i < NBCMAP2; i ++)
00359         if (cmap[i].initialized())
00360           {
00361             if (sminput.initialized()) sminput += cmap[i];
00362             else sminput = cmap[i];
00363             info += sformat("%06d ", cmapframe[i]);
00364           }
00365         else
00366           info += "------ ";
00367 
00368       // inject saliency map input into saliency map:
00369       if (sminput.initialized()) sm = sm * 0.7F + sminput * 0.3F;
00370 
00371       // evolve our saccade controller up to now:
00372       while(seq->now() < masterclock.getSimTime()) seq->evolve();
00373       sc->evolve(*seq);
00374 
00375       // find most salient location and feed saccade controller:
00376       float maxval; Point2D<int> currwin; findMax(sm, currwin, maxval);
00377       WTAwinner newwin =
00378         WTAwinner::buildFromSMcoords(currwin, sml, true,
00379                                      masterclock.getSimTime(),
00380                                      maxval, false);
00381       if (newwin.isValid()) sc->setPercept(newwin, *seq);
00382 
00383       uint64 t4 = timer.get();
00384       LINFO("time4[%d]: %f", fNum, (t4-t3)/1000.0F);
00385 
00386       // receive conspicuity maps:
00387       receiveCMAPS(beo, cmap, cmapframe);
00388 
00389       // ready for next frame:
00390       tim.nextFrame();
00391       while(seq->now() < masterclock.getSimTime()) seq->evolve();
00392 
00393       uint64 t5 = timer.get();
00394       LINFO("time5[%d]: %f", fNum, (t5-t4)/1000.0F);
00395 
00396       fNum++;
00397     }
00398 
00399   // got interrupted; let's cleanup and exit:
00400   //d->destroyYUVoverlay();
00401   //double frate = tim.frameNumber() / (tim.getElapsedTime()).sec();
00402   //LINFO("Fr: %6.3f fps -> %8.3f ms/f\n", frate, 1000.0/frate);
00403   double time = (tim.getElapsedTime()).sec();
00404   double frate = TOTAL_FRAMES/time;
00405   LINFO("[%6d]: %15.6fsec:  %6.3f fps -> %8.3f ms/f\n", 
00406         fNum, time, frate, 1000/frate);
00407 
00408   LINFO("Normal exit");
00409   manager.stop();
00410 #endif
00411   return 0;
00412 }
00413 
00414 // ######################################################################
00415 void receiveCMAPS(nub::soft_ref<Beowulf>& beo, Image<float> *cmap,
00416                   int32 *cmapframe)
00417 {
00418   TCPmessage rmsg;      // buffer to receive messages from nodes
00419   int32 rframe, raction, rnode = -1, recnb=0; // receive from any node
00420   while(beo->receive(rnode, rmsg, rframe, raction)) // no wait
00421     {
00422       nCMAPSreceived++; 
00423       LINFO("--------------> nCMAPSreceived: %6d", nCMAPSreceived);
00424       //LINFO("received %d/%d from %d while at %d",
00425       //    rframe, raction, rnode, frame);
00426       switch(raction & 0xffff)
00427         {
00428         case BEO_CMAP: // ##############################
00429           {
00430             // get the map:
00431             Image<float> ima = rmsg.getElementFloatIma();
00432 
00433             // the map number is stored in the high 16 bits of the
00434             // raction field:
00435             int32 mapn = raction >> 16;
00436             if (mapn < 0 || mapn >= NBCMAP4) {
00437               LERROR("Bogus cmap number ignored");
00438               break;
00439             }
00440 
00441             // here is a totally asynchronous system example: we
00442             // just update our current value of a given cmap if
00443             // the one we just received is more recent than the
00444             // one we had so far:
00445             if (cmapframe[mapn] < rframe)
00446               { cmap[mapn] = ima; cmapframe[mapn] = rframe; }
00447           }
00448 
00449           break;
00450         default: // ##############################
00451           LERROR("Bogus action %d -- IGNORING.", raction);
00452           break;
00453         }
00454       // limit number of receives, so we don't hold CPU too long:
00455       recnb ++; if (recnb > NBCMAP4 * 2) break;
00456     }
00457 }
00458 
00459 // ######################################################################
00460 extern "C" int main(int argc, char** argv)
00461 {
00462   try
00463     {
00464       return submain(argc, argv);
00465     }
00466   catch (...)
00467     {
00468       REPORT_CURRENT_EXCEPTION;
00469       return 1;
00470     }
00471   return 0;
00472 }
00473 
00474 // ######################################################################
00475 /* So things look consistent in everyone's emacs... */
00476 /* Local Variables: */
00477 /* indent-tabs-mode: nil */
00478 /* End: */
Generated on Sun May 8 08:41:08 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3