SimulationViewerEyeRegion.C

Go to the documentation of this file.
00001 /*!@file Neuro/SimulationViewerEyeRegion.C comparison between region data from an ObjRec data (from an XML file) and human eye movements */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the 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/Neuro/SimulationViewerEyeRegion.C $
00035 // $Id: SimulationViewerEyeRegion.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 #include "Neuro/SimulationViewerEyeRegion.H"
00039 
00040 #include "Component/OptionManager.H"
00041 #include "Component/ModelOptionDef.H"
00042 #include "Transport/TransportOpts.H"
00043 #include "Channels/ChannelBase.H"
00044 #include "Image/DrawOps.H"
00045 #include "Image/ColorOps.H"    // for toRGB()
00046 #include "Image/CutPaste.H"    // for concatX()
00047 #include "Image/FilterOps.H"   // for lowPass3()
00048 #include "Image/MathOps.H"     // for alphaBlend()
00049 #include "Image/ShapeOps.H"    // for rescale()
00050 #include "Image/Transforms.H"  // for composite()
00051 #include "Neuro/NeuroOpts.H"
00052 #include "Neuro/NeuroSimEvents.H"
00053 #include "Psycho/EyeData.H"
00054 #include "Simulation/SimEventQueue.H"
00055 #include "Util/sformat.H"
00056 
00057 #include "rutz/trace.h"
00058 
00059 #include <fstream>
00060 //#include <iostream>
00061 
00062 const ModelOptionDef OPT_SimViewXMLInputFile =
00063   { MODOPT_ARG(std::string), "SimViewXMLInputFile", &MOC_INPUT, OPTEXP_CORE,
00064     "XML file to gather region data from.",
00065     "xml-file", '\0', "string", ""};
00066 
00067 const ModelOptionDef OPT_SimViewSelectedObjects =
00068   { MODOPT_ARG(std::string), "SimViewSelectedObjects", &MOC_DISPLAY, OPTEXP_CORE,
00069     "Only display objects matching the given name.",
00070     "objs-filter", '\0', "string", "" };
00071 
00072 const ModelOptionDef OPT_SimViewObjDrawMode =
00073   { MODOPT_ARG(std::string), "SimViewObjDrawMode", &MOC_DISPLAY, OPTEXP_CORE,
00074     "Chooses which objects are displayed.  Note that these options currently "
00075     "depend upon --display-patch and --display-foa.  \n"
00076     "\t'selected' objects are objects which are selected by the option --objs-filter.\n"
00077     "\t'targeted' objects are objects that saccades are directed towards.\n"
00078     "\t'traced' objects are objects that are followed by an eyetrace.\n"
00079     "\t'none' and 'all' are none and all labeled objects, respectively.",
00080     "obj-drawmode", '\0', "<none|selected|targeted|traced|all>", "all" };
00081 
00082 const ModelOptionDef OPT_SimViewHighlightMode =
00083   { MODOPT_ARG(std::string), "SimViewHighlightMode", &MOC_DISPLAY, OPTEXP_CORE,
00084     "Chooses when objects are highlighted.  Note that these options currently "
00085     "depend upon --display-patch and --display-foa.  Also, highlighting is currently "
00086     "ambiguous with multiple eye-traces. \n"
00087     "\t'targeted' triggers highlighting only at the FOA.\n"
00088     "\t'traced' highlights the object that is at the point of gaze.",
00089     "obj-highlightmode", '\0', "<off|targeted|traced>", "targeted" };
00090 
00091 // needs updating
00092 const ModelOptionDef OPT_SimViewPrependHeader =
00093   { MODOPT_FLAG, "SimViewPrependHeader", &MOC_DISPLAY, OPTEXP_CORE,
00094     "Determines whether to add a header to svem or region output",
00095     "prepend-header", '\0', "", "false" };
00096 
00097 // Used by: SimulationViewerEyeRegion
00098 const ModelOptionDef OPT_SimViewRegionOutFile =
00099   { MODOPT_ARG_STRING, "SimViewRegionOutFile", &MOC_DISPLAY, OPTEXP_CORE,
00100     "File name for region-based output data (or empty to not save output data).",
00101     "region-out-fname", '\0', "<file>", "" };
00102 
00103 // ######################################################################
00104 SimulationViewerEyeRegion::
00105 SimulationViewerEyeRegion(OptionManager& mgr, const std::string& descrName,
00106                        const std::string& tagName) :
00107   SimulationViewerEyeMvt(mgr, descrName, tagName),
00108   itsRegionOutFname(&OPT_SimViewRegionOutFile, this),
00109   itsXMLFname(&OPT_SimViewXMLInputFile, this),
00110   itsSelectedObjects(&OPT_SimViewSelectedObjects, this),
00111   itsObjectDrawMode(&OPT_SimViewObjDrawMode, this),
00112   itsHighlightMode(&OPT_SimViewHighlightMode, this),
00113   itsPrependHeader(&OPT_SimViewPrependHeader,this),
00114   itsLineThickness("SVLineThickness", this, 2),
00115   itsHitTransparency("SVHitTransparency", this, 0.65),
00116   itsRandomColoring("SVRandomColoring", this, true),
00117   itsRegionOutFile(0), itsRegions(), itsTargetsMask(), itsNumObjects(0),
00118   itsCurrRegionID(NULL_OBJ), 
00119   itsObjectEntry(new EyeData(1,1,1,SACSTATE_FIX,false)), 
00120   itsObjectOnset(SimTime::ZERO()), itsObjectFrameOnset(0), itsRandColors(), 
00121   itsObjectsNames(), itsRegHeaderWritten(false)
00122 {
00123 GVX_TRACE(__PRETTY_FUNCTION__);
00124 }
00125 
00126 // ######################################################################
00127 SimulationViewerEyeRegion::~SimulationViewerEyeRegion()
00128 {
00129 GVX_TRACE(__PRETTY_FUNCTION__);
00130 }
00131 
00132 // ######################################################################
00133 void SimulationViewerEyeRegion::start1()
00134 {
00135   if (itsXMLFname.getVal().empty())
00136     LFATAL("No XML file given - use --xml-file option with sv-Type EyeRegion");
00137   else
00138     {
00139     // load up the objects from the XML file
00140     itsObjectsInfo.reset(new TestImages(itsXMLFname.getVal().c_str(),
00141                                         TestImages::XMLFILE));
00142 
00143     // "count" the number of distinct objects by ID and get their names
00144     // this works b/c currently our script indexes objects sequentially 
00145     // from 0 ... n
00146     Scene thisScene;
00147     std::string nom;
00148     for (uint i = 0; i < itsObjectsInfo->getNumScenes(); i++)
00149       {
00150         thisScene = itsObjectsInfo->getSceneData(i);
00151         for (std::vector<Object>::iterator iObj = thisScene.objects.begin();
00152              iObj != thisScene.objects.end(); iObj++)
00153           {
00154             //if the array is too small, resize the array
00155             if((*iObj).id >= itsNumObjects) 
00156               {
00157                 itsNumObjects = (*iObj).id+1;
00158                 itsObjectsNames.resize(itsNumObjects,std::string());
00159               }
00160 
00161             // get rid of leading and trailing underscores
00162             nom = (*iObj).name;
00163             if(!nom.empty() && (nom[nom.length()-1] == '_')) 
00164               nom.erase(nom.length()-1);
00165             if(!nom.empty() && (nom[0] == '_')) nom.erase(0,1);
00166 
00167             //if this is a new name, use the id to write the name
00168             if(itsObjectsNames[(*iObj).id].empty()==true) 
00169               {
00170                 itsObjectsNames[(*iObj).id] = nom;
00171                 LINFO("assigning obj %s to obj id #%d from frame %u",
00172                       nom.c_str(),(*iObj).id,i);
00173               }
00174 
00175             // if this id is already used for a different object, throw an error
00176             if (itsObjectsNames[(*iObj).id].compare(nom) != 0)
00177               LFATAL("XML file %s has name conflict for object #%u, %s <-> %s",
00178                      itsXMLFname.getVal().c_str(), (*iObj).id, 
00179                      itsObjectsNames[(*iObj).id].c_str(), nom.c_str());
00180           }
00181      
00182        }
00183     }
00184 
00185   // open output file:
00186   if (!itsRegionOutFname.getVal().empty())
00187     {
00188       if (itsRegionOutFile) delete itsRegionOutFile;
00189       itsRegionOutFile = new std::ofstream(itsRegionOutFname.getVal().c_str());
00190       if (itsRegionOutFile->is_open() == false)
00191         LFATAL("Cannot open '%s' for writing", itsRegionOutFname.getVal().c_str());
00192     }
00193 
00194   // ensure that if this output file is open then --display-patch is also on.
00195   if (!(itsRegionOutFname.getVal().empty()) && itsDisplayPatch.getVal() == false)
00196         LFATAL("Cannot write %s unless --display-patch is set.",
00197                itsRegionOutFname.getVal().c_str());
00198 
00199   // initialize random colors
00200 
00201   if(itsRandomColoring.getVal())
00202     for (uint i = 0; i < itsNumObjects; i++)
00203       itsRandColors.push_back(PixRGB<byte>(randomUpToIncluding(255),
00204                                            randomUpToIncluding(255),
00205                                            randomUpToIncluding(255)));
00206 
00207   SimulationViewerEyeMvt::start1(); 
00208 }
00209 
00210 // ######################################################################
00211 void SimulationViewerEyeRegion::stop1()
00212 {
00213 GVX_TRACE(__PRETTY_FUNCTION__);
00214  if (itsRegionOutFile) {
00215    writeROIOutput(rawToRet(itsObjectEntry->position()));
00216    delete itsRegionOutFile; 
00217    itsRegionOutFile = 0;
00218 }
00219 
00220  SimulationViewerEyeMvt::stop1();
00221 }
00222 
00223 // ######################################################################
00224 uint SimulationViewerEyeRegion::findHitRegion(const Point2D<int> pt, uint fNum)
00225 {
00226   // TODO: how can we guarantee that the frame matches the annotation?
00227   // Reasonable assumption 1: the annotation corresponds to the video
00228   // Danger 1: different input frame sequence (e.g. frame rate)
00229   // Danger 2: holdup of frames from Retina
00230 
00231   if(itsObjectsInfo.get() == 0)
00232     LFATAL("No objects data - check xml file.");
00233 
00234   if(itsFrameNumber >= itsObjectsInfo->getNumScenes())
00235     {
00236       LINFO("Ran out of XML scene data...");
00237       return NULL_OBJ;
00238     }
00239 
00240   //should check pt must also be looking at current frame w.r.t cropping, etc.
00241 
00242   Scene sceneData =
00243     itsObjectsInfo->getSceneData(fNum);
00244 
00245   // find which object this saccade target hits
00246   uint pID = NULL_OBJ;
00247   double thisrank, maxrank=-1;
00248 
00249   for(std::vector<Object>::iterator itrObject =
00250         sceneData.objects.begin(); itrObject != sceneData.objects.end(); itrObject++)
00251     if(pnpoly((*itrObject).polygon,pt)) // is our object hit by the pt?
00252       {
00253         thisrank = rankForeground(*itrObject);
00254         if(thisrank > maxrank) // is our object in front?
00255           {
00256             pID = (*itrObject).id;
00257             maxrank = thisrank;
00258           }
00259       }
00260   return pID;
00261 }
00262 
00263 
00264 // ######################################################################
00265 double SimulationViewerEyeRegion::rankForeground(Object obj)
00266 {
00267   // This is an ad-hoc way to determine which object is most in front.
00268 
00269   const int h=1080,w=1920;
00270   const double scrsize= h*w;
00271   const size_t npos = std::string::npos;
00272 
00273   // simple way to assign foregroundness
00274   std::string name = toLowerCase(getObjName(obj.id));
00275   if(name.find("eyes") != npos || name.find("mouth") != npos) return 4.0;
00276   if(name.find("head") != npos || name.find("face") != npos) return 3.0;
00277   if(name.find("body") != npos) return 2.0;
00278   if(name.find("man") != npos || name.find("guy") != npos ||
00279      name.find("girl") != npos || name.find("person") != npos ||
00280      name.find("people") != npos || name.find("group") != npos)
00281      return area(obj.polygon)/scrsize+1; // weight based on area, normed by screen size - smaller is worse
00282   if(obj.id == NULL_OBJ) return 0;
00283   else return 1-area(obj.polygon)/scrsize; // smaller is better
00284   // none is assigned 
00285 }
00286 
00287 // ######################################################################
00288 std::string SimulationViewerEyeRegion::listAllRegionsHit(const Point2D<int> pt, uint fNum)
00289 {
00290   if(itsObjectsInfo.get() == 0)
00291     LFATAL("No objects data - check xml file.");
00292 
00293   if(itsFrameNumber >= itsObjectsInfo->getNumScenes())
00294     {
00295       LINFO("Ran out of XML scene data...");
00296       return std::string();
00297     }
00298 
00299   //TODO: should check pt is also looking at current frame w.r.t cropping, etc.
00300 
00301   Scene sceneData =
00302     itsObjectsInfo->getSceneData(fNum);
00303 
00304   // find which images this saccade target hits
00305   std::string hits;
00306 
00307   for(std::vector<Object>::iterator itrObject =
00308         sceneData.objects.begin(); itrObject != sceneData.objects.end(); itrObject++)
00309     if(pnpoly((*itrObject).polygon,pt))
00310       {
00311         if (!hits.empty()) hits += ";"; //delimiter
00312         hits += getObjName((*itrObject).id);
00313       }
00314 
00315   if (hits.empty()) 
00316     {
00317       LINFO("nothing hit!");  
00318       hits = "none";
00319     }
00320   return hits;
00321 }
00322 // ######################################################################
00323 void SimulationViewerEyeRegion::extraSampleProcessing(const rutz::shared_ptr<EyeData> data)
00324 {
00325   Point2D<int> currPos = rawToRet(data->position());
00326   uint hitObjID = findHitRegion(currPos);
00327 
00328   if(hitObjID != itsCurrRegionID)
00329     {
00330       // every time we switch objects we send output to a different file than the one for svem data
00331       // this gives an object by object account instead of a saccade by saccade account
00332       writeROIOutput(currPos);
00333 
00334       // TODO: incorporate output into one file, interweave headers? something perhaps more meaningful, less readable though.
00335       // probably not worth it as a separate option..
00336       // TODO: work into multiple eyetrace streams?
00337 
00338       Object oldObj = getSceneObj(itsCurrRegionID, itsObjectFrameOnset),
00339         newObj = getSceneObj(hitObjID);
00340       //            CLINFO("**** Object gaze shift found: %s (%0.3f)->%s (%0.3f) at %.1fms **** ",
00341       //   getObjName(oldObj.id).c_str(), rankForeground(oldObj),
00342       //   getObjName(newObj.id).c_str(), rankForeground(newObj),
00343       //   itsCurrTime.msecs());
00344       
00345       // update new information
00346       itsCurrRegionID = hitObjID;
00347       itsObjectOnset = itsCurrTime;
00348       itsObjectFrameOnset = itsFrameNumber;
00349       itsObjectEntry = data;
00350     }
00351 }
00352 
00353 // ######################################################################
00354 void SimulationViewerEyeRegion::writeROIOutput(Point2D<int> currPos)
00355 {
00356   // writes another file with more specific region data, namely:
00357   // distances to different objects
00358   // only works for one file at a time right now
00359 
00360   if(itsObjectsInfo.get() == 0)
00361     LFATAL("No objects data - check xml file.");
00362   if(itsFrameNumber >= itsObjectsInfo->getNumScenes())
00363     {
00364       LINFO("Ran out of XML scene data...");
00365       return;
00366     }
00367 
00368   // if we don't have the name for the file, exit
00369   if (itsRegionOutFname.getVal().empty()) return;
00370 
00371 
00372   if (!itsRegHeaderWritten) //write the header first
00373     {
00374       itsRegHeaderWritten = true;
00375 
00376       std::string header;
00377       header += "objname onset duration ";
00378       for(std::vector<std::string>::iterator iStr = itsObjectsNames.begin();
00379           iStr != itsObjectsNames.end(); iStr++)
00380         header += sformat("%sDist ", (*iStr).c_str());
00381 
00382       if (itsRegionOutFile)
00383         (*itsRegionOutFile) << header << std::endl;
00384 
00385   //      return; // don't want to process first object
00386 
00387     }
00388 
00389   std::string output;
00390 
00391   // first, the last region
00392   Object thisObj =
00393     getSceneObj(itsCurrRegionID,itsObjectFrameOnset);
00394   output += sformat("%s ", getObjName(thisObj.id).c_str());
00395 
00396   // second, the time entered to that region
00397   output += sformat("%.1fms ", itsObjectOnset.msecs());
00398   // third, the time elapsed in that region
00399   output += sformat("%.1fms ", (itsCurrTime-itsObjectOnset).msecs());
00400 
00401   // now, for distances to region.
00402   // we precompute the distances to each region (calculated from edges)
00403   // and sample at N evenly spaced frames to see where the average distance is
00404   const uint N = 5;
00405   uint iFrame;
00406 
00407   double dist;
00408   const double NOT_IN_FRAME = 10000; //out of range
00409   std::vector<std::vector<double> > distsNow
00410     (itsNumObjects, std::vector<double>(N,NOT_IN_FRAME));
00411 
00412   for(uint i = 0; i < N; i++)
00413     {
00414       iFrame = itsObjectFrameOnset + uint((itsFrameNumber-itsObjectFrameOnset)*i/N);
00415       Scene sceneData =
00416         itsObjectsInfo->getSceneData(iFrame);
00417 
00418       // find the distances to the objects in that frame
00419       std::vector<Object>::iterator itr;
00420       for(itr = sceneData.objects.begin(); itr != sceneData.objects.end(); itr++)
00421         {
00422           std::string objName = getObjName((*itr).id);
00423           std::vector<Point2D<int> > objPoly = (*itr).polygon; //grab its polygon
00424           uint ps = objPoly.size();
00425           uint objID = (*itr).id;
00426 
00427           // find min distance to polygon by iterating around edges
00428           double mindist = 10000;
00429           for (uint ii = 0, jj = ps-1; ii < ps; jj = ii++)
00430             {
00431               dist = currPos.distanceToSegment(objPoly[ii],objPoly[jj]);
00432               if(mindist > dist) mindist = dist;
00433             }
00434 
00435           // assign distance as inside or outside a polygon (-/+)
00436           distsNow[objID][i] = (pnpoly(objPoly,currPos)) ?
00437             -mindist : mindist;
00438         }
00439     }
00440 
00441   uint nPts;
00442   for(uint i = 0; i < itsNumObjects; i++) // report the average of those distances
00443     {
00444       nPts = 0;
00445       dist = 0;
00446       for(uint j = 0; j < N; j++)
00447         {
00448           // if the object is not in the frame we do not average it
00449           if(distsNow[i][j] != NOT_IN_FRAME) nPts++;
00450           dist += distsNow[i][j];
00451         }
00452       if (nPts == 0) output += "NaN "; // to be read by matlab
00453       else output += sformat("%0.3f ", dist/nPts);
00454     }
00455 
00456   if (itsRegionOutFile)
00457     (*itsRegionOutFile) << output << std::endl;
00458 }
00459 
00460 // ######################################################################
00461 void SimulationViewerEyeRegion::drawEye(const rutz::shared_ptr<EyeData> rawPos, const uint tN)
00462 {
00463   // convert to retinal coordinates (accounting for any shifting,
00464   // embedding, etc):
00465   // Point2D<int> currPos = rawToRet(rawPos->position());
00466  
00467  const PixRGB<byte> col = itsEyeStyles[tN].col;
00468   if(itsFrameNumber >= itsObjectsInfo->getNumScenes())
00469     {
00470       LINFO("Ran out of XML scene data... (%d/%d)",itsFrameNumber,
00471             itsObjectsInfo->getNumScenes());
00472       return;
00473     }
00474 
00475   // note: these functions are tolerant to
00476   // coordinates outside the actual image area
00477   // this may cause errors if the eye coordinate is outside
00478 
00479   if(itsHighlightMode.getVal().compare("traced") == 0)
00480     {
00481       Object currObj =
00482         getSceneObj(itsCurrRegionID);
00483 
00484       drawFilledPolygon(itsTargetsMask, currObj.polygon, col);
00485       drawRegions(currObj);
00486     }
00487   if(itsObjectDrawMode.getVal().compare("traced") == 0)
00488     {
00489       Object currObj =
00490         getSceneObj(itsCurrRegionID);
00491       drawRegions(currObj);
00492     }
00493   SimulationViewerEyeMvt::drawEye(rawPos, tN);
00494 }
00495 
00496 // ######################################################################
00497 void SimulationViewerEyeRegion::drawFOA(const Point2D<int> target, const uint tN)
00498 {
00499   const PixRGB<byte> col = itsEyeStyles[tN].col;
00500   if(itsFrameNumber >= itsObjectsInfo->getNumScenes())
00501     {
00502       LINFO("Ran out of XML scene data...");
00503       return;
00504     }
00505 
00506   if(itsHighlightMode.getVal().compare("targeted") == 0)
00507     {
00508       uint hitObjID = findHitRegion(target);
00509       Object thisObj =
00510         getSceneObj(hitObjID);
00511       drawFilledPolygon(itsTargetsMask, thisObj.polygon, col);
00512       drawRegions(thisObj);
00513     }
00514   if(itsObjectDrawMode.getVal().compare("targeted") == 0)
00515     {
00516       uint hitObjID = findHitRegion(target);
00517       Object thisObj =
00518         getSceneObj(hitObjID);
00519       drawRegions(thisObj);
00520     }
00521 
00522   SimulationViewerEyeMvt::drawFOA(target,tN);
00523 }
00524 
00525 // ######################################################################
00526 void SimulationViewerEyeRegion::drawRegions(Object myObj)
00527 {
00528   if(itsObjectsInfo.get() == 0)
00529     LFATAL("No objects data - check xml file.");
00530   
00531 
00532   if(itsFrameNumber >= itsObjectsInfo->getNumScenes())
00533     {
00534       LINFO("Ran out of XML scene data...");
00535       return;
00536     }
00537 
00538   Image<PixRGB<byte> > shapes(itsDrawings.getDims(),ZEROS);
00539 
00540   Scene sceneData = itsObjectsInfo->getSceneData(itsFrameNumber);
00541   if(myObj.id!=NULL_OBJ || itsObjectDrawMode.getVal().compare("all") != 0)
00542     {
00543       PixRGB<byte> lineCol(0,255,0);
00544       if (itsRandomColoring.getVal())
00545         lineCol = itsRandColors[myObj.id];
00546 
00547 
00548       drawOutlinedPolygon(shapes, myObj.polygon,
00549                           lineCol,
00550                                                                                                         Point2D<int>(0,0), 0, 1.0, 0, 0,
00551                                                                                                         itsLineThickness.getVal());
00552 
00553       // find appropriate (i.e. upperleft most) corner to write name on...
00554       // define upper left corner as farthest from 
00555       // lowerleft/upperright diagonal of polygon
00556       Point2D<int> cm = centroid(myObj.polygon);
00557       Point2D<int> upperleft = cm - Point2D<int>(-10,10);
00558       
00559       double thisDist, maxDist = 0; 
00560       Point2D<int> refPt = myObj.polygon[0];
00561       for(uint i = 0; i < myObj.polygon.size(); i++) {
00562         thisDist = myObj.polygon[i].distanceToLine(cm, upperleft, true);
00563         if (thisDist > maxDist) {
00564           maxDist = thisDist;
00565           refPt = myObj.polygon[i];
00566         }
00567       }
00568 
00569       writeText(itsDrawings, refPt+Point2D<int>(10,5), 
00570                 getObjName(myObj.id).c_str(),
00571                 PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
00572                 SimpleFont::FIXED(10), true);
00573     }
00574   else { // if no obj, show all objects in this frame
00575     Scene thisScene = itsObjectsInfo->getSceneData(itsFrameNumber);
00576     for (std::vector<Object>::iterator iObj = thisScene.objects.begin();
00577          iObj != thisScene.objects.end(); iObj++)
00578       drawRegions(*iObj);
00579   }
00580   itsDrawings = composite(itsDrawings,shapes);
00581 }
00582 
00583 
00584 // ######################################################################
00585 Object SimulationViewerEyeRegion::getSceneObj(uint objID, uint FrameNum)
00586 {
00587   Object non_object = Object();
00588   non_object.name = getObjName(NULL_OBJ);
00589   non_object.id = NULL_OBJ;
00590   if(objID == NULL_OBJ) return non_object; // no object targeted
00591   ASSERT(FrameNum < itsObjectsInfo->getNumScenes());
00592 
00593   Scene sceneData = itsObjectsInfo->getSceneData(FrameNum);
00594   for(std::vector<Object>::iterator itrObject =
00595         sceneData.objects.begin(); itrObject != sceneData.objects.end(); itrObject++)
00596     if ((*itrObject).id==objID) return (*itrObject);
00597 
00598   return non_object; // object not found
00599 }
00600 
00601 // ######################################################################
00602 std::string SimulationViewerEyeRegion::getObjName(uint objID)
00603 {
00604   if(objID == NULL_OBJ) return "none";
00605   else if(objID >= itsNumObjects) LFATAL("%d illegal index (max = %d, null = %d)", objID, itsNumObjects, NULL_OBJ);
00606   return itsObjectsNames[objID];
00607 }
00608 
00609 // ######################################################################
00610 std::string SimulationViewerEyeRegion::craftSVEMOutput(const std::string tfn,
00611                         const rutz::shared_ptr<EyeData> data)
00612 {
00613   // Write some measurements to a string. Here, we just put all the stats
00614   // into a text string, and we will send that off to be
00615   // written to disk.
00616 
00617   // The first time we run this, we build a header for the file
00618   // to know what stats to read. This is done in the craft submodules.
00619 
00620   // Note: This overloads the SVEyeMvt class method craftSVEMOutput.
00621   // It does so to insert a 
00622   // In the future we may implement a policy-based method to grab different output modules.
00623 
00624   std::string output = SimulationViewerEyeMvt::craftSVEMOutput(tfn,data);
00625 
00626   // add which objects are saccaded to/from
00627   output += craftRegionOutput(data);
00628 
00629   return output;
00630 }
00631 
00632 // ######################################################################
00633 std::string SimulationViewerEyeRegion::
00634 craftRegionOutput(const rutz::shared_ptr<EyeData> data)
00635 {
00636   std::string output;
00637   // output region of origin, region of destination
00638 
00639   Point2D<int> position = rawToRet(data->position());
00640   Point2D<int> sacTarget = rawToRet(data->saccadeTarget());
00641   bool giveAllRegions = true; //TODO: should be ModelParam
00642   if(giveAllRegions)
00643     {
00644       uint destObjID = findHitRegion(sacTarget);
00645       output += sformat(" %s %s %s %s",
00646                         getObjName(itsCurrRegionID).c_str(),
00647                         listAllRegionsHit(position).c_str(),
00648                         getObjName(destObjID).c_str(),
00649                         listAllRegionsHit(sacTarget).c_str());
00650 
00651       if(!itsHeaderCrafted)
00652         {
00653           itsOutFields.push_back("bestregion_src");
00654           itsOutFields.push_back("region_src");
00655           itsOutFields.push_back("bestregion_target");
00656           itsOutFields.push_back("region_target");
00657         }
00658     }
00659   else
00660     {
00661       uint destObjID = findHitRegion(sacTarget);
00662       output += sformat(" %s %s",
00663                         getObjName(itsCurrRegionID).c_str(),
00664 
00665                         getObjName(destObjID).c_str());
00666       if(!itsHeaderCrafted)
00667         {
00668           itsOutFields.push_back("region_src");
00669           itsOutFields.push_back("region_target");
00670         }
00671 
00672     }
00673   return output;
00674 }
00675 
00676 // ######################################################################
00677 Image< PixRGB<byte> > SimulationViewerEyeRegion::getTraj(SimEventQueue& q)
00678 {
00679   LDEBUG("Buffering output frame %d...", itsFrameNumber);
00680 
00681 GVX_TRACE(__PRETTY_FUNCTION__);
00682   // get the latest retina image:
00683   Image< PixRGB<byte> > input;
00684   if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this, SEQ_ANY))
00685     {
00686       input = e->frame().colorByte();
00687 
00688       if(itsObjectDrawMode.getVal().compare("all") == 0) 
00689         drawRegions();
00690       else if(itsObjectDrawMode.getVal().compare("selected") == 0 &&
00691               !itsSelectedObjects.getVal().empty())
00692         {
00693           Scene sceneData = itsObjectsInfo->getSceneData(itsFrameNumber);
00694           for(uint i = 0; i < itsObjectsInfo->getNumObj(itsFrameNumber); i++)
00695             {
00696               Object objData = sceneData.objects[i];
00697 
00698               //TODO: write rules to determine which objects to draw
00699               //as external opt
00700               std::string objName = getObjName(objData.id);
00701               //if(objName.compare(itsSelectedObjects.getVal()) == 0) 
00702               drawRegions(objData);
00703             }
00704         }
00705     }
00706   else
00707     LFATAL("Could not find required SimEventRetinaImage");
00708 
00709   // draw the highlighted regions if there are any...
00710   if(itsTargetsMask.initialized()) { //TODO: add && itsTargetsMask is not blank for speed
00711     input = alphaBlend(itsTargetsMask, input,
00712                        itsHitTransparency.getVal());
00713   }
00714 
00715   // reinit these here, although this should be done in onSimEventClockTick
00716   itsTargetsMask.resize(input.getDims(), true);
00717 
00718   // make a composite of the input + the drawings:
00719   Image<PixRGB<byte> > comp = composite(itsDrawings, input);
00720 
00721   // return a plain traj?
00722   if (itsSaveTraj.getVal()) return comp;
00723 
00724   // let's get the current saliency map (normalized):
00725   const Dims dims = input.getDims();
00726   Image<float> sm = getMap(q, false);
00727   if (sm.initialized()) sm = rescaleOpt(sm, dims, itsDisplayInterp.getVal());
00728   else sm.resize(dims, true); // blank
00729   Image< PixRGB<byte> > smc = toRGB(Image<byte>(sm));
00730 
00731   // make a composite of the instantaneous SM + the drawings:
00732   Image< PixRGB<byte> > smcomp = composite(itsDrawings, smc);
00733 
00734   // otherwise, return mega combo; we have two formats: if we have a
00735   // max-cache, it will be a 4-image format, otherwise a 2-image
00736   // format:
00737   Image< PixRGB<byte> > ret;
00738   if (itsMaxCacheSize.getVal())
00739     {
00740       // 4-image format
00741       Image<float> maxsm =
00742         rescaleOpt(itsMaxCache.getMax(), dims, itsDisplayInterp.getVal());
00743       Image< PixRGB<byte> > maxsmc = toRGB(Image<byte>(maxsm));
00744 
00745       ret = concatX(concatY(input, smcomp),
00746                     concatY(comp, composite(itsDrawings, maxsmc)));
00747 
00748       drawGrid(ret, dims.w()-1, dims.h()-1, 3, 3, PixRGB<byte>(128, 128, 128));
00749     }
00750   else
00751     {
00752       // 2-image format:
00753       ret = concatX(comp, smcomp);
00754       drawLine(ret, Point2D<int>(dims.w()-1, 0), Point2D<int>(dims.w()-1, dims.h()-1),
00755                PixRGB<byte>(255, 255, 0), 1);
00756       drawLine(ret, Point2D<int>(dims.w(), 0), Point2D<int>(dims.w(), dims.h()-1),
00757                PixRGB<byte>(255, 255, 0), 1);
00758     }
00759 
00760   // make sure image is not unreasonably large:
00761   while (ret.getWidth() > itsMaxComboWidth.getVal())
00762     ret = decY(lowPass3y(decX(lowPass3x(ret))));
00763 
00764   return ret;
00765 }
00766 
00767 // ######################################################################
00768 /* So things look consistent in everyone's emacs... */
00769 /* Local Variables: */
00770 /* indent-tabs-mode: nil */
00771 /* End: */
00772 
Generated on Sun May 8 08:05:26 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3