00001 /*!@file Parallel/pvisionTCP2-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/Parallel/pvisionTCP2-master.C $ 00035 // $Id: pvisionTCP2-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/FrameGrabberConfigurator.H" 00045 #include "GUI/XWindow.H" 00046 #include "Image/ColorOps.H" 00047 #include "Image/CutPaste.H" // for inplacePaste() 00048 #include "Image/DrawOps.H" 00049 #include "Image/FilterOps.H" 00050 #include "Image/Image.H" 00051 #include "Image/Image.H" 00052 #include "Image/ImageSet.H" 00053 #include "Image/MathOps.H" 00054 #include "Image/Pixels.H" 00055 #include "Image/ShapeOps.H" // for decX() etc. 00056 #include "Parallel/pvisionTCP-defs.H" 00057 #include "Transport/FrameIstream.H" 00058 #include "Util/Assert.H" 00059 #include "Util/Timer.H" 00060 00061 #include <signal.h> 00062 #include <unistd.h> 00063 00064 00065 //! Number of frames over which average framerate is computed 00066 #define NAVG 20 00067 //! Number of stats collected 00068 #define NSTAT 4 00069 00070 //! prescale level by which we downsize images before sending them off 00071 #define PRESCALE 2 00072 00073 //! shift attention at most once every SHIFTINT frames 00074 #define SHIFTINT 5 00075 00076 //! injection ratio between new and older sm: 00077 #define SMINJECT 0.6f 00078 00079 //! threshold salience (between 0 and 255) to warrant a shift of attention 00080 #define SMTHRESH 200 00081 00082 static bool goforever = true; //!< Will turn false on interrupt signal 00083 00084 //! Signal handler (e.g., for control-C) 00085 void terminate(int s) 00086 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); } 00087 00088 // ###################################################################### 00089 int main(const int argc, const char **argv) 00090 { 00091 MYLOGVERB = LOG_INFO; 00092 00093 // instantiate a model manager: 00094 ModelManager manager("Parallel Vision TCP Version 2"); 00095 00096 // Instantiate our various ModelComponents: 00097 nub::soft_ref<FrameGrabberConfigurator> 00098 gbc(new FrameGrabberConfigurator(manager)); 00099 manager.addSubComponent(gbc); 00100 00101 nub::soft_ref<Beowulf> 00102 beo(new Beowulf(manager, "Beowulf Master", "BeowulfMaster", true)); 00103 manager.addSubComponent(beo); 00104 00105 // Parse command-line: 00106 if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1); 00107 00108 // do post-command-line configs: 00109 nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber(); 00110 if (gb.isInvalid()) 00111 LFATAL("You need to select a frame grabber type via the " 00112 "--fg-type=XX command-line option for this program " 00113 "to be useful"); 00114 int w = gb->getWidth(), h = gb->getHeight(); 00115 00116 // catch signals and redirect them to terminate for clean exit: 00117 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00118 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00119 signal(SIGALRM, terminate); 00120 00121 // get prepared to grab, communicate, display, etc: 00122 XWindow xw(Dims(w * 2, h), -1, -1, "USC Saliency Cam"); 00123 Image<PixRGB<byte> > disp(w * 2, h, ZEROS); 00124 int32 frame = 0; // count the frames 00125 PixRGB<byte> pix(255, 255, 0); // yellow color for fixations 00126 Point2D<int> win(w/2, h/2), winsm; // coordinates of attended location 00127 int foa_size = std::min(w, h) / 12; // radius of focus of attention 00128 TCPmessage rmsg; // buffer to receive messages from nodes 00129 TCPmessage smsg; // buffer to send messages to nodes 00130 Timer tim; // for computation of framerate 00131 int t[NSTAT][NAVG], ff; // to compute average framerate and other stats 00132 int latency = 0, nlat = 0; // to compute average processing latency 00133 int lastshift = 0; // frame of last shift 00134 int sml = 4; Image<byte> sm; 00135 00136 // let's get all our ModelComponent instances started: 00137 manager.start(); 00138 00139 // get the frame grabber to start streaming: 00140 gb->startStream(); 00141 00142 // ########## MAIN LOOP: grab, process, display: 00143 while(goforever) 00144 { 00145 // initialize the timer: 00146 tim.reset(); ff = frame % NAVG; 00147 00148 // grab an image: 00149 Image< PixRGB<byte> > ima = gb->readRGB(); 00150 t[0][ff] = tim.getReset(); // grab time 00151 00152 // send every other image to processing: 00153 if (frame & 1) 00154 { 00155 // prescale image: 00156 Image<PixRGB<byte> > ima2 = 00157 decY(lowPass9y(decX(lowPass9x(ima),1<<PRESCALE)),1<<PRESCALE); 00158 00159 // we do the job of BEO_RETINA on the master to reduce latency: 00160 // compute luminance and send it off: 00161 Image<byte> lum = luminance(ima2); 00162 smsg.reset(frame, BEO_LUMINANCE); 00163 smsg.addImage(lum); 00164 beo->send(0, smsg); // send off to luminance slave 00165 00166 // compute RG and BY and send them off: 00167 Image<byte> r, g, b, y; getRGBY(ima2, r, g, b, y, (byte)25); 00168 smsg.reset(frame, BEO_REDGREEN); 00169 smsg.addImage(r); smsg.addImage(g); 00170 beo->send(1, smsg); // send off to RG slave 00171 smsg.reset(frame, BEO_BLUEYELLOW); 00172 smsg.addImage(b); smsg.addImage(y); 00173 beo->send(2, smsg); // send off to BY slave 00174 00175 t[1][ff] = tim.getReset(); // send out time 00176 00177 //LINFO("sent frame %d", frame); 00178 } 00179 else 00180 { 00181 // sleep a bit so that we give more CPU to other threads/processes: 00182 struct timespec ts, ts2; 00183 ts.tv_sec = 0; ts.tv_nsec = 5000000; // sleep 5 ms 00184 nanosleep(&ts, &ts2); 00185 00186 // duplicate real send time from previous frame: 00187 int ff2 = ff - 1; if (ff2 < 0) ff2 += NAVG; 00188 t[1][ff] = t[1][ff2]; tim.reset(); 00189 } 00190 00191 // receive current coordinates of focus of attention: 00192 int32 rframe, raction, rnode = -1, recnb = 0; // receive from any node 00193 while(beo->receive(rnode, rmsg, rframe, raction, 5)) // wait up to 5ms 00194 { 00195 // accumulate data for average latency computation: 00196 latency += frame - rframe; nlat ++; 00197 //LINFO("received %d/%d from %d while at %d", 00198 // rframe, raction, rnode, frame); 00199 switch(raction) 00200 { 00201 case BEO_WINNER: // ############################## 00202 { 00203 Image<byte> smap = rmsg.getElementByteIma(); 00204 00205 // trigger IOR at currently-attended location: 00206 if (sm.initialized() && rframe - lastshift <= SHIFTINT) 00207 drawDisk(sm, winsm, 00208 int(ceil(float(foa_size) / (1<<sml))), 00209 byte(0)); 00210 00211 // inject newly received saliency map: 00212 if (sm.initialized()) 00213 sm = sm * (1.1f - SMINJECT) + smap * SMINJECT; 00214 else 00215 sm = smap; 00216 00217 if (rframe - lastshift >= SHIFTINT) 00218 { 00219 // find most salient location: 00220 byte maxval; findMax(sm, winsm, maxval); 00221 00222 // rescale winner coordinates according to PRESCALE: 00223 win.i = winsm.i << sml; 00224 win.i += int(((1<<(sml-1)) * float(rand()))/RAND_MAX); 00225 win.j = winsm.j << sml; 00226 win.j += int(((1<<(sml-1)) * float(rand()))/RAND_MAX); 00227 00228 // just did a shift of attention: 00229 lastshift = rframe; 00230 } 00231 } 00232 break; 00233 default: // ############################## 00234 LERROR("Bogus action %d -- IGNORING.", raction); 00235 break; 00236 } 00237 // limit number of receives, so we don't hold CPU too long: 00238 recnb ++; if (recnb > 3) break; 00239 } 00240 t[2][ff] = tim.getReset(); // receive time 00241 00242 // display image in window: 00243 inplacePaste(disp, ima, Point2D<int>(0, 0)); 00244 drawPatch(disp, win, 3, pix); 00245 drawCircle(disp, win, foa_size, pix, 2); 00246 if (sm.initialized()) 00247 inplacePaste(disp, 00248 toRGB(quickInterpolate(sm, 1<<sml)), Point2D<int>(w, 0)); 00249 xw.drawImage(disp); 00250 00251 t[3][ff] = tim.getReset(); // display time 00252 if (t[3][ff] > 20) 00253 LINFO("*** Display took %dms for frame %d", t[3][ff], frame); 00254 00255 00256 // compute and show framerate and stats over the last NAVG frames: 00257 if (ff == 1 && frame > 1) 00258 { 00259 float avg[NSTAT], tot = 0.0f; 00260 for (int j = 0; j < NSTAT; j ++) 00261 { 00262 avg[j] = 0.0f; 00263 for (int i = 0; i < NAVG; i ++) 00264 { avg[j] += t[j][i]; tot += t[j][i]; } 00265 avg[j] /= NAVG; 00266 } 00267 tot /= NAVG; 00268 if (nlat == 0) { latency = -1; nlat = 1; } 00269 LINFO("%.1ffps [G=%.1f S=%.1f R=%.1f D=%.1f T=%.1f F=%.1f]", 00270 1000.0f / tot, avg[0], avg[1], 00271 avg[2], avg[3], tot, float(latency) / nlat); 00272 latency = 0; nlat = 0; 00273 } 00274 00275 // ready for next frame: 00276 frame++; 00277 } 00278 00279 // got interrupted; let's cleanup and exit: 00280 00281 // stop all our ModelComponents 00282 manager.stop(); 00283 return 0; 00284 } 00285 00286 // ###################################################################### 00287 /* So things look consistent in everyone's emacs... */ 00288 /* Local Variables: */ 00289 /* indent-tabs-mode: nil */ 00290 /* End: */