00001 /*!@file Nerdcam/nerd-camTCP2.C A parallel vision slave to use w/ pvisionTCP2master */ 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.C $ 00035 // $Id: nerd-camTCP2.C 12074 2009-11-24 07:51:51Z itti $ 00036 // 00037 00038 /*! See the pvisionTCP2go script in bin/ for how to launch the slaves, and 00039 see pvisionTCP2-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/Timer.H" 00056 #include "Util/Types.H" 00057 00058 #include <cstdlib> 00059 #include <signal.h> 00060 #include <time.h> 00061 #include <unistd.h> 00062 #include <cstdio> 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 images 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.5 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("NerdCam 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 Timer tim; // to measure processing speed 00133 TCPmessage rmsg; // message being received and to process 00134 TCPmessage smsg; // message being sent 00135 00136 // let's get all our ModelComponent instances started: 00137 manager.start(); 00138 00139 // wait for data and process it: 00140 while(goforever) 00141 { 00142 int32 rframe, raction, rnode = -1; // receive from any node 00143 if (beo->receive(rnode, rmsg, rframe, raction, 3)) // wait up to 3ms 00144 { 00145 LINFO("Frame %d, action %d from node %d", rframe, raction, rnode); 00146 tim.reset(); 00147 00148 // select processing branch based on frame number: 00149 switch(raction) 00150 { 00151 case BEO_INIT: // ############################## 00152 { 00153 // ooops, someone wants to re-initialize us! 00154 // forget about all our current frames: 00155 for (int i = 0; i < NBOUT; i ++) 00156 { outframe[i] = -1; nbcmap[i] = 0; } 00157 // reinitialization of beowulf is handled automatically. 00158 } 00159 break; 00160 case BEO_RETINA: // ############################## 00161 { 00162 // get the color image: 00163 Image< PixRGB<byte> > ima = rmsg.getElementColByteIma(); 00164 00165 // compute luminance and send it off: 00166 Image<byte> lum = luminance(ima); 00167 smsg.reset(rframe, BEO_LUMINANCE); 00168 smsg.addImage(lum); 00169 beo->send(0, smsg); // send off to luminance slave 00170 00171 // compute RG and BY and send them off: 00172 Image<byte> r, g, b, y; getRGBY(ima, r, g, b, y, (byte)25); 00173 smsg.reset(rframe, BEO_REDGREEN); 00174 smsg.addImage(r); smsg.addImage(g); 00175 beo->send(1, smsg); // send off to RG slave 00176 smsg.reset(rframe, BEO_BLUEYELLOW); 00177 smsg.addImage(b); smsg.addImage(y); 00178 beo->send(2, smsg); // send off to BY slave 00179 } 00180 break; 00181 case BEO_LUMINANCE: // ############################## 00182 { 00183 // first, send off luminance to orientation slaves: 00184 rmsg.setAction(BEO_ORI0); 00185 beo->send(3, rmsg); // send off to ori0 slave 00186 rmsg.setAction(BEO_ORI45); 00187 beo->send(4, rmsg); // send off to ori45 slave 00188 rmsg.setAction(BEO_ORI90); 00189 beo->send(5, rmsg); // send off to ori90 slave 00190 rmsg.setAction(BEO_ORI135); 00191 beo->send(6, rmsg); // send off to ori135 slave 00192 00193 // and also send to flicker slave: 00194 rmsg.setAction(BEO_FLICKER); 00195 beo->send(8, rmsg); // send off to flick slave 00196 00197 // now compute intensity conspicuity map and send to collector: 00198 computeCMAP(rmsg, Gaussian5, 0.0, IWEIGHT, 7, beo); 00199 } 00200 break; 00201 case BEO_FLICKER: 00202 { 00203 // get the luminance image out of the message: 00204 Image<byte> ima = rmsg.getElementByteIma(); 00205 Image<float> fima = ima; // convert to float 00206 00207 // compute flicker consp map and send to collector: 00208 if (previma.initialized() == false) previma = fima; 00209 previma -= fima; 00210 computeCMAP(previma, Gaussian5, 0.0, FWEIGHT, 7, 00211 beo, rframe); 00212 previma = fima; 00213 } 00214 break; 00215 case BEO_REDGREEN: // ############################## 00216 computeCMAP2(rmsg, Gaussian5, 0.0, CWEIGHT, 7, beo); 00217 break; 00218 case BEO_BLUEYELLOW: // ############################## 00219 computeCMAP2(rmsg, Gaussian5, 0.0, CWEIGHT, 7, beo); 00220 break; 00221 case BEO_ORI0: // ############################## 00222 computeCMAP(rmsg, Oriented5, 0.0, OWEIGHT, 7, beo); 00223 break; 00224 case BEO_ORI45: // ############################## 00225 computeCMAP(rmsg, Oriented5, 45.0, OWEIGHT, 7, beo); 00226 break; 00227 case BEO_ORI90: // ############################## 00228 computeCMAP(rmsg, Oriented5, 90.0, OWEIGHT, 7, beo); 00229 break; 00230 case BEO_ORI135: // ############################## 00231 computeCMAP(rmsg, Oriented5, 135.0, OWEIGHT, 7, beo); 00232 break; 00233 case BEO_CMAP: // ############################## 00234 { 00235 // get the map: 00236 Image<float> ima = rmsg.getElementFloatIma(); 00237 00238 // do we already have some accumulated data on this 00239 // frame, or is this a new frame? 00240 int32 oldestidx = 0; 00241 int32 oldestframe = std::numeric_limits<int32>::max(); 00242 int32 curridx = -1; 00243 for (int32 i = 0; i < NBOUT; i ++) 00244 { 00245 if (outframe[i] < oldestframe) 00246 { oldestframe = outframe[i]; oldestidx = i; } 00247 if (outframe[i] == rframe) // ok, already in progress 00248 { curridx = i; break; } 00249 } 00250 00251 // if we are not already processing this frame, set it up, 00252 // possibly dropping oldest frame in buffer if buffer full: 00253 if (curridx == -1) 00254 { 00255 // ok, use oldest frame, then... 00256 curridx = oldestidx; 00257 // was it in progress? 00258 if (nbcmap[curridx]) 00259 { 00260 LINFO("Dropping frame %d!", outframe[curridx]); 00261 char junk[1024], junk2[256]; junk[0] = '\0'; 00262 for (int i = 0; i < NBOUT; i ++) 00263 { 00264 sprintf(junk2, "%d/%d ", outframe[i], nbcmap[i]); 00265 strcat(junk, junk2); 00266 } 00267 LINFO("BUFFER = [ %s]", junk); 00268 } 00269 // now we process frame nb rframe at slot curridx: 00270 outframe[curridx] = rframe; nbcmap[curridx] = 0; 00271 outmap[curridx].resize(ima.getWidth(), 00272 ima.getHeight(), true); 00273 } 00274 00275 // add received cmap to output map: 00276 outmap[curridx] += ima; nbcmap[curridx] ++; 00277 00278 // have we received all the cmaps? 00279 if (nbcmap[curridx] == NBCMAP2) 00280 { 00281 outmap[curridx] = 00282 maxNormalize(outmap[curridx], 0.0f, 9.0f, normtyp); 00283 inplaceClamp(outmap[curridx], 0.0f, 255.0f); 00284 00285 // send result to master: 00286 smsg.reset(outframe[curridx], BEO_WINNER); 00287 Image<byte> smap = outmap[curridx]; // convert to byte 00288 00289 smsg.addImage(smap); 00290 beo->send(-1, smsg); 00291 nbcmap[curridx] = 0; // ready for next frame 00292 //LINFO("sending off %d", outframe[curridx]); 00293 } 00294 } 00295 break; 00296 default: // ############################## 00297 LERROR("Bogus action %d -- IGNORING.", raction); 00298 break; 00299 } 00300 if (rframe % 101 == 0) 00301 LINFO("Action %d, frame %d processed in %llxms", 00302 raction, rframe, tim.get()); 00303 } 00304 } 00305 00306 // we got broken: 00307 manager.stop(); 00308 return 0; 00309 } 00310 00311 // ###################################################################### 00312 void computeCMAP(TCPmessage& msg, const PyramidType ptyp, 00313 const float ori, const float coeff, 00314 const int slave, nub::soft_ref<Beowulf>& b) 00315 { 00316 Image<byte> ima = msg.getElementByteIma(); 00317 Image<float> fima = ima; // convert to float 00318 00319 computeCMAP(fima, ptyp, ori, coeff, slave, b, msg.getID()); 00320 } 00321 00322 // ###################################################################### 00323 void computeCMAP2(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> ima1 = msg.getElementByteIma(); 00328 Image<byte> ima2 = msg.getElementByteIma(); 00329 Image<float> fima = ima1 - ima2; 00330 00331 computeCMAP(fima, ptyp, ori, coeff, slave, b, msg.getID()); 00332 } 00333 00334 // ###################################################################### 00335 void computeCMAP(const Image<float>& fima, const PyramidType ptyp, 00336 const float ori, const float coeff, 00337 const int slave, nub::soft_ref<Beowulf>& b, const int32 id) 00338 { 00339 // compute pyramid: 00340 ImageSet<float> pyr = buildPyrGeneric(fima, 0, maxdepth, 00341 ptyp, ori); 00342 00343 // alloc conspicuity map and clear it: 00344 Image<float> cmap(pyr[sml].getDims(), ZEROS); 00345 00346 // intensities is the max-normalized weighted sum of IntensCS: 00347 for (int delta = delta_min; delta <= delta_max; delta ++) 00348 for (int lev = level_min; lev <= level_max; lev ++) 00349 { 00350 Image<float> tmp = centerSurround(pyr, lev, lev + delta, true); 00351 tmp = downSize(tmp, cmap.getWidth(), cmap.getHeight()); 00352 inplaceAddBGnoise(tmp, 255.0); 00353 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00354 cmap += tmp; 00355 } 00356 if (normtyp == VCXNORM_MAXNORM) 00357 cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp); 00358 else 00359 cmap = maxNormalize(cmap, 0.0f, 0.0f, normtyp); 00360 00361 // multiply by conspicuity coefficient: 00362 cmap *= coeff; 00363 00364 //float mi, ma; getMinMax(cmap, mi, ma); LINFO("[%f .. %f]", mi, ma); 00365 00366 // send off resulting conspicuity map: 00367 TCPmessage smsg(id, BEO_CMAP); 00368 smsg.addImage(cmap); 00369 b->send(slave, smsg); 00370 } 00371 00372 // ###################################################################### 00373 /* So things look consistent in everyone's emacs... */ 00374 /* Local Variables: */ 00375 /* indent-tabs-mode: nil */ 00376 /* End: */