app-cam-saccades.C

Go to the documentation of this file.
00001 /*!@file AppDevices/app-cam-saccades.C Use a pan-tilt camera for executing saccades */
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: Dirk Walther <walther@caltech.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppDevices/app-cam-saccades.C $
00035 // $Id: app-cam-saccades.C 10982 2009-03-05 05:11:22Z itti $
00036 //
00037 
00038 #include "Channels/ChannelBase.H"
00039 #include "Channels/ChannelOpts.H"
00040 #include "Component/GlobalOpts.H"
00041 #include "Component/ModelManager.H"
00042 #include "Devices/DeviceOpts.H"
00043 #include "Devices/FrameGrabberConfigurator.H"
00044 #include "Devices/VCC4.H"
00045 #include "GUI/XWinManaged.H"
00046 #include "Image/DrawOps.H"
00047 #include "Image/Image.H"
00048 #include "Image/ShapeOps.H"
00049 #include "Image/fancynorm.H"
00050 #include "Media/MediaSimEvents.H"
00051 #include "Neuro/NeuroOpts.H"
00052 #include "Neuro/NeuroSimEvents.H"
00053 #include "Neuro/SaccadeControllers.H"
00054 #include "Neuro/ShapeEstimator.H"
00055 #include "Neuro/SimulationViewerStd.H"
00056 #include "Neuro/SpatialMetrics.H"
00057 #include "Neuro/StdBrain.H"
00058 #include "Neuro/VisualCortex.H"
00059 #include "Simulation/SimEventQueueConfigurator.H"
00060 #include "Transport/FrameIstream.H"
00061 #include "Util/log.H"
00062 
00063 #include <algorithm> // for std::max() and std::min()
00064 #include <cmath>
00065 #include <iostream>
00066 #include <stdio.h>
00067 
00068 //#define CAM_DISPLAY NULL
00069 #define CAM_WINDOW_NAME "Saliency Calculated"
00070 #define CAM_PREV_NAME "Captured Image"
00071 #define ANG_FACTOR (180.0/Pi)
00072 #define MAXPAN ((float)100.0)
00073 #define MINPAN ((float)-100.0)
00074 #define MAXTILT ((float)30.0)
00075 #define MINTILT ((float)-30.0)
00076 
00077 // make random saccade if the salmap evolves for more than TOO_MUCH_TIME s
00078 #define TOO_MUCH_TIME SimTime::SECS(0.7)
00079 
00080 
00081 float sqr (float x);
00082 float randang();
00083 
00084 // give back a random angle increment/decrement
00085 inline float randang ()
00086 {
00087   const float max_randang = 30.0;
00088   return ((float)(2.0 * rand() / RAND_MAX) - 1.0) * max_randang;
00089 }
00090 
00091 // sqr(x) = x*x;
00092 inline float sqr (float x)
00093 {
00094   return (x * x);
00095 }
00096 
00097 // ######################################################################
00098 // ##### Main Program:
00099 // ######################################################################
00100 /*! This program takes input from a camera, calculates
00101   the most salient spot(s) and moves the camera there
00102   according to the following rules:<p>
00103   1) take image from camera
00104   2) calculate next most salient spot
00105   3) If (spot is already in list) goto 2
00106   4) store spot in list
00107   5) move to the spot
00108   6) goto 1<p>
00109   The list is finite (small) sized and "forgets" the oldest entries.
00110   When the search for the next most salient spot in a given image
00111   takes too much time, the camera is moved by a random amount.*/
00112 int main(const int argc, const char **argv)
00113 {
00114   LOG_FLAGS &= (~LOG_FULLTRACE);
00115 
00116   // instantiate a model manager:
00117   ModelManager manager("Saccade Tester");
00118 
00119   // Instantiate our various ModelComponents:
00120   nub::soft_ref<SimEventQueueConfigurator>
00121     seqc(new SimEventQueueConfigurator(manager));
00122   manager.addSubComponent(seqc);
00123 
00124   nub::soft_ref<FrameGrabberConfigurator>
00125     gbc(new FrameGrabberConfigurator(manager));
00126   manager.addSubComponent(gbc);
00127 
00128   nub::soft_ref<VCC4> pantilt(new VCC4(manager));
00129   manager.addSubComponent(pantilt);
00130 
00131   nub::soft_ref<StdBrain> brain(new StdBrain(manager));
00132   manager.addSubComponent(brain);
00133 
00134   nub::ref<SpatialMetrics> metrics(new SpatialMetrics(manager));
00135   manager.addSubComponent(metrics);
00136 
00137   // choose a V4Lgrabber by default, and a few custom grabbing
00138   // defaults, for backward compatibility with an older version of
00139   // this program:
00140   manager.setOptionValString(&OPT_FrameGrabberType, "V4L");
00141   manager.setOptionValString(&OPT_FrameGrabberDims, "320x240");
00142   manager.setOptionValString(&OPT_FrameGrabberChannel, "1");
00143 
00144   // set some more parameters as defaults
00145   manager.setOptionValString(&OPT_OriInteraction,"SubtractMean");
00146   manager.setOptionValString(&OPT_OrientComputeType,"Steerable");
00147   manager.setOptionValString(&OPT_RawVisualCortexChans,"OIC");
00148   manager.setOptionValString(&OPT_UseRandom,"false");
00149   manager.setOptionValString(&OPT_ShapeEstimatorMode,"FeatureMap");
00150   manager.setOptionValString(&OPT_ShapeEstimatorSmoothMethod,"Chamfer");
00151   manager.setOptionValString(&OPT_IORtype,"ShapeEst");
00152   manager.setOptionValString(&OPT_SVdisplayFOA,"true");
00153   manager.setOptionValString(&OPT_SVdisplayPatch,"false");
00154   manager.setOptionValString(&OPT_SVdisplayFOALinks,"false");
00155   manager.setOptionValString(&OPT_SVdisplayAdditive,"false");
00156   manager.setOptionValString(&OPT_SVdisplayTime,"false");
00157   manager.setOptionValString(&OPT_SVdisplayBoring,"false");
00158   metrics->setFOAradius(20);
00159 
00160   // Parse command-line:
00161   if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1);
00162 
00163   // do post-command-line configs:
00164   nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00165   if (gb.isInvalid())
00166     LFATAL("You need to select a frame grabber type via the "
00167            "--fg-type=XX command-line option for this program "
00168            "to be useful");
00169   const Dims dims = gb->peekDims();
00170   nub::soft_ref<SimEventQueue> seq = seqc->getQ();
00171 
00172   // let's get all our ModelComponent instances started:
00173   manager.start();
00174 
00175   float hdeg = 80, wdeg = 100;;
00176   float min_dist = std::min(hdeg, wdeg) / 12;
00177   const int num_mem = 10;
00178   float mem_pan[num_mem], mem_tilt[num_mem];
00179   int mem_ptr = 0;
00180   bool mem_filled = false;
00181   bool is_in_mem;
00182   int mem_top;
00183 
00184   pantilt->CameraInitialize(true);
00185   pantilt->PlainCommand(VCC4_SetZoomingWIDE);
00186 
00187   XWinManaged salWin(dims*2, -1, -1, CAM_WINDOW_NAME);
00188   XWinManaged capWin(dims*2, -1, -1, CAM_PREV_NAME);
00189 
00190   //StdBrain brain(4,2,4,3,4,4,SMDfoa,VCXNORM_FANCY);
00191   Image<PixRGB <byte> > capImg, salImg, capImg2;
00192 
00193   float campos_pan = 0.0, campos_tilt = 0.0;
00194   float oldpos_pan = 0.0, oldpos_tilt = 0.0;
00195   float newpos_pan, newpos_tilt;
00196 
00197   // main loop
00198   while (!salWin.pressedCloseButton() && !capWin.pressedCloseButton())
00199     {
00200       // wait until camera stops moving
00201       //while (pantilt->IsMoving()) usleep (10000);
00202       //usleep (100000);
00203 
00204       brain->reset(MC_RECURSE);
00205 
00206       // capture image and show in preview window
00207       for (int i = 0; i < 20; i++) capImg = gb->readRGB();
00208       capImg2 = capImg;
00209       drawDisk(capImg2, Point2D<int>(dims/2),
00210                3, PixRGB<byte>(255,0,0));
00211       capWin.drawImage(rescale(capImg2,dims*2));
00212       rutz::shared_ptr<SimEventInputFrame>
00213         e(new SimEventInputFrame(brain.get(), GenericFrame(capImg), 0));
00214       seq->post(e); // post the image to the brain
00215 
00216       // evolve
00217       seq->resetTime();
00218       while(true)
00219         {
00220           Point2D<int> winner(-1, -1);
00221           while(seq->now() < TOO_MUCH_TIME)
00222             {
00223               if (SeC<SimEventWTAwinner> e =
00224                   seq->check<SimEventWTAwinner>(0))
00225                 {
00226                   winner = e->winner().p;
00227                   break;
00228                 }
00229               if (seq->evolve() == SIM_BREAK) LFATAL("BREAK");
00230             }
00231 
00232           // too much time -> random saccade
00233           if (seq->now() >= TOO_MUCH_TIME || winner.isValid() == false)
00234             {
00235               newpos_pan = oldpos_pan + randang();
00236               newpos_pan = std::max(newpos_pan, MINPAN);
00237               newpos_pan = std::min(newpos_pan, MAXPAN);
00238 
00239               newpos_tilt = oldpos_tilt + randang();
00240               newpos_tilt = std::max(newpos_tilt, MINTILT);
00241               newpos_tilt = std::min(newpos_tilt, MAXTILT);
00242 
00243               LINFO("Using random position.");
00244               break;
00245             }
00246 
00247           // calculate new camera position and make sure they are in
00248           // the right range
00249           newpos_pan = oldpos_pan + (((float)winner.i -
00250                                       0.5 * (float)dims.w()) /
00251                                      (float)dims.w() * 0.5 * wdeg);
00252           //newpos_pan = oldpos_pan + ANG_FACTOR * tan(X_FACTOR *
00253           //((float)winner.i - 0.5*dims.w()));
00254           newpos_pan = std::max(newpos_pan, MINPAN);
00255           newpos_pan = std::min(newpos_pan, MAXPAN);
00256 
00257           newpos_tilt = oldpos_tilt + ((0.5 * (float)dims.h() -
00258                                         (float)winner.j) /
00259                                        (float)dims.h() * 0.5 * hdeg);
00260           //newpos_tile = oldpos_tilt + ANG_FACTOR * tan(Y_FACTOR *
00261           //((float)winner.j - 0.5*dims.h()));
00262           newpos_tilt = std::max(newpos_tilt, MINTILT);
00263           newpos_tilt = std::min(newpos_tilt, MAXTILT);
00264 
00265           is_in_mem = false;
00266           mem_top = mem_filled ? num_mem : mem_ptr;
00267           for (int i = 0; i < mem_top; i++)
00268             is_in_mem |= (sqr(newpos_pan - mem_pan[i]) +
00269                           sqr(newpos_tilt - mem_tilt[i]) < sqr(min_dist));
00270 
00271           if (!is_in_mem) break;
00272 
00273           LDEBUG("Using next cycle.");
00274           LDEBUG("newpos = %f, %f", newpos_pan, newpos_tilt);
00275 #ifdef DEBUG
00276           std::cout << "Mark 15 \n";
00277           for (int i = 0; i < mem_top; i++)
00278             LDEBUG("mempos[%i] = %f, %f",i, mem_pan[i], mem_tilt[i]);
00279 #endif
00280         }
00281 
00282       campos_pan  = newpos_pan;
00283       campos_tilt = newpos_tilt;
00284 
00285       mem_pan  [mem_ptr] = newpos_pan;
00286       mem_tilt [mem_ptr] = newpos_tilt;
00287       mem_ptr++;
00288 
00289       if (mem_ptr >= num_mem)
00290         {
00291           mem_ptr = 0;
00292           mem_filled = true;
00293         }
00294 
00295       LDEBUG("mem_ptr = %i",mem_ptr);
00296       LDEBUG("newpos = %i, %i",int(newpos_pan),int(newpos_tilt));
00297 
00298       oldpos_pan  = newpos_pan;
00299       oldpos_tilt = newpos_tilt;
00300       pantilt->gotoPosition (campos_pan, campos_tilt);
00301 
00302       // set the window's title bar to the ShapeEstimatorLabel
00303       //salWin.setTitle(brain->getSE()->getWinningLabel().c_str());
00304 
00305       // retrieve the image with marked salient spot and display it
00306       ////////////salImg = brain->getSV()->getTraj(seq->now());
00307       salWin.drawImage(rescale(salImg,dims*2));
00308 
00309       // end of the main loop
00310     }
00311   pantilt->PlainCommand(VCC4_GoHome);
00312   manager.stop();
00313   return 0;
00314 }
00315 
00316 
00317 
00318 // ######################################################################
00319 /* So things look consistent in everyone's emacs... */
00320 /* Local Variables: */
00321 /* indent-tabs-mode: nil */
00322 /* End: */
Generated on Sun May 8 08:04:10 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3