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