nerd-camTCP2-master.C

Go to the documentation of this file.
00001 /*!@file Nerdcam/nerd-camTCP2-master.C Grab & process over beowulf w/ pvisionTCP2 */
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/Nerdcam/nerd-camTCP2-master.C $
00035 // $Id: nerd-camTCP2-master.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 /*! This parallel vision processing master is for use with pvisionTCP2.
00039   See the pvisionTCP2go script in bin/ for how to launch the slaves.
00040 */
00041 
00042 #include "Beowulf/Beowulf.H"
00043 #include "Component/ModelManager.H"
00044 #include "Devices/CameraControl.H"
00045 #include "Devices/DeviceOpts.H"
00046 #include "Devices/FrameGrabberConfigurator.H"
00047 #include "GUI/XWindow.H"
00048 #include "Image/ColorOps.H"
00049 #include "Image/CutPaste.H"    // for inplacePaste()
00050 #include "Image/DrawOps.H"
00051 #include "Image/FilterOps.H"
00052 #include "Image/Image.H"
00053 #include "Image/ImageSet.H"
00054 #include "Image/MathOps.H"
00055 #include "Image/Pixels.H"
00056 #include "Image/ShapeOps.H"    // for decX() etc.
00057 #include "Parallel/pvisionTCP-defs.H"
00058 #include "Transport/FrameIstream.H"
00059 #include "Util/Assert.H"
00060 #include "Util/Timer.H"
00061 #include "rutz/shared_ptr.h"
00062 
00063 #include <signal.h>
00064 #include <unistd.h>
00065 
00066 
00067 //! Number of frames over which average framerate is computed
00068 #define NAVG 20
00069 //! Number of stats collected
00070 #define NSTAT 4
00071 
00072 //! prescale level by which we downsize images before sending them off
00073 #define PRESCALE 2
00074 
00075 //! Names of the beowulf slaves
00076 #define SLAVES "n01 n02 n03 n04 n05 n06 n07 n08 n09 n10 n11 n12 n13 n14 \
00077 n15 n16"
00078 
00079 //! shift attention at most once every SHIFTINT frames
00080 #define SHIFTINT 5
00081 
00082 //! injection ratio between new and older sm:
00083 #define SMINJECT 0.6f
00084 
00085 //! threshold salience (between 0 and 255) to warrant a shift of attention
00086 #define SMTHRESH 200
00087 
00088 static bool goforever = true;  //!< Will turn false on interrupt signal
00089 
00090 //! Signal handler (e.g., for control-C)
00091 void terminate(int s)
00092 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); }
00093 
00094 // ######################################################################
00095 int main(const int argc, const char **argv)
00096 {
00097   MYLOGVERB = LOG_INFO;
00098 
00099   // instantiate a model manager:
00100   ModelManager manager("NerdCam WAN");
00101 
00102   // Instantiate our various ModelComponents:
00103   nub::soft_ref<FrameGrabberConfigurator>
00104     gbc(new FrameGrabberConfigurator(manager));
00105   manager.addSubComponent(gbc);
00106 
00107   nub::soft_ref<Beowulf>
00108     beo(new Beowulf(manager, "Beowulf Master", "BeowulfMaster", true));
00109   manager.addSubComponent(beo);
00110 
00111   nub::soft_ref<CameraControl>
00112     camera(new CameraControl(manager, "Camera Controller", "CameraControl",
00113                              0, true, 0));
00114   manager.addSubComponent(camera);
00115 
00116   // choose a V4Lgrabber by default, and a few custom grabbing
00117   // defaults, for backward compatibility with an older version of
00118   // this program:
00119   manager.setOptionValString(&OPT_FrameGrabberType, "V4L");
00120   manager.setOptionValString(&OPT_FrameGrabberDims, "320x240");
00121 
00122   // Parse command-line:
00123   if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1);
00124 
00125   // do post-command-line configs:
00126   nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00127   if (gb.isInvalid())
00128     LFATAL("You need to select a frame grabber type via the "
00129            "--fg-type=XX command-line option for this program "
00130            "to be useful");
00131   int w = gb->getWidth(), h = gb->getHeight();
00132 
00133   // catch signals and redirect them to terminate for clean exit:
00134   signal(SIGHUP, terminate); signal(SIGINT, terminate);
00135   signal(SIGQUIT, terminate); signal(SIGTERM, terminate);
00136   signal(SIGALRM, terminate);
00137 
00138   XWindow xw(Dims(w * 2, h), -1, -1, "USC Nerd Cam");
00139   Image<PixRGB<byte> > disp(w * 2, h, ZEROS);
00140   int32 frame = 0;                // count the frames
00141   PixRGB<byte> pix(255, 255, 0);  // yellow color for fixations
00142   Point2D<int> win(w/2, h/2), winsm; // coordinates of attended location
00143   int foa_size = std::min(w, h) / 12; // radius of focus of attention
00144   TCPmessage rmsg;      // buffer to receive messages from nodes
00145   TCPmessage smsg;      // buffer to send messages to nodes
00146   Timer tim;            // for computation of framerate
00147   Timer camPause;       // to pause the move command
00148   int t[NSTAT][NAVG], ff; // to compute average framerate and other stats
00149   int latency = 0, nlat = 0;  // to compute average processing latency
00150   int lastshift = 0;    // frame of last shift
00151   int sml = 4; Image<byte> sm;
00152   int lastX = w/2; int lastY = h/2;// keep track of last secade
00153   int overTravel = 0;
00154   float move = 0;
00155   float delay = 0;
00156 
00157   // let's get all our ModelComponent instances started:
00158   manager.start();
00159 
00160   // ########## MAIN LOOP: grab, process, display:
00161   while(goforever)
00162     {
00163       // initialize the timer:
00164       tim.reset(); ff = frame % NAVG;
00165 
00166       // grab an image:
00167       Image< PixRGB<byte> > ima = gb->readRGB();
00168       t[0][ff] = tim.getReset();  // grab time
00169 
00170       // send every other image to processing:
00171       if (frame & 1)
00172         {
00173           // prescale image:
00174           Image<PixRGB<byte> > ima2 =
00175             decY(lowPass9y(decX(lowPass9x(ima),1<<PRESCALE)),1<<PRESCALE);
00176 
00177           // we do the job of BEO_RETINA on the master to reduce latency:
00178           // compute luminance and send it off:
00179           Image<byte> lum = luminance(ima2);
00180           smsg.reset(frame, BEO_LUMINANCE);
00181           smsg.addImage(lum);
00182           beo->send(0, smsg);  // send off to luminance slave
00183 
00184           // compute RG and BY and send them off:
00185           Image<byte> r, g, b, y; getRGBY(ima2, r, g, b, y, (byte)25);
00186           smsg.reset(frame, BEO_REDGREEN);
00187           smsg.addImage(r); smsg.addImage(g);
00188           beo->send(1, smsg);  // send off to RG slave
00189           smsg.reset(frame, BEO_BLUEYELLOW);
00190           smsg.addImage(b); smsg.addImage(y);
00191           beo->send(2, smsg);  // send off to BY slave
00192 
00193           t[1][ff] = tim.getReset();  // send out time
00194 
00195           //LINFO("sent frame %d", frame);
00196         }
00197       else
00198         {
00199           // sleep a bit so that we give more CPU to other threads/processes:
00200           struct timespec ts, ts2;
00201           ts.tv_sec = 0; ts.tv_nsec = 5000000;  // sleep 5 ms
00202           nanosleep(&ts, &ts2);
00203 
00204           // duplicate real send time from previous frame:
00205           int ff2 = ff - 1; if (ff2 < 0) ff2 += NAVG;
00206           t[1][ff] = t[1][ff2]; tim.reset();
00207         }
00208 
00209       // receive current coordinates of focus of attention:
00210       int32 rframe, raction, rnode = -1, recnb = 0;  // receive from any node
00211       while(beo->receive(rnode, rmsg, rframe, raction, 5)) // wait up to 5ms
00212         {
00213           // accumulate data for average latency computation:
00214           latency += frame - rframe; nlat ++;
00215           //LINFO("received %d/%d from %d while at %d",
00216           //    rframe, raction, rnode, frame);
00217           switch(raction)
00218             {
00219             case BEO_WINNER: // ##############################
00220               {
00221                 Image<byte> smap = rmsg.getElementByteIma();
00222 
00223                 // trigger IOR at currently-attended location:
00224                 if (sm.initialized() && rframe - lastshift <= SHIFTINT)
00225                   drawDisk(sm, winsm,
00226                            int(ceil(float(foa_size) / (1<<sml))),
00227                            byte(0));
00228 
00229                 // inject newly received saliency map:
00230                 if (sm.initialized())
00231                   sm = sm * (1.1f - SMINJECT) + smap * SMINJECT;
00232                 else
00233                   sm = smap;
00234 
00235                 if (rframe - lastshift >= SHIFTINT)
00236                   {
00237                     // find most salient location:
00238                     byte maxval; findMax(sm, winsm, maxval);
00239 
00240                     // rescale winner coordinates according to PRESCALE:
00241                     win.i = winsm.i << sml;
00242                     win.i += int(((1<<(sml-1)) * float(rand()))/RAND_MAX);
00243                     win.j = winsm.j << sml;
00244                     win.j += int(((1<<(sml-1)) * float(rand()))/RAND_MAX);
00245 
00246                     // just did a shift of attention:
00247                     lastshift = rframe;
00248                   }
00249               }
00250               break;
00251             default: // ##############################
00252               LERROR("Bogus action %d -- IGNORING.", raction);
00253               break;
00254             }
00255           // limit number of receives, so we don't hold CPU too long:
00256           recnb ++; if (recnb > 3) break;
00257         }
00258       t[2][ff] = tim.getReset(); // receive time
00259 
00260       // display image in window:
00261       inplacePaste(disp, ima, Point2D<int>(0, 0));
00262       drawPatch(disp, win, 3, pix);
00263       drawCircle(disp, win, foa_size, pix, 2);
00264 
00265 
00266 
00267       int modi = win.i*2;
00268       int modj = 480-(win.j*2);
00269       lastX = w-win.i;
00270       lastY = h-win.j;
00271 
00272       if(move <= 0)
00273       {
00274         delay = camera->moveCamXYFrame(modi,modj);
00275         LINFO("CAMERA MOVE %d, %d",modi,modj);
00276         camPause.reset();
00277         LINFO("travel time is %f",delay);
00278 
00279         if((lastX >= 0) && (lastX < w) && (lastY >= 0) && (lastY < h))
00280         {
00281           drawCircle(disp, Point2D<int>(lastX,lastY), foa_size, pix, 1);
00282           drawArrow(disp, Point2D<int>(lastX,lastY),win,pix,1);
00283         }
00284         if(delay < 0)
00285         {
00286           writeText(disp, Point2D<int>(50,50),"666");
00287           overTravel++;
00288           LINFO("OVERTRAVEL %d",overTravel);
00289           delay = camera->moveCamXYFrame(320,240);
00290           LINFO("CAMERA MOVE %d, %d",320,240);
00291           camPause.reset();
00292           //delay = 0;
00293         }
00294         move = delay - camPause.get();
00295       }
00296       else
00297       {
00298         move = delay - camPause.get();
00299       }
00300 
00301       if (sm.initialized())
00302         inplacePaste(disp, toRGB(quickInterpolate(sm, 1<<sml)), Point2D<int>(w, 0));
00303       xw.drawImage(disp);
00304 
00305       t[3][ff] = tim.getReset();  // display time
00306       if (t[3][ff] > 20)
00307         LINFO("*** Display took %dms for frame %d", t[3][ff], frame);
00308 
00309 
00310       // compute and show framerate and stats over the last NAVG frames:
00311       if (ff == 1 && frame > 1)
00312         {
00313           float avg[NSTAT], tot = 0.0f;
00314           for (int j = 0; j < NSTAT; j ++)
00315             {
00316               avg[j] = 0.0f;
00317               for (int i = 0; i < NAVG; i ++)
00318                 { avg[j] += t[j][i]; tot += t[j][i]; }
00319               avg[j] /= NAVG;
00320             }
00321           tot /= NAVG;
00322           if (nlat == 0) { latency = -1; nlat = 1; }
00323           LINFO("%.1ffps [G=%.1f S=%.1f R=%.1f D=%.1f T=%.1f F=%.1f]",
00324                 1000.0f / tot, avg[0], avg[1],
00325                 avg[2], avg[3], tot, float(latency) / nlat);
00326           latency = 0; nlat = 0;
00327         }
00328 
00329       // ready for next frame:
00330       frame++;
00331     }
00332 
00333   // got interrupted; let's cleanup and exit:
00334 
00335   // stop all our ModelComponents
00336   manager.stop();
00337   return 0;
00338 }
00339 
00340 // ######################################################################
00341 /* So things look consistent in everyone's emacs... */
00342 /* Local Variables: */
00343 /* indent-tabs-mode: nil */
00344 /* End: */
Generated on Sun May 8 08:05:24 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3