00001 /*!@file Parallel/pvisionTCP-master.C Grab video & process over beowulf w/ pvisionTCP */ 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-master.C $ 00035 // $Id: pvisionTCP-master.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 /* This parallel vision processing master is for use with pvisionTCP. 00039 See the pvisionTCPgo 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/DrawOps.H" 00048 #include "Image/Image.H" 00049 #include "Image/Pixels.H" 00050 #include "Image/ShapeOps.H" 00051 #include "Parallel/pvisionTCP-defs.H" 00052 #include "Transport/FrameIstream.H" 00053 #include "Util/Assert.H" 00054 00055 #include <signal.h> 00056 00057 00058 //! Number of frames over which average framerate is computed 00059 #define NAVG 20 00060 //! Number of stats collected 00061 #define NSTAT 6 00062 00063 //! prescale level by which we downsize images before sending them off 00064 #define PRESCALE 2 00065 00066 static bool goforever = true; //!< Will turn false on interrupt signal 00067 00068 //! Signal handler (e.g., for control-C) 00069 void terminate(int s) 00070 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); } 00071 00072 // ###################################################################### 00073 int main(const int argc, const char **argv) 00074 { 00075 MYLOGVERB = LOG_INFO; 00076 00077 // instantiate a model manager: 00078 ModelManager manager("Parallel Vision TCP Version 2"); 00079 00080 // Instantiate our various ModelComponents: 00081 nub::soft_ref<FrameGrabberConfigurator> 00082 gbc(new FrameGrabberConfigurator(manager)); 00083 manager.addSubComponent(gbc); 00084 00085 nub::soft_ref<Beowulf> 00086 beo(new Beowulf(manager, "Beowulf Master", "BeowulfMaster", true)); 00087 manager.addSubComponent(beo); 00088 00089 // Parse command-line: 00090 if (manager.parseCommandLine(argc, argv, "<nframes> <framepause>", 2, 2) 00091 == false) return(1); 00092 00093 // do post-command-line configs: 00094 nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber(); 00095 if (gb.isInvalid()) 00096 LFATAL("You need to select a frame grabber type via the " 00097 "--fg-type=XX command-line option for this program " 00098 "to be useful"); 00099 int w = gb->getWidth(), h = gb->getHeight(); 00100 00101 int nframes = manager.getExtraArgAs<int>(0); 00102 if (nframes < 1 || nframes > 2048) LFATAL("Invalid number of frames"); 00103 uint64 framepause = manager.getExtraArgAs<uint64>(1); 00104 if (framepause < 1 || framepause > 2048) LFATAL("Invalid framepause"); 00105 00106 // catch signals and redirect them to terminate for clean exit: 00107 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00108 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00109 signal(SIGALRM, terminate); 00110 00111 // get prepared to grab, communicate, display, etc: 00112 XWindow xw(gb->peekDims(), -1, -1, "USC Saliency Cam"); 00113 int32 frame = 0; // count the frames 00114 PixRGB<byte> pix(255, 255, 0); // yellow color for fixations 00115 Point2D<int> win(w/2, h/2); // coordinates of attended location 00116 int foa_size = std::min(w, h) / 12; // radius of focus of attention 00117 TCPmessage rmsg; // buffer to receive messages from nodes 00118 TCPmessage smsg; // buffer to send messages to nodes 00119 Timer tim; // for computation of framerate 00120 int t[NSTAT][NAVG], ff; // to compute average framerate and other stats 00121 int latency = 0, nlat = 0; // to compute average processing latency 00122 int dropped = 0; // number of frames dropped lately 00123 00124 // setup array of frames: 00125 Image< PixRGB<byte> > ima[nframes]; 00126 00127 // let's get all our ModelComponent instances started: 00128 manager.start(); 00129 00130 // get the frame grabber to start streaming: 00131 gb->startStream(); 00132 00133 // ########## MAIN LOOP: grab, process, display: 00134 while(goforever) 00135 { 00136 // initialize the timer: 00137 tim.reset(); ff = frame % NAVG; 00138 00139 // grab an image: 00140 int32 index = frame % nframes; 00141 ima[index] = gb->readRGB(); 00142 t[0][ff] = tim.get(); // grab time 00143 00144 // display current processed frame, i.e., grabbed frame-nframes+1 ago: 00145 if (frame >= nframes) 00146 xw.drawImage(ima[(frame - nframes + 1) % nframes]); 00147 t[1][ff] = tim.get() - t[0][ff]; // display time 00148 if (t[1][ff] > 20) 00149 LINFO("*** Display took %dms for frame %d", t[1][ff], frame); 00150 00151 // send every image to processing, unless we are recovering from drops: 00152 if (dropped == 0) 00153 { 00154 // prescale image: 00155 Image< PixRGB<byte> > tmpi = ima[index]; 00156 tmpi = rescale(tmpi, 00157 tmpi.getWidth() >> PRESCALE, 00158 tmpi.getHeight() >> PRESCALE); 00159 00160 // select processing branch based on frame number: 00161 int32 offset; if (frame & 1) offset = POFFSET; else offset = 0; 00162 00163 // we do the job of BEO_RETINA on the master to reduce latency: 00164 // compute luminance and send it off: 00165 Image<byte> lum = luminance(tmpi); 00166 smsg.reset(frame, 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(tmpi, r, g, b, y, (byte)25); 00172 smsg.reset(frame, BEO_REDGREEN); 00173 smsg.addImage(r); smsg.addImage(g); 00174 beo->send(offset + 1, smsg); // send off to RG slave 00175 smsg.reset(frame, BEO_BLUEYELLOW); 00176 smsg.addImage(b); smsg.addImage(y); 00177 beo->send(offset + 2, smsg); // send off to BY slave 00178 00179 //LINFO("sent frame %d", frame); 00180 } 00181 t[2][ff] = tim.get() - t[1][ff] - t[0][ff]; // send out time 00182 00183 // receive current coordinates of focus of attention: 00184 int32 rframe, raction, rnode = -1, recnb = 0; // receive from any node 00185 while(beo->receive(rnode, rmsg, rframe, raction, 5)) // wait up to 5ms 00186 { 00187 // accumulate data for average latency computation: 00188 latency += frame - rframe; nlat ++; 00189 //LINFO("received %d/%d from %d while at %d", 00190 // rframe, raction, rnode, frame); 00191 switch(raction) 00192 { 00193 case BEO_WINNER: // ############################## 00194 { 00195 const Fixation fix = rmsg.getElementFixation(); 00196 win.i = fix.i; win.j = fix.j; rframe = fix.frame; 00197 00198 // are we going to keep or drop this result? 00199 if (rframe > frame - nframes) 00200 { 00201 00202 // rescale winner coordinates according to PRESCALE: 00203 win.i <<= PRESCALE; 00204 win.i += int(((1 << (PRESCALE - 1)) * 00205 float(rand()) ) / RAND_MAX); 00206 win.j <<= PRESCALE; 00207 win.j += int(((1 << (PRESCALE - 1)) * 00208 float(rand()) ) / RAND_MAX); 00209 00210 // plot focus of attention onto image, at winning coords: 00211 int32 fidx = rframe % nframes; 00212 drawPatch(ima[fidx], win, 3, pix); 00213 drawCircle(ima[fidx], win, foa_size, pix, 3); 00214 00215 if (dropped) dropped --; 00216 } 00217 else 00218 { 00219 dropped += 3; 00220 LINFO(" dropping frame %d (%d) [now %d]; dropped = %d", 00221 rframe, rframe % nframes, frame, dropped); 00222 } 00223 } 00224 break; 00225 default: // ############################## 00226 LERROR("Bogus action %d -- IGNORING.", raction); 00227 break; 00228 } 00229 // limit number of receives, so we don't hold CPU too long: 00230 recnb ++; if (recnb > 4) break; 00231 } 00232 t[3][ff] = tim.get() - t[2][ff] - t[1][ff] - t[0][ff]; // receive time 00233 00234 // compute and show framerate and stats over the last NAVG frames: 00235 if (ff == 1 && frame > 1) 00236 { 00237 int avg[NSTAT]; 00238 for (int j = 0; j < NSTAT; j ++) 00239 { 00240 avg[j] = 0; 00241 for (int i = 0; i < NAVG; i ++) avg[j] += t[j][i]; 00242 avg[j] /= NAVG; 00243 } 00244 if (nlat == 0) { latency = -1; nlat = 1; } 00245 LINFO("%.1ffps/%llxms [G=%d D=%d S=%d R=%d A=%d T=%d F=%d]", 00246 1000.0 / ((float)(avg[5])), framepause, 00247 avg[0], avg[1], avg[2], avg[3], avg[4], avg[5], 00248 latency / nlat); 00249 latency = 0; nlat = 0; 00250 // try to resorb the number of dropped frames: 00251 if (dropped) dropped --; 00252 } 00253 t[4][ff] = tim.get(); // after total before pause 00254 00255 // if necessary, sleep for a while until fixed amount of time elapsed: 00256 while(tim.get() < framepause) 00257 { 00258 struct timespec ts, ts2; 00259 ts.tv_sec = 0; ts.tv_nsec = 1000000; // sleep 1 ms 00260 nanosleep(&ts, &ts2); 00261 } 00262 00263 t[5][ff] = tim.get(); // total time 00264 00265 // ready for next frame: 00266 frame++; 00267 } 00268 00269 // got interrupted; let's cleanup and exit: 00270 // stop all our ModelComponents 00271 manager.stop(); 00272 exit(0); 00273 } 00274 00275 // ###################################################################### 00276 /* So things look consistent in everyone's emacs... */ 00277 /* Local Variables: */ 00278 /* indent-tabs-mode: nil */ 00279 /* End: */