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: */