SimulationViewerHand.C

Go to the documentation of this file.
00001 /*!@file Neuro/SimulationViewerHand.C comparison between saliency and
00002   human hand movement reactions */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00006 // by the University of Southern California (USC) and the iLab at USC.  //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Dicky Nauli Sihite <sihite@usc.edu>
00035 // $HeadURL:
00036 // $Id:
00037 //
00038 
00039 #include "Neuro/SimulationViewerHand.H"
00040 
00041 //#include "Channels/ChannelBase.H"
00042 //#include "Channels/ChannelOpts.H" // for LevelSpec option
00043 #include "Component/OptionManager.H"
00044 //#include "Component/ModelOptionDef.H"
00045 #include "Image/ColorOps.H"    // for contrastModulate(), toRGB()
00046 //#include "Image/CutPaste.H"    // for concatX()
00047 #include "Image/DrawOps.H"     // for colGreyCombo()
00048 #include "Image/FilterOps.H"   // for lowPass3()
00049 //#include "Image/MathOps.H"     // for scramble()
00050 #include "Image/Transforms.H"  // for segmentObjectClean(), contour2D()
00051 #include "Image/ShapeOps.H"    // for rescale()
00052 #include "Neuro/NeuroOpts.H"
00053 #include "Neuro/NeuroSimEvents.H"
00054 #include "Neuro/SpatialMetrics.H"
00055 #include "Psycho/HandData.H"
00056 #include "Simulation/SimEventQueue.H"
00057 //#include "Transport/FrameInfo.H"
00058 #include "Transport/FrameOstream.H"
00059 #include "Util/sformat.H"
00060 #include "rutz/trace.h"
00061 
00062 #include <fstream>
00063 #include <iostream>
00064 
00065 // for some reason this is not recognized when it appears in NeuroOpts.C
00066 /*const ModelOptionDef OPT_SMhistoryQlen =
00067   { MODOPT_ARG(uint), "SMhistoryQ", &MOC_DISPLAY, OPTEXP_CORE,
00068     "Keep a historical queue of salieny maps (one per new input frame), "
00069     "and report the history of saliency values over the entire queue "
00070     "and at a saccade target location, for each saccade",
00071     "sm-history-qlen", '\0', "<uint>", "0" };
00072 //*/
00073 
00074 // ######################################################################
00075 SimulationViewerHand::
00076 SimulationViewerHand(OptionManager& mgr, const std::string& descrName,
00077                        const std::string& tagName) :
00078   SimulationViewer(mgr, descrName, tagName),
00079   SIMCALLBACK_INIT(SimEventClockTick),
00080   SIMCALLBACK_INIT(SimEventSaveOutput),
00081   itsMetrics(new SpatialMetrics(mgr)),
00082   itsSaveTraj(&OPT_SVsaveTraj, this),
00083   itsSaveCombo(&OPT_SVHandSaveCombo, this),
00084   itsDisplayHand(&OPT_SVHandDisplay, this),
00085   itsPatchSize(&OPT_SVpatchSize, this),
00086   itsEraseMarker(&OPT_SVeraseMarker, this),
00087   itsMaxComboWidth(&OPT_SVHandMaxComboWidth, this),
00088   itsDrawings(), itsCurrTime(),  itsFrameNumber(-1), 
00089   itsHeaderCrafted(false), itsOutFields(), itsHandStyles(), 
00090   itsTargets()
00091 {
00092 GVX_TRACE(__PRETTY_FUNCTION__);
00093 
00094   this->addSubComponent(itsMetrics);
00095 
00096   // Select HandTrack for the HandControllerType
00097   getManager().setOptionValString(&OPT_HandControllerType, "HandTrack");
00098 }
00099 
00100 // ######################################################################
00101 SimulationViewerHand::~SimulationViewerHand()
00102 {
00103 GVX_TRACE(__PRETTY_FUNCTION__);
00104 }
00105 
00106 // ######################################################################
00107 void SimulationViewerHand::start1()
00108 {
00109 GVX_TRACE(__PRETTY_FUNCTION__);
00110 
00111   SimulationViewer::start1();
00112 }
00113 
00114 // ######################################################################
00115 void SimulationViewerHand::stop1()
00116 {
00117 GVX_TRACE(__PRETTY_FUNCTION__);
00118 }
00119 
00120 // ######################################################################
00121 void SimulationViewerHand::
00122 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& ect)
00123 {
00124   // get the current time (mostly for SVHandRegion)
00125   itsCurrTime = q.now();
00126   // any new input frame from the retina? If so, let's initialize or
00127   // clear all our drawings:
00128   if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this)) {
00129     itsDrawings.resize(e->frame().getDims(), true);
00130     itsFrameNumber++; // used for derived class SVHandRegion
00131     // this member is never used in SVHand
00132   }
00133   
00134   // Let's update our sliding caches with the current SM/AGM/etc:
00135   const Image<float> currsm = getMap(q, false);
00136 
00137   // all right, get the latest retina image (whether new or not) as we
00138   // will need it to do coordinate transforms, coordinate clippings, etc:
00139   SeC<SimEventRetinaImage> retev = q.check<SimEventRetinaImage>(this, SEQ_ANY);
00140   if (retev.is_valid() == false)
00141     LFATAL("I need some SimEventRetinaImage in the queue to function.");
00142  
00143   // any hand-tracker action?
00144   SeC<SimEventHandTrackerData> e = q.check<SimEventHandTrackerData>(this);
00145   
00146   while(e.is_valid()) {
00147     // parse that event:
00148     const rutz::shared_ptr<HandData> trackCurrPos = e->data();
00149     const uint tnum = e->trackerNum();
00150     const std::string tfn = e->trackerFilename();
00151     // add entry to style vector when we get a new trackernum
00152     if (itsHandStyles.size() <= tnum) {
00153       itsHandStyles.resize(tnum+1);
00154       
00155       itsHandStyles[tnum].pSize = itsPatchSize.getVal();
00156       itsHandStyles[tnum].col = e->trackerColor();
00157       
00158       // give distinct label, TODO: maybe write a switch for this
00159       //      itsHandStyles[tnum].label = convertToString(tnum);
00160       //huge hack right now, relies on directory tree data/<subject>/ pieces
00161       itsHandStyles[tnum].label = tfn.substr(tfn.find("data")+5,2);
00162     }
00163     
00164     // draw the conditions of current hand conditions:
00165     if (itsDisplayHand.getVal()) {
00166 
00167       // erase previous hand markers first
00168       if (itsEraseMarker.getVal()) itsDrawings.resize(retev->frame().getDims(), true);
00169       
00170       // draw marker at hand position
00171       drawHand(trackCurrPos, tnum);
00172     }
00173     
00174     // do we want to do any other sample processing? 
00175     // (for SVHandRegion or other derived classes)
00176     extraSampleProcessing(trackCurrPos);
00177     
00178     // any more events like that in the queue?
00179     e = q.check<SimEventHandTrackerData>(this);
00180   }
00181 }
00182 
00183 
00184 
00185 // ######################################################################
00186 void SimulationViewerHand::drawHand(const rutz::shared_ptr<HandData> rawPos, const uint tN)
00187 {
00188   /* The output that we expect on screen:
00189    * .--------------------.
00190    * | |                  |
00191    * | |                  |
00192    * | Y                  |
00193    * | | B B B B ...      |
00194    * |  ------X--------   |
00195    * '--------------------'
00196    * X & Y = x & y (left-right & accl-brake) direction respectively
00197    *         It will show a line for range of movement and a box
00198    *         indicating the current position
00199    * B's   = buttons, there will be circles with numbers on it indicating
00200    *         whether the button is pressed(green) or not(red)
00201    *         Hopefully the B's on screen is wrapped around incase too many
00202    *         buttons are avail
00203    */
00204 
00205   // Our screen dimensions
00206   const Dims dims = itsDrawings.getDims();
00207   
00208   // Default one grid cell based on the screen dimensions
00209   // Assuming we always have 4:3 tv ratio to get a square grid
00210   const Dims numgrid (80,60); // Under 640x480, its expected to have 8x8 per grid
00211   const Dims grid (dims.w()/numgrid.w(),dims.h()/numgrid.h()); 
00212 
00213   // Get raw X and Y position
00214   int rawX = rawPos->getX();
00215   int rawY = rawPos->getY();
00216 
00217   // Get the dims of X and Y position
00218   /*! Assuming grid [1,1]'s coord is (8,8) --> [ 0, 0] is (  0,  0)
00219    *                                       --> [80,60] is (640,480)
00220    *  We only want the X to be in between grid [2,59] to [79,59]
00221    *  and Y in [1,1] to [1,58]. We set those instead of [1,59] to prevent
00222    *  collision incase both meet eachother (rawX=0/255, rawY=0/255)
00223    *  |----------------|-------[]------|
00224    *  X1               XC      X_      X2
00225    */
00226   Point2D<int> X1 (getGridCoord(grid,             2, numgrid.h()-1));
00227   Point2D<int> X2 (getGridCoord(grid, numgrid.w()-1, numgrid.h()-1));
00228   Point2D<int> XC ((127*(X2.i-X1.i)/255)+X1.i,X1.j);
00229   Point2D<int> XD (0,grid.h()/2); // for difference
00230   Point2D<int> Y1 (getGridCoord(grid,             1,             1));
00231   Point2D<int> Y2 (getGridCoord(grid,             1, numgrid.h()-2));
00232   Point2D<int> YC (grid.w(),(127*(Y2.j-Y1.j)/255)+Y1.j);
00233   Point2D<int> YD (grid.w()/2,0); // for difference
00234   // The patch coords
00235   Point2D<int> X_ ((rawX*(X2.i-X1.i)/255)+X1.i, dims.h()-grid.h());
00236   Point2D<int> Y_ (grid.w(), (rawY*(Y2.j-Y1.j)/255)+Y1.j);
00237 
00238   // First draw the white line for the X-Y coords
00239   const PixRGB<byte> colWhite (255,255,255);
00240   // The X-line
00241   drawLine(itsDrawings, X1, X2, colWhite);
00242   drawLine(itsDrawings, X1-XD, X1+XD, colWhite);
00243   drawLine(itsDrawings, XC-XD, XC+XD, colWhite);
00244   drawLine(itsDrawings, X2-XD, X2+XD, colWhite);
00245   // The Y-line
00246   drawLine(itsDrawings, Y1, Y2, colWhite);
00247   drawLine(itsDrawings, Y1-YD, Y1+YD, colWhite);
00248   drawLine(itsDrawings, YC-YD, YC+YD, colWhite);
00249   drawLine(itsDrawings, Y2-YD, Y2+YD, colWhite);
00250 
00251 
00252   // Draw the box for the X-Y
00253   drawPatchBB(itsDrawings, X_, itsHandStyles[tN].pSize,   
00254               colWhite, PixRGB<byte>(1));
00255   drawPatchBB(itsDrawings, Y_, itsHandStyles[tN].pSize,   
00256               colWhite, PixRGB<byte>(1));
00257   
00258   PixRGB<byte> colB;
00259   // For the buttons
00260   if (rawPos->isButtonEmpty() == false) {  
00261     for (uint i = 0; i < rawPos->numButton(); i++) {
00262       // Blue if pressed, red if not
00263       if (rawPos->isPressed(i))
00264         colB = PixRGB<byte> (255, 0, 0); // Red
00265       else
00266         colB = PixRGB<byte> (0, 0, 0); // Transparent
00267 
00268       // For buttons position, we want them to be @ bottom of the screen
00269       // TODO: wrapped around in case the buttons grid over [80,_]
00270 
00271       // Write text of numbers into this thing
00272       writeText(itsDrawings, Point2D<int>(getGridCoord(grid, 3*i+10, numgrid.h()-5)),
00273                 sformat("%2d",i+1).c_str(), PixRGB<byte>(255), colB,SimpleFont::FIXED(10),false);
00274   
00275       // Draw circle
00276       //drawCircle(itsDrawings, Point2D<int>(getGridCoord(grid, 3*i+3, 1)),6,colB,1);
00277     }
00278   }
00279 }
00280 
00281 // ######################################################################
00282 void SimulationViewerHand::extraSampleProcessing(const rutz::shared_ptr<HandData>) {}
00283 // empty here, written so that HandRegion can do extra output on each hand position
00284 
00285 // ######################################################################
00286 Image< PixRGB<byte> > SimulationViewerHand::getTraj(SimEventQueue& q)
00287 {
00288 GVX_TRACE(__PRETTY_FUNCTION__);
00289 
00290   // get the latest retina image:
00291   Image< PixRGB<byte> > input;
00292   if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this, SEQ_ANY))
00293     input = e->frame().colorByte();
00294   else
00295     LFATAL("Could not find required SimEventRetinaImage");
00296 
00297   // make a composite of the input + the drawings:
00298   Image< PixRGB<byte> > comp = composite(itsDrawings, input);
00299 
00300   // return a plain traj?
00301   if (itsSaveTraj.getVal()) return comp;
00302 
00303   // otherwise, return mega combo; we have two formats: if we have a
00304   // max-cache, it will be a 4-image format, otherwise a 2-image
00305   // format:
00306   const Dims dims = itsDrawings.getDims();
00307   Image< PixRGB<byte> > ret;
00308 
00309   if (itsSaveCombo.getVal()) {
00310     ret = concatX(input, itsDrawings);
00311     drawLine(ret, Point2D<int>(dims.w()-1, 0), Point2D<int>(dims.w()-1, dims.h()-1),
00312              PixRGB<byte>(255, 255, 0), 1);
00313     drawLine(ret, Point2D<int>(dims.w(), 0), Point2D<int>(dims.w(), dims.h()-1),
00314              PixRGB<byte>(255, 255, 0), 1);
00315   }
00316 
00317   // make sure image is not unreasonably large:
00318   while (ret.getWidth() > itsMaxComboWidth.getVal())
00319     ret = decY(lowPass3y(decX(lowPass3x(ret))));
00320 
00321   return ret;
00322 }
00323 
00324 // ######################################################################
00325 void SimulationViewerHand::
00326 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00327 {
00328   this->save1(e->sinfo());
00329 }
00330 
00331 // ######################################################################
00332 void SimulationViewerHand::save1(const ModelComponentSaveInfo& sinfo)
00333 {
00334 GVX_TRACE(__PRETTY_FUNCTION__);
00335   SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q;
00336 
00337   // update the trajectory:
00338   Image< PixRGB<byte> > res = getTraj(*q);
00339 
00340   // save results?
00341   if (itsSaveCombo.getVal() || itsSaveTraj.getVal())
00342     {
00343       // get the OFS to save to, assuming sinfo is of type
00344       // SimModuleSaveInfo (will throw a fatal exception otherwise):
00345       nub::ref<FrameOstream> ofs =
00346         dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs;
00347 
00348       ofs->writeRGB(res, "T",
00349                     FrameInfo("SimulationViewerHand trajectory", SRC_POS));
00350 
00351     }
00352 }
00353 
00354 // ######################################################################
00355 /* So things look consistent in everyone's emacs... */
00356 /* Local Variables: */
00357 /* indent-tabs-mode: nil */
00358 /* End: */
Generated on Sun May 8 08:05:26 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3