pvisionTCP.C

Go to the documentation of this file.
00001 /*!@file Parallel/pvisionTCP.C A parallel vision slave to use with pvisionTCPmaster */
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/pvisionTCP.C $
00035 // $Id: pvisionTCP.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 /*! See the pvisionTCPgo script in bin/ for how to launch the slaves, and
00039   see pvisionTCP-master.C for the master program.
00040 */
00041 
00042 #include "Beowulf/Beowulf.H"
00043 #include "Component/ModelManager.H"
00044 #include "Image/ColorOps.H"
00045 #include "Image/Image.H"
00046 #include "Image/ImageSet.H"
00047 #include "Image/MathOps.H"
00048 #include "Image/Pixels.H"
00049 #include "Image/PyramidOps.H"
00050 #include "Image/ShapeOps.H"
00051 #include "Image/Transforms.H"
00052 #include "Image/fancynorm.H"
00053 #include "Parallel/pvisionTCP-defs.H"
00054 #include "Util/Assert.H"
00055 #include "Util/Types.H"
00056 #include "Util/sformat.H"
00057 
00058 #include <cstdlib>
00059 #include <limits>
00060 #include <signal.h>
00061 #include <time.h>
00062 #include <unistd.h>
00063 
00064 static bool goforever = true;  //!< Will turn false on interrupt signal
00065 
00066 //! Signal handler (e.g., for control-C)
00067 void terminate(int s) { LERROR("*** INTERRUPT ***"); goforever = false; }
00068 
00069 //! Compute a conspicuity map from an image received in a message
00070 void computeCMAP(TCPmessage& msg, const PyramidType ptyp,
00071                  const float ori, const float coeff,
00072                  const int slave, nub::soft_ref<Beowulf>& b);
00073 
00074 //! Compute a conspicuity map from two imagew received in a message
00075 void computeCMAP2(TCPmessage& msg, const PyramidType ptyp,
00076                  const float ori, const float coeff,
00077                  const int slave, nub::soft_ref<Beowulf>& b);
00078 
00079 //! Compute a conspicuity map from an image
00080 void computeCMAP(const Image<float>& fima, const PyramidType ptyp,
00081                  const float ori, const float coeff,
00082                  const int slave, nub::soft_ref<Beowulf>& b, const int32 id);
00083 
00084 // ######################################################################
00085 // ##### Global options:
00086 // ######################################################################
00087 #define sml        2
00088 #define delta_min  3
00089 #define delta_max  4
00090 #define level_min  0
00091 #define level_max  2
00092 #define maxdepth   (level_max + delta_max + 1)
00093 #define normtyp    (VCXNORM_MAXNORM)
00094 
00095 // number of output saliency maps kept in buffer (to accomodate for
00096 // speed variations):
00097 #define NBOUT 10
00098 
00099 // relative feature weights:
00100 #define IWEIGHT 1.0
00101 #define CWEIGHT 1.0
00102 #define OWEIGHT 1.0
00103 #define FWEIGHT 1.0
00104 
00105 // ######################################################################
00106 int main(const int argc, const char **argv)
00107 {
00108   MYLOGVERB = LOG_INFO;
00109 
00110   // instantiate a model manager:
00111   ModelManager manager("Parallel Vision TCP - Slave");
00112 
00113   // Instantiate our various ModelComponents:
00114   nub::soft_ref<Beowulf>
00115     beo(new Beowulf(manager, "Beowulf Slave", "BeowulfSlave", false));
00116   manager.addSubComponent(beo);
00117 
00118   // Parse command-line:
00119   if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1);
00120 
00121   // setup signal handling:
00122   signal(SIGHUP, terminate); signal(SIGINT, terminate);
00123   signal(SIGQUIT, terminate); signal(SIGTERM, terminate);
00124   initRandomNumbers();
00125 
00126   // various processing inits:
00127   Image<float> outmap[NBOUT]; // array of output saliency maps
00128   int32 outframe[NBOUT];      // array of output frame numbers
00129   int nbcmap[NBOUT];          // how many consp maps in each outmap
00130   for (int i = 0; i < NBOUT; i ++) { outframe[i] = -1; nbcmap[i] = 0; }
00131   Image<float> previma;       // previous image; for flicker processing
00132   TCPmessage rmsg;                 // message being received and to process
00133   TCPmessage smsg;                 // message being sent
00134 
00135   // let's get all our ModelComponent instances started:
00136   manager.start();
00137 
00138   // wait for data and process it:
00139   while(goforever)
00140     {
00141       int32 rframe, raction, rnode = -1;  // receive from any node
00142       if (beo->receive(rnode, rmsg, rframe, raction, 3)) // wait up to 3ms
00143         {
00144           //LINFO("Frame %d, action %d from node %d", rframe, raction, rnode);
00145           // select processing branch based on frame number:
00146           int32 offset; if (rframe & 1) offset = POFFSET; else offset = 0;
00147 
00148           switch(raction)
00149             {
00150             case BEO_INIT:       // ##############################
00151               {
00152                 // ooops, someone wants to re-initialize us!
00153                 // forget about all our current frames:
00154                 for (int i = 0; i < NBOUT; i ++)
00155                   { outframe[i] = -1; nbcmap[i] = 0; }
00156                 // reinitialization of beowulf is handled automatically.
00157               }
00158               break;
00159             case BEO_RETINA:     // ##############################
00160               {
00161                 // get the color image:
00162                 Image<PixRGB<byte> > ima = rmsg.getElementColByteIma();
00163 
00164                 // compute luminance and send it off:
00165                 Image<byte> lum = luminance(ima);
00166                 smsg.reset(rframe, BEO_LUMINANCE);
00167                 smsg.addImage(lum);
00168                 beo->send(offset + 0, smsg);  // send off to luminance slave
00169 
00170                 // compute RG and BY and send them off:
00171                 Image<byte> r, g, b, y; getRGBY(ima, r, g, b, y, (byte)25);
00172                 smsg.reset(rframe, BEO_REDGREEN);
00173                 smsg.addImage(r); smsg.addImage(g);
00174                 beo->send(offset + 1, smsg);  // send off to RG slave
00175                 smsg.reset(rframe, BEO_BLUEYELLOW);
00176                 smsg.addImage(y); smsg.addImage(y);
00177                 beo->send(offset + 2, smsg);  // send off to BY slave
00178               }
00179               break;
00180             case BEO_LUMINANCE:  // ##############################
00181               {
00182                 // first, send off luminance to orientation slaves:
00183                 rmsg.setAction(BEO_ORI0);
00184                 beo->send(offset + 3, rmsg);  // send off to ori0 slave
00185                 rmsg.setAction(BEO_ORI45);
00186                 beo->send(offset + 4, rmsg);  // send off to ori45 slave
00187                 rmsg.setAction(BEO_ORI90);
00188                 beo->send(offset + 5, rmsg);  // send off to ori90 slave
00189                 rmsg.setAction(BEO_ORI135);
00190                 beo->send(offset + 6, rmsg);  // send off to ori135 slave
00191 
00192                 // and also send to flicker slave:
00193                 //rmsg.setAction(BEO_FLICKER);
00194                 //beo->send(offset + 1, rmsg);  // send off to flick slave
00195 
00196                 // now compute intensity conspicuity map and send to collector:
00197                 computeCMAP(rmsg, Gaussian5, 0.0, IWEIGHT, offset + 7, beo);
00198               }
00199               break;
00200             case BEO_FLICKER:
00201               {
00202                 // get the luminance image out of the message:
00203                 Image<byte> ima = rmsg.getElementByteIma();
00204                 Image<float> fima = ima;  // convert to float
00205 
00206                 // compute flicker consp map and send to collector:
00207                 if (previma.initialized() == false) previma = fima;
00208                 previma -= fima;
00209                 computeCMAP(previma, Gaussian5, 0.0, FWEIGHT, offset + 7,
00210                             beo, rframe);
00211                 previma = fima;
00212               }
00213               break;
00214             case BEO_REDGREEN:   // ##############################
00215               computeCMAP2(rmsg, Gaussian5, 0.0, CWEIGHT, offset + 7, beo);
00216               break;
00217             case BEO_BLUEYELLOW: // ##############################
00218               computeCMAP2(rmsg, Gaussian5, 0.0, CWEIGHT, offset + 7, beo);
00219               break;
00220             case BEO_ORI0:       // ##############################
00221               computeCMAP(rmsg, Oriented5, 0.0, OWEIGHT, offset + 7, beo);
00222               break;
00223             case BEO_ORI45:      // ##############################
00224               computeCMAP(rmsg, Oriented5, 45.0, OWEIGHT, offset + 7, beo);
00225               break;
00226             case BEO_ORI90:      // ##############################
00227               computeCMAP(rmsg, Oriented5, 90.0, OWEIGHT, offset + 7, beo);
00228               break;
00229             case BEO_ORI135:     // ##############################
00230               computeCMAP(rmsg, Oriented5, 135.0, OWEIGHT, offset + 7, beo);
00231               break;
00232             case BEO_CMAP:       // ##############################
00233               {
00234                 // get the map:
00235                 Image<float> ima = rmsg.getElementFloatIma();
00236 
00237                 // do we already have some accumulated data on this
00238                 // frame, or is this a new frame?
00239                 int32 oldestidx = 0;
00240                 int32 oldestframe = std::numeric_limits<int32>::max();
00241                 int32 curridx = -1;
00242                 for (int i = 0; i < NBOUT; i ++)
00243                   {
00244                     if (outframe[i] < oldestframe)
00245                       { oldestframe = outframe[i]; oldestidx = i; }
00246                     if (outframe[i] == rframe) // ok, already in progress
00247                       { curridx = i; break; }
00248                   }
00249 
00250                 // if we are not already processing this frame, set it up,
00251                 // possibly dropping oldest frame in buffer if buffer full:
00252                 if (curridx == -1)
00253                   {
00254                     // ok, use oldest frame, then...
00255                     curridx = oldestidx;
00256                     // was it in progress?
00257                     if (nbcmap[curridx])
00258                       {
00259                         LINFO("Dropping frame %d!", outframe[curridx]);
00260                         std::string junk;
00261                         for (int i = 0; i < NBOUT; i ++)
00262                           junk += sformat("%d/%d ", outframe[i], nbcmap[i]);
00263 
00264                         LINFO("BUFFER = [ %s]", junk.c_str());
00265                       }
00266                     // now we process frame nb rframe at slot curridx:
00267                     outframe[curridx] = rframe; nbcmap[curridx] = 0;
00268                     outmap[curridx].resize(ima.getWidth(),
00269                                            ima.getHeight(), true);
00270                   }
00271 
00272                 // add received cmap to output map:
00273                 outmap[curridx] += ima; nbcmap[curridx] ++;
00274 
00275                 // have we received all the cmaps?
00276                 if (nbcmap[curridx] == NBCMAP)
00277                   {
00278                     outmap[curridx] =
00279                       maxNormalize(outmap[curridx], 0.0f, 2.0f, normtyp);
00280                     // output is now in the (0.0..8.0) range;
00281                     // typical images are in (0..4) range;
00282                     // we want input current in nA
00283                     outmap[curridx] *= 1.0e-9;
00284 
00285                     // add a tiny background activity:
00286                     inplaceAddBGnoise(outmap[curridx], 1.0e-12);
00287                     outmap[curridx] += 1.0e-14;
00288 
00289                     // find most salient location:
00290                     Point2D<int> win; float maxval;
00291                     findMax(outmap[curridx], win, maxval);
00292 
00293                     // rescale those coordinates to scale of original image:
00294                     win.i <<= sml;
00295                     win.i += int(((1 << (sml - 1)) *
00296                                   float(rand())) / RAND_MAX);
00297                     win.j <<= sml;
00298                     win.j += int(((1 << (sml - 1)) *
00299                                   float(rand())) / RAND_MAX);
00300 
00301                     // send result to master:
00302                     smsg.reset(outframe[curridx], BEO_WINNER);
00303                     smsg.addFixation(Fixation(win, rframe));
00304                     beo->send(-1, smsg);
00305                     nbcmap[curridx] = 0;  // ready for next frame
00306                     //LINFO("sending off %d", outframe[curridx]);
00307                   }
00308               }
00309               break;
00310             default: // ##############################
00311               LERROR("Bogus action %d -- IGNORING.", raction);
00312               break;
00313             }
00314         }
00315     }
00316 
00317   // we got broken:
00318   manager.stop();
00319   return 0;
00320 }
00321 
00322 // ######################################################################
00323 void computeCMAP(TCPmessage& msg, const PyramidType ptyp,
00324                  const float ori, const float coeff,
00325                  const int slave, nub::soft_ref<Beowulf>& b)
00326 {
00327   Image<byte> ima = msg.getElementByteIma();
00328   Image<float> fima = ima; // convert to float
00329 
00330   computeCMAP(fima, ptyp, ori, coeff, slave, b, msg.getID());
00331 }
00332 
00333 // ######################################################################
00334 void computeCMAP2(TCPmessage& msg, const PyramidType ptyp,
00335                  const float ori, const float coeff,
00336                  const int slave, nub::soft_ref<Beowulf>& b)
00337 {
00338   Image<byte> ima1 = msg.getElementByteIma();
00339   Image<byte> ima2 = msg.getElementByteIma();
00340   Image<float> fima = ima1 - ima2;
00341 
00342   computeCMAP(fima, ptyp, ori, coeff, slave, b, msg.getID());
00343 }
00344 
00345 // ######################################################################
00346 void computeCMAP(const Image<float>& fima, const PyramidType ptyp,
00347                  const float ori, const float coeff,
00348                  const int slave, nub::soft_ref<Beowulf>& b, const int32 id)
00349 {
00350   // compute pyramid:
00351   ImageSet<float> pyr = buildPyrGeneric(fima, 0, maxdepth, ptyp, ori);
00352 
00353   // alloc conspicuity map and clear it:
00354   Image<float> cmap(pyr[sml].getDims(), ZEROS);
00355 
00356   // intensities is the max-normalized weighted sum of IntensCS:
00357   for (int delta = delta_min; delta <= delta_max; delta ++)
00358     for (int lev = level_min; lev <= level_max; lev ++)
00359       {
00360         Image<float> tmp = centerSurround(pyr, lev, lev + delta, true);
00361         tmp = downSize(tmp, cmap.getWidth(), cmap.getHeight());
00362         inplaceAddBGnoise(tmp, 255.0);
00363         tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp);
00364         cmap += tmp;
00365       }
00366   if (normtyp == VCXNORM_MAXNORM)
00367     cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp);
00368   else
00369     cmap = maxNormalize(cmap, 0.0f, 0.0f, normtyp);
00370 
00371   // multiply by conspicuity coefficient:
00372   cmap *= coeff;
00373 
00374   //float mi, ma; getMinMax(cmap, mi, ma); LINFO("[%f .. %f]", mi, ma);
00375 
00376   // send off resulting conspicuity map:
00377   TCPmessage smsg(id, BEO_CMAP);
00378   smsg.addImage(cmap);
00379   b->send(slave, smsg);
00380 }
00381 
00382 // ######################################################################
00383 /* So things look consistent in everyone's emacs... */
00384 /* Local Variables: */
00385 /* indent-tabs-mode: nil */
00386 /* End: */
Generated on Sun May 8 08:05:30 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3