SimulationViewerNerdCam.C

Go to the documentation of this file.
00001 /*!@file Neuro/SimulationViewerNerdCam.C entry interface between INVT and ASAC */
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: T. Nathan Mundhenk <mundhenk@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/SimulationViewerNerdCam.C $
00035 // $Id: SimulationViewerNerdCam.C 13065 2010-03-28 00:01:00Z itti $
00036 //
00037 
00038 #include "Neuro/SimulationViewerNerdCam.H"
00039 
00040 #include "Channels/BlueYellowChannel.H"
00041 #include "Channels/ChannelBase.H"
00042 #include "Channels/ColorChannel.H"
00043 #include "Channels/DirectionChannel.H"
00044 #include "Channels/FlickerChannel.H"
00045 #include "Channels/GaborChannel.H"
00046 #include "Channels/IntensityChannel.H"
00047 #include "Channels/MotionChannel.H"
00048 #include "Channels/OrientationChannel.H"
00049 #include "Channels/RedGreenChannel.H"
00050 #include "Image/ColorOps.H"    // for normalizeC()
00051 #include "Image/CutPaste.H"    // for concatX()
00052 #include "Image/DrawOps.H"
00053 #include "Image/MathOps.H"   // for takeMax()
00054 #include "Image/PyramidOps.H"
00055 #include "Image/ShapeOps.H"  // for crop()
00056 #include "Image/Transforms.H"  // for contour2D()
00057 #include "Image/LevelSpec.H"
00058 #include "Neuro/AttentionGuidanceMap.H"
00059 #include "Neuro/NeuroOpts.H"
00060 #include "Neuro/NeuroSimEvents.H"
00061 #include "Neuro/SaliencyMap.H"
00062 #include "Neuro/TaskRelevanceMap.H"
00063 #include "Raster/Raster.H"
00064 #include "Simulation/SimEventQueue.H"
00065 #include "Transport/FrameInfo.H"
00066 #include "Transport/FrameOstream.H"
00067 #include "Util/readConfig.H"
00068 #include <time.h>
00069 #include <stdio.h>
00070 
00071 
00072 
00073 // ######################################################################
00074 SimulationViewerNerdCam::SimulationViewerNerdCam(OptionManager& mgr,
00075                                            const std::string& descrName,
00076                                            const std::string& tagName) :
00077   SimulationViewer(mgr, descrName, tagName),
00078   SIMCALLBACK_INIT(SimEventInputFrame),
00079   SIMCALLBACK_INIT(SimEventClockTick),
00080   SIMCALLBACK_INIT(SimEventWTAwinner),
00081   SIMCALLBACK_INIT(SimEventSaveOutput),
00082   itsMetrics(new SpatialMetrics(mgr)),
00083   itsColorBoring("SVcolorBoring", this, PixRGB<byte>(127, 0, 0)),
00084   itsColorLink("SVcolorLink", this, PixRGB<byte>(255, 0, 0)),
00085   itsColorNormal("SVcolorNormal", this, PixRGB<byte>(255, 255, 0)),
00086   itsConfigFile(&OPT_NerdCamConfigFile, this),
00087   itsCropFOA(&OPT_SVcropFOA, this),
00088   itsDisplayAdditive(&OPT_SVdisplayAdditive, this),
00089   itsDisplayBoring(&OPT_SVdisplayBoring, this),
00090   itsDisplayFOA(&OPT_SVdisplayFOA, this),
00091   itsDisplayFOALinks(&OPT_SVdisplayFOALinks, this),
00092   itsDisplayHighlights(&OPT_SVdisplayHighlights, this),
00093   itsDisplayPatch(&OPT_SVdisplayPatch, this),
00094   itsDisplaySMmodulate(&OPT_SVdisplaySMmodulate, this),
00095   itsDisplayTime(&OPT_SVdisplayTime, this),
00096   itsFOApsiz("SVfoapsiz", this, 3),
00097   itsFOAthick("SVfoathick", this, 3),
00098   itsFOAlinkThick("SVfoalinkthick", this, 2),
00099   itsMegaCombo(&OPT_SVmegaCombo, this),
00100   itsWarp3Dpitch("SVwarp3DInitialPitch", this, -25.0F),
00101   itsWarp3Dyaw("SVwarp3DInitialYaw", this, -15.0F),
00102   itsWarp3DpitchRate("SVwarp3DpitchRate", this, 0.0F),
00103   itsWarp3DyawRate("SVwarp3DyawRate", this, 15.0F),
00104   itsWarp3DpitchMax("SVwarp3DpitchMax", this, 0.0F),
00105   itsWarp3DyawMax("SVwarp3DyawMax", this, 20.0F),
00106   itsUseLargerDrawings(&OPT_SVuseLargerDrawings, this),
00107   itsCumFOAmask(),
00108   itsCurrFOA(WTAwinner::NONE()),
00109   itsCurrFOAmask(),
00110   itsCurrTime(),
00111   itsDims3D(),
00112   itsMultiTraj(),
00113   itsPrevFOA(WTAwinner::NONE()),
00114   itsTraj(),
00115   itsPitch3D(-1.0e10F),
00116   itsYaw3D(-1.0e10F)
00117 {
00118   this->addSubComponent(itsMetrics);
00119   itsInit = false;
00120   nlog("INIT - Normal startup recognized");
00121 }
00122 
00123 // ######################################################################
00124 SimulationViewerNerdCam::~SimulationViewerNerdCam()
00125 {
00126   nlog("SHUTDOWN - normal shutdown recognized");
00127 }
00128 
00129 // ######################################################################
00130 void SimulationViewerNerdCam::init(const ushort baseSizeX,
00131                                    const ushort baseSizeY)
00132 {
00133   char        base[100];
00134   std::string logstr;
00135 
00136   itsBaseSizeX = baseSizeX;
00137   itsBaseSizeY = baseSizeY;
00138 
00139   const std::string configFile = itsConfigFile.getVal();
00140   readConfig config(25);
00141   config.openFile(configFile.c_str(),false);
00142 
00143   itsLogFile           = config.getItemValueS("LogFile");
00144   sprintf(base,"INIT - Config File %s",configFile.c_str());
00145   logstr = base; nlog(logstr);
00146 
00147   itsOutputMotionImage = config.getItemValueS("OutputMotionImage");
00148   itsOutputSalMapImage = config.getItemValueS("OutputSalMapImage");
00149   itsOutput3DImage     = config.getItemValueS("Output3DImage");
00150   itsOutputMegaImage   = config.getItemValueS("OutputMegaImage");
00151   itsOutputTrajImage   = config.getItemValueS("OutputTrajImage");
00152   itsWebPageFile       = config.getItemValueS("WebPageFile");
00153   itsStatusFile        = config.getItemValueS("StatusFile");
00154   itsStatusHeader      = config.getItemValueS("StatusHeader");
00155   itsStatusFooter      = config.getItemValueS("StatusFooter");
00156   itsChannelFile       = config.getItemValueS("ChannelFile");
00157   itsBaseURL           = config.getItemValueS("BaseURL");
00158   itsBaseName          = config.getItemValueS("BaseName");
00159   itsMotionThreshold   = config.getItemValueF("MotionThreshold");
00160 
00161   sprintf(base,"INIT - Image %d x %d",itsBaseSizeX,itsBaseSizeY);
00162   logstr = base; nlog(logstr);
00163   nlog("INIT - Init complete");
00164   itsInit = true;
00165 
00166   // Get server Start Time
00167   time_t rawtime; struct tm * timeinfo;
00168   time ( &rawtime ); timeinfo = localtime ( &rawtime );
00169   itsStartTime   =  asctime (timeinfo);
00170   itsTotalFrames = 0;
00171 }
00172 
00173 // ######################################################################
00174 void SimulationViewerNerdCam::reset1()
00175 {
00176   itsCurrFOA     = WTAwinner::NONE();
00177   itsCurrFOAmask.freeMem();
00178   itsCurrTime    = SimTime::ZERO();
00179   itsCumFOAmask.freeMem();
00180   itsDims3D      = Dims();
00181   itsHasNewInput = false;
00182   itsMultiTraj.reset();
00183   itsPitch3D     = -1.0e10F;
00184   itsPrevFOA     = WTAwinner::NONE();
00185   itsTraj.freeMem();
00186   itsYaw3D       = -1.0e10F;
00187 
00188   SimulationViewer::reset1();
00189   nlog("INIT - Model reset complete");
00190 }
00191 
00192 // ######################################################################
00193 void SimulationViewerNerdCam::start2()
00194 {
00195   // do we wnat larger drawings?
00196   if (itsUseLargerDrawings.getVal())
00197   {
00198     itsFOApsiz.setVal(5);
00199   }
00200 }
00201 
00202 // ######################################################################
00203 void SimulationViewerNerdCam::
00204 onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e)
00205 {
00206   LINFO("Inputing to Nerd-cam");
00207   // keep a copy of the image
00208   itsInput = e->frame().asRgb();
00209 
00210   if (!itsInit) init(itsInput.getWidth(), itsInput.getHeight());
00211 
00212   // erase old trajectory and replace it by fresh new input:
00213   itsTraj = itsInput;
00214   // we have a new input; this will force redrawing various things on
00215   // the trajectory in case people request it before a new shift of
00216   // attention or other event occurrs:
00217   itsHasNewInput = true;
00218   itsTotalFrames++;
00219 }
00220 
00221 // ######################################################################
00222 void SimulationViewerNerdCam::
00223 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& e)
00224 {
00225   const SimTime t = q.now();
00226 
00227   // do the 3D rotation:
00228   if (itsPitch3D == -1.0e10F)
00229     itsPitch3D = itsWarp3Dpitch.getVal();
00230   if (itsYaw3D == -1.0e10F)
00231     itsYaw3D = itsWarp3Dyaw.getVal();
00232 
00233   itsPitch3D += itsWarp3DpitchRate.getVal() * (t - itsCurrTime).secs();
00234   itsYaw3D += itsWarp3DyawRate.getVal() * (t - itsCurrTime).secs();
00235 
00236   if (itsYaw3D >= itsWarp3DyawMax.getVal() ||
00237       itsYaw3D <= -itsWarp3DyawMax.getVal())
00238     itsWarp3DyawRate.setVal(- itsWarp3DyawRate.getVal());
00239   if (itsPitch3D >= itsWarp3DpitchMax.getVal() ||
00240       itsPitch3D <= -itsWarp3DpitchMax.getVal())
00241     itsWarp3DpitchRate.setVal(- itsWarp3DpitchRate.getVal());
00242 
00243   itsCurrTime = t;
00244 }
00245 
00246 // ######################################################################
00247 void SimulationViewerNerdCam::
00248 onSimEventWTAwinner(SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e)
00249 {
00250   // Any output from the ShapeEstimator?
00251   Image<byte> foaMask;
00252   if (SeC<SimEventShapeEstimatorOutput> ee = q.check<SimEventShapeEstimatorOutput>(this))
00253     {
00254       foaMask = Image<byte>(ee->smoothMask() * 255.0F);
00255       if (foaMask.isSameSize(itsInput) == false)
00256         LFATAL("Dimensions of FOAmask must match those of input");
00257     }
00258 
00259   // check dims of mask:
00260   if (foaMask.initialized() && foaMask.isSameSize(itsInput) == false)
00261     LFATAL("Dimensions of FOAmask must match those of input");
00262 
00263   // update our internals:
00264   itsPrevFOA = itsCurrFOA; itsCurrFOA = e->winner();
00265   if (foaMask.initialized())
00266     itsCurrFOAmask = foaMask;  // keep a copy of the FOA mask
00267   else
00268     {
00269       // draw a disk at current foa position:
00270       itsCurrFOAmask.resize(itsInput.getDims(), true);
00271       if (itsCurrFOA.isValid())
00272         drawDisk(itsCurrFOAmask, itsCurrFOA.p,
00273                  itsMetrics->getFOAradius(), byte(255));
00274     }
00275 
00276   // update cumulative FOA mask:
00277   if (itsDisplayAdditive.getVal() &&            // cumulative display?
00278       itsCumFOAmask.initialized() &&            // not first frame?
00279       itsCumFOAmask.isSameSize(itsCurrFOAmask)) // not changing frame dims?
00280     itsCumFOAmask = takeMax(itsCumFOAmask, itsCurrFOAmask);
00281   else
00282     itsCumFOAmask = itsCurrFOAmask;
00283 
00284   // forget it if we don't have a traj yet:
00285   if (itsTraj.initialized() == false) return;
00286 
00287   // draw the FOA:
00288   if (itsDisplayFOA.getVal() || itsDisplayPatch.getVal()) drawFOA();
00289 
00290   // link the last two FOAs:
00291   if (itsDisplayFOALinks.getVal()) linkFOAs();
00292 }
00293 
00294 // ######################################################################
00295 Image< PixRGB<byte> > SimulationViewerNerdCam::getTraj(SimEventQueue& q)
00296 {
00297   //LINFO("Get Traj");
00298   itsCurrTime = q.now(); bool redraw = false;
00299   if (itsTraj.initialized() == false) return itsTraj;
00300 
00301   // ##### if not doing additive displays, clear traj and redraw only
00302   // ##### current foa/eye/head data:
00303   if (itsDisplayAdditive.getVal() == false)
00304     { itsTraj = itsInput; redraw = true; }
00305 
00306   // ##### re-do a bunch of drawings if we destroyed the traj
00307   // ##### (foveation, highlights, etc). We only care about current
00308   // ##### attention/eye/head position and not about any previous ones
00309   // ##### or links:
00310   if (redraw || itsHasNewInput)
00311   {
00312     if (itsDisplayFOA.getVal() || itsDisplayPatch.getVal()) drawFOA();
00313     itsHasNewInput = false;
00314   }
00315 
00316   // ##### let's get ready to return the traj, but we may reshape it
00317   // ##### just before that, or return something that involves the
00318   // ##### traj plus some other maps in some combined display:
00319   Image< PixRGB<byte> > ret;
00320 
00321   // if cropping let's crop now:
00322   // resizing and other normalizations are taken care of by FrameOstream
00323   if (itsCropFOA.getVal().isNonEmpty())
00324   {
00325     Dims crop_dims = itsCropFOA.getVal();
00326     Rectangle crect =
00327       Rectangle::tlbrI(itsCurrFOA.p.j - crop_dims.h() / 2,
00328                       itsCurrFOA.p.i - crop_dims.w() / 2,
00329                       itsCurrFOA.p.j + crop_dims.h() / 2 - 1,
00330                       itsCurrFOA.p.i + crop_dims.w() / 2 - 1);
00331     ret = crop(itsTraj, crect, true);
00332   }
00333   else ret = itsTraj;
00334 
00335   // ##### do a bunch of last-minute drawings:
00336   if (itsDisplayTime.getVal()) drawTime(ret);
00337 
00338   return ret;
00339 }
00340 
00341 // ######################################################################
00342 void SimulationViewerNerdCam::saveResults(const nub::ref<FrameOstream>& ofs,
00343                                           SimEventQueue& q)
00344 {
00345   // update the trajectory:
00346   const Image< PixRGB<byte> > traj = getTraj(q);
00347 
00348   const double msecs = itsCurrTime.msecs();
00349 
00350   LINFO("Running Nerd-cam on Sample Input time %f ms",msecs);
00351   Image<float> salMap             = getMap(q);
00352 
00353   // write out saliency map
00354   itsSalMap = rescale(salMap,itsBaseSizeX,itsBaseSizeY);
00355 
00356   // write web status page
00357 
00358   const Image<byte> bsal = itsSalMap;
00359   struct flock fl_smap;
00360   int fd_smap;
00361   lockFile(itsOutputSalMapImage,fd_smap,fl_smap);
00362   Raster::WriteRGB(bsal,itsOutputSalMapImage);
00363 
00364 
00365   nub::soft_ref<MotionChannel>      mc;
00366 
00367   LFATAL("FIXME I should derive from SimulationViewerStd");
00368   /*
00369   if(vc->hasSubChan("motion"))
00370     dynCastWeakToFrom(mc, vc->subChan("motion"));
00371   else
00372   {
00373     nlog("FATAL - No motion channel supplied by brain");
00374     LFATAL("No Motion Channel Supplied by Brain");
00375   }
00376   */
00377   if (mc.isInvalid())
00378   {
00379     nlog("FATAL - Channel named 'motion' not a MotionChannel");
00380     LFATAL("Channel named 'motion' not a MotionChannel");
00381   }
00382 
00383   int fd_traj, fd_mega;
00384   struct flock fl_traj;
00385   struct flock fl_mega;
00386   if(itsTraj.initialized())
00387   {
00388     // draw simple trajectory image
00389     lockFile(itsOutputTrajImage,fd_traj,fl_traj);
00390     Raster::WriteRGB(traj,itsOutputTrajImage);
00391     // Draw a megacombo
00392     if(itsTotalFrames > 1)
00393     {
00394       const Image< PixRGB<byte> > meg = drawMegaCombo(q);
00395       lockFile(itsOutputMegaImage,fd_mega,fl_mega);
00396       Raster::WriteRGB(meg,itsOutputMegaImage);
00397       itsComboSizeX = meg.getWidth();
00398       itsComboSizeY = meg.getHeight();
00399     }
00400   }
00401 
00402   float min = 0, max = 0, avg = 0;
00403   float div = 0;
00404 
00405   bool doMotion = false;
00406 
00407   for(ushort i = 0; i < mc->numChans(); i++)
00408   {
00409     float mi,ma,av;
00410     const Image<float> ftmp = mc->dirChan(i).getOutput();
00411     getMinMaxAvg(ftmp,mi,ma,av);
00412     min += mi; max += ma; avg += av;
00413     div++;
00414     if(ma > itsMotionThreshold)
00415       doMotion = true;
00416   }
00417   min = min/div; max = max/div; avg = avg/div;
00418 
00419 
00420   // write an image, something is moving
00421   int fd_mot;
00422   struct flock fl_mot;
00423   if(doMotion)
00424   {
00425     LINFO("Drawing Motion Image");
00426     const Image<PixRGB<byte> > bimg = itsInput;
00427     lockFile(itsOutputMotionImage,fd_mot,fl_mot);
00428     Raster::WriteRGB(bimg,itsOutputMotionImage);
00429   }
00430 
00431   // draw nifty 3D saliency map
00432   Image< PixRGB<byte> > ret = itsInput;
00433   drawGrid(ret, ret.getWidth() / 6, ret.getHeight() / 6, 3, 3,
00434            itsColorNormal.getVal());
00435   drawRect(ret, Rectangle::tlbrI(1, 1, ret.getHeight()-2, ret.getWidth()-2),
00436            itsColorNormal.getVal(), 3);
00437   ret = warp3Dmap(ret, getMap(q), itsPitch3D, itsYaw3D, itsDims3D);
00438   int fd_3d;
00439   struct flock fl_3d;
00440   lockFile(itsOutput3DImage,fd_3d,fl_3d);
00441   Raster::WriteRGB(ret,itsOutput3DImage);
00442   its3DSizeX = ret.getWidth();
00443   its3DSizeY = ret.getHeight();
00444 
00445   writeStatusPage();
00446 
00447   if(itsTotalFrames > 1)
00448   {
00449     writeChannelPage();
00450   }
00451 
00452   // unlock all our image files
00453   if(avg > itsMotionThreshold)
00454   {
00455     unlockFile(itsOutputMotionImage,fd_mot,fl_mot);
00456   }
00457   if(itsTraj.initialized())
00458   {
00459     unlockFile(itsOutputTrajImage,fd_traj,fl_traj);
00460     if(itsTotalFrames > 1)
00461     {
00462       unlockFile(itsOutputMegaImage,fd_mega,fl_mega);
00463     }
00464   }
00465   unlockFile(itsOutputSalMapImage,fd_smap,fl_smap);
00466   unlockFile(itsOutput3DImage,fd_3d,fl_3d);
00467 }
00468 
00469 // ######################################################################
00470 void SimulationViewerNerdCam::
00471 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00472 {
00473   this->save1(e->sinfo());
00474 }
00475 
00476 // ######################################################################
00477 void SimulationViewerNerdCam::save1(const ModelComponentSaveInfo& sinfo)
00478 {
00479   // get the OFS to save to, assuming sinfo is of type
00480   // SimModuleSaveInfo (will throw a fatal exception otherwise):
00481   nub::ref<FrameOstream> ofs =
00482     dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs;
00483 
00484   // also get the SimEventQueue:
00485   SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q;
00486 
00487   saveResults(ofs, *q);
00488 }
00489 
00490 // #####################################################################
00491 void SimulationViewerNerdCam::writeStatusPage() const
00492 {
00493   std::ifstream headFile(itsStatusHeader.c_str(),std::ios::in);
00494   std::ifstream footFile(itsStatusFooter.c_str(),std::ios::in);
00495 
00496   // get min/max/avg and stdev and number of peaks:
00497   double peaksum;
00498   const double sdev = stdev(itsSalMap);
00499   float mi, ma, av; getMinMaxAvg(itsSalMap, mi, ma, av);
00500   const int npeaks = findPeaks(itsSalMap, 0.0f, 255.0f, peaksum);
00501 
00502   // find the location of max in the salmap, at scale of original input:
00503   float maxval; Point2D<int> maxloc;
00504   findMax(itsSalMap, maxloc, maxval);
00505   const float scale = float(itsInput.getWidth()) / float(itsSalMap.getWidth());
00506   maxloc.i = int(maxloc.i * scale + 0.4999F);
00507   maxloc.j = int(maxloc.j * scale + 0.4999F);
00508 
00509   // find the location of min in the salmap, at scale of original input:
00510   float minval; Point2D<int> minloc;
00511   findMin(itsSalMap, minloc, minval);
00512   minloc.i = int(minloc.i * scale + 0.4999F);
00513   minloc.j = int(minloc.j * scale + 0.4999F);
00514 
00515   int fd; struct flock fl;
00516   lockFile(itsStatusFile,fd,fl);
00517   std::ofstream statFile(itsStatusFile.c_str(),std::ios::out);
00518 
00519   std::string in;
00520   while (headFile >> in)
00521   {
00522     if(!in.compare("\\"))
00523       statFile << "\n";
00524     else
00525       statFile << in << " ";
00526   }
00527   statFile.flush();
00528   statFile << "\n<!-- End Header File -->\n"
00529            << "<!--\n"
00530            << "Nerd Cam Daemon\n"
00531            << "T. Nathan Mundhenk and Laurent Itti\n"
00532            << "http://www.nerd-cam.com\n"
00533            << "-->\n"
00534            << "<a href=\"" << itsBaseURL  << "\">"
00535            << "<H1>"       << itsBaseName << "</a> "
00536            << "Detailed Server Status</H1>\n";
00537 
00538   time_t rawtime; struct tm * timeinfo;
00539   time ( &rawtime ); timeinfo = localtime ( &rawtime );
00540 
00541   // general server stats
00542   statFile << "<H2>Nerd-Cam Daemon Saliency Server Statistics </H2>\n"
00543            << "<table border=\"0\" width=\"800\">\n"
00544            << "<tr>\n"
00545            << "\t<td width=\"275\">\n"
00546            << "\t\t<H3>Current Time </H3>"
00547            << asctime (timeinfo) << "<br>\n"
00548            << "\t\t<H3>Server Start Time </H3>"
00549            << itsStartTime << "<br>\n"
00550            << "\t\t<H3>Total Frames Processed </H3>"
00551            << itsTotalFrames << "<br>\n"
00552            << "\t\t<p>&nbsp;</td>\n"
00553            << "\t<td width=\"525\" align=\"center\">\n"
00554            << "\t\t<h1>Last Nerd Spotted by Nerd-Cam</h1>\n"
00555            << "\t\t<p><img border=\"0\" src=\"nerd-cam.motion.png\" "
00556            << "width=\"320\" height=\"240\"></p>\n"
00557            << "\t</td>\n"
00558            << "</tr>\n"
00559            << "</table>\n";
00560 
00561   statFile.flush();
00562   // save some stats for that location:
00563   statFile << "<H2>Current Saliency Map Statistics </H2>\n"
00564            << "<table border=0 cellpadding=0 width=800>\n"
00565            << "<tr>\n"
00566            << "\t<td width=275 valign=top>\n"
00567            << "\t\t<H3>Point of Maximum Saliency </H3>"
00568            << "(" << maxloc.i << "," << maxloc.j << ")<br>\n"
00569            << "\t\t<H3>Point of Minimum Saliency </H3>"
00570            << "(" << minloc.i << "," << minloc.j << ")<br>\n"
00571            << "\t\t<H3>Maximum Saliency Value </H3>"
00572            << ma      << "<br>\n"
00573            << "\t\t<H3>Minimum Saliency Value </H3>"
00574            << mi      << "<br>\n"
00575            << "\t\t<H3>Average Saliency Value </H3>"
00576            << av      << "<br>\n"
00577            << "\t\t<H3>Standard Deviation </H3>"
00578            << sdev    << "<br>\n"
00579            << "\t\t<H3>Number of Peaks </H3>"
00580            << npeaks  << "<br>\n"
00581            << "\t\t<H3>Peak Sum </H3>"
00582            << peaksum << "<br>\n"
00583            << "\t</td>\n"
00584            << "\t<td width=525 valign=top align=\"center\">\n"
00585            << "\t\t<H1>Superimposed 3D Saliency Image</H1>\n"
00586            << "\t\t<img border=0 width="
00587            << its3DSizeX
00588            << " height="
00589            << its3DSizeY
00590            << " src=\"awesome.3d.image.png\" "
00591            << " alt=\"Awesome 3D Saliency Map "
00592            << "to shock and awe\"><br>\n"
00593            << "\t</td>\n"
00594            << "</tr>\n"
00595            << "</table>\n";
00596   statFile.flush();
00597   statFile << "<!-- Start Footer File -->\n";
00598   while (footFile >> in)
00599   {
00600     if(!in.compare("\\"))
00601       statFile << "\n";
00602     else
00603       statFile << in << " ";
00604   }
00605 
00606   statFile.flush();
00607   statFile.close();
00608   while(statFile.is_open() != 0){}
00609   unlockFile(itsStatusFile,fd,fl);
00610 }
00611 
00612 // #####################################################################
00613 void SimulationViewerNerdCam::writeChannelPage() const
00614 {
00615   std::ifstream headFile(itsStatusHeader.c_str(),std::ios::in);
00616   std::ifstream footFile(itsStatusFooter.c_str(),std::ios::in);
00617 
00618   int fd; struct flock fl;
00619   lockFile(itsChannelFile,fd,fl);
00620   std::ofstream statFile(itsChannelFile.c_str(),std::ios::out);
00621 
00622   std::string in;
00623   while (headFile >> in)
00624   {
00625     if(!in.compare("\\"))
00626       statFile << "\n";
00627     else
00628       statFile << in << " ";
00629   }
00630   statFile.flush();
00631   statFile << "\n<!-- End Header File -->\n"
00632            << "<!--\n"
00633            << "Nerd Cam Daemon\n"
00634            << "T. Nathan Mundhenk and Laurent Itti\n"
00635            << "http://www.nerd-cam.com\n"
00636            << "-->\n"
00637            << "<a href=\"" << itsBaseURL  << "\">"
00638            << "<H1>"       << itsBaseName << "</a> "
00639            << "Detailed Channel Status</H1>\n"
00640            << "<H2>Mega Combo Saliency Image</H2>\n"
00641            << "<img border=0 width="
00642            << itsComboSizeX
00643            << " height="
00644            << itsComboSizeY
00645            << " src=\"mega.surprise.combo.png\" "
00646            << " alt=\"Mega Combo Saliency Map with all the topings "
00647            << "for your viewing pleasure\"><br>\n";
00648 
00649   statFile << "<H2>Current Saliency Map Statistics Per Channel</H2>\n"
00650            << "<table border=0 cellpadding=0 width=900>\n"
00651            << "<tr>\n"
00652            << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00653            << "\t\t<H2>Channel Type</H2>\n"
00654            << "\t</td>\n"
00655            << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00656            << "\t\t<H2>Maximum Saliency</H2>\n"
00657            << "\t</td>\n"
00658            << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00659            << "\t\t<H2>Minimum Saliency</H2>\n"
00660            << "\t</td>\n"
00661            << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00662            << "\t\t<H2>Average Saliency</H2>\n"
00663            << "\t</td>\n"
00664            << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00665            << "\t\t<H2>Saliency Peaks</H2>\n"
00666            << "\t</td>\n"
00667            << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00668            << "\t\t<H2>Saliency Peaks Sum</H2>\n"
00669            << "\t</td>\n"
00670            << "</tr>\n";
00671   statFile.flush();
00672 
00673   LFATAL("FIXME I should derive from SimulationViewerStd");
00674   /*
00675 
00676   const nub::ref<VisualCortex> vc = itsBrain->getVC();
00677   if (vc->hasSubChan("color"))
00678   {
00679     const Image<float> ftmp = vc->subChan("color")->getOutput();
00680     double peaksum;
00681     float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av);
00682     const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum);
00683     statFile << "<tr>\n"
00684              << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00685              << "\t\t<H2>Color Channel</H2>\n"
00686              << "\t</td>\n"
00687              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00688              << "\t\t<H3>" << ma      << "</H3>\n"
00689              << "\t</td>\n"
00690              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00691              << "\t\t<H3>" << mi      << "</H3>\n"
00692              << "\t</td>\n"
00693              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00694              << "\t\t<H3>" << av      << "</H3>\n"
00695              << "\t</td>\n"
00696              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00697              << "\t\t<H3>" << npeaks  << "</H3>\n"
00698              << "\t</td>\n"
00699              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00700              << "\t\t<H3>" << peaksum << "</H3>\n"
00701              << "\t</td>\n"
00702              << "</tr>\n";
00703   }
00704   statFile.flush();
00705   if (vc->hasSubChan("intensity"))
00706   {
00707     const Image<float> ftmp = vc->subChan("intensity")->getOutput();
00708     double peaksum;
00709     float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av);
00710     const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum);
00711     statFile << "<tr>\n"
00712              << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00713              << "\t\t<H2>Intensity Channel</H2>\n"
00714              << "\t</td>\n"
00715              << "\t<td width=\"150\">\n"
00716              << "\t\t<H3>" << ma      << "</H3>\n"
00717              << "\t</td>\n"
00718              << "\t<td width=\"150\">\n"
00719              << "\t\t<H3>" << mi      << "</H3>\n"
00720              << "\t</td>\n"
00721              << "\t<td width=\"150\">\n"
00722              << "\t\t<H3>" << av      << "</H3>\n"
00723              << "\t</td>\n"
00724              << "\t<td width=\"150\">\n"
00725              << "\t\t<H3>" << npeaks  << "</H3>\n"
00726              << "\t</td>\n"
00727              << "\t<td width=\"150\">\n"
00728              << "\t\t<H3>" << peaksum << "</H3>\n"
00729              << "\t</td>\n"
00730              << "</tr>\n";
00731 
00732   }
00733   statFile.flush();
00734   if (vc->hasSubChan("orientation"))
00735   {
00736     const Image<float> ftmp = vc->subChan("orientation")->getOutput();
00737     double peaksum;
00738     float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av);
00739     const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum);
00740     statFile << "<tr>\n"
00741              << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00742              << "\t\t<H2>Orientation Channel</H2>\n"
00743              << "\t</td>\n"
00744              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00745              << "\t\t<H3>" << ma      << "</H3>\n"
00746              << "\t</td>\n"
00747              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00748              << "\t\t<H3>" << mi      << "</H3>\n"
00749              << "\t</td>\n"
00750              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00751              << "\t\t<H3>" << av      << "</H3>\n"
00752              << "\t</td>\n"
00753              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00754              << "\t\t<H3>" << npeaks  << "</H3>\n"
00755              << "\t</td>\n"
00756              << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"
00757              << "\t\t<H3>" << peaksum << "</H3>\n"
00758              << "\t</td>\n"
00759              << "</tr>\n";
00760   }
00761   statFile.flush();
00762   if (vc->hasSubChan("flicker"))
00763   {
00764     const Image<float> ftmp = vc->subChan("flicker")->getOutput();
00765     double peaksum;
00766     float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av);
00767     const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum);
00768     statFile << "<tr>\n"
00769              << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00770              << "\t\t<H2>Flicker Channel</H2>\n"
00771              << "\t</td>\n"
00772              << "\t<td width=\"150\">\n"
00773              << "\t\t<H3>" << ma      << "</H3>\n"
00774              << "\t</td>\n"
00775              << "\t<td width=\"150\">\n"
00776              << "\t\t<H3>" << mi      << "</H3>\n"
00777              << "\t</td>\n"
00778              << "\t<td width=\"150\">\n"
00779              << "\t\t<H3>" << av      << "</H3>\n"
00780              << "\t</td>\n"
00781              << "\t<td width=\"150\">\n"
00782              << "\t\t<H3>" << npeaks  << "</H3>\n"
00783              << "\t</td>\n"
00784              << "\t<td width=\"150\">\n"
00785              << "\t\t<H3>" << peaksum << "</H3>\n"
00786              << "\t</td>\n"
00787              << "</tr>\n";
00788   }
00789   statFile.flush();
00790   if (vc->hasSubChan("motion"))
00791   {
00792     nub::soft_ref<MotionChannel> mc; dynCastWeakToFrom(mc, vc->subChan("motion"));
00793     if (mc.isInvalid())
00794     {
00795       nlog(" FATAL- In writing channel page Channel named 'motion' not a MotionChannel");
00796       LFATAL("Channel named 'motion' not a MotionChannel");
00797     }
00798     for(uint i = 0; i < mc->numChans(); i++)
00799     {
00800       Image<float> ftmp = mc->dirChan(i).getOutput();
00801       double peaksum;
00802       float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av);
00803       const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum);
00804       statFile << "<tr>\n"
00805                << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n"
00806                << "\t\t<H2>";
00807 
00808       if(i == 0)
00809         statFile << "MotionRight";
00810       else if(i == 1)
00811         statFile << "MotionDown";
00812       else if(i == 2)
00813         statFile << "MotionLeft";
00814       else if(i == 3)
00815         statFile << "MotionUp";
00816       else
00817         statFile << "Motion " << i;
00818 
00819       statFile << "</H2>\n"
00820                << "\t</td>\n";
00821 
00822       if(i%2 == 0)
00823         statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n";
00824       else
00825         statFile << "\t<td width=\"150\">\n";
00826 
00827       statFile << "\t\t<H3>" << ma      << "</H3>\n"
00828                << "\t</td>\n";
00829 
00830       if(i%2 == 0)
00831         statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n";
00832       else
00833         statFile << "\t<td width=\"150\">\n";
00834 
00835       statFile << "\t\t<H3>" << mi      << "</H3>\n"
00836                << "\t</td>\n";
00837 
00838       if(i%2 == 0)
00839         statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n";
00840       else
00841         statFile << "\t<td width=\"150\">\n";
00842 
00843       statFile << "\t\t<H3>" << av      << "</H3>\n"
00844                << "\t</td>\n";
00845 
00846       if(i%2 == 0)
00847         statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n";
00848       else
00849         statFile << "\t<td width=\"150\">\n";
00850 
00851       statFile << "\t\t<H3>" << npeaks  << "</H3>\n"
00852                << "\t</td>\n";
00853 
00854       if(i%2 == 0)
00855         statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n";
00856       else
00857         statFile << "\t<td width=\"150\">\n";
00858 
00859       statFile << "\t\t<H3>" << peaksum << "</H3>\n"
00860                << "\t</td>\n"
00861                << "</tr>\n";
00862     }
00863   }
00864   statFile.flush();
00865   */
00866 
00867   statFile << "</table>\n"
00868            << "<!-- Start Footer File -->\n";
00869   while (footFile >> in)
00870   {
00871     if(!in.compare("\\"))
00872       statFile << "\n";
00873     else
00874       statFile << in << " ";
00875   }
00876 
00877   statFile.flush();
00878   statFile.close();
00879   while(statFile.is_open() != 0){}
00880   unlockFile(itsChannelFile,fd,fl);
00881 }
00882 
00883 // #####################################################################
00884 void SimulationViewerNerdCam::drawTime(Image<PixRGB<byte> >& image) const
00885 {
00886   char txt[20]; sprintf(txt, " %dms ", int(itsCurrTime.msecs() + 0.4999));
00887   writeText(image, Point2D<int>(0, 0), txt);
00888 }
00889 
00890 // #####################################################################
00891 void SimulationViewerNerdCam::lockFile(const std::string fileName,
00892                                        int &fd,
00893                                        struct flock &fl) const
00894 {
00895   // lock file
00896   fd = open(fileName.c_str(), O_RDWR);
00897   if (fd < 0)
00898   {
00899         LINFO("lockFile: Open failure on file %s",fileName.c_str());
00900   }
00901   else
00902   {
00903     fl.l_type   = F_WRLCK;
00904     fl.l_whence = SEEK_SET;
00905     fl.l_start  = 0;
00906     fl.l_len    = 0;
00907     if (fcntl(fd, F_SETLK, &fl) == -1)
00908     {
00909       if (errno == EACCES || errno == EAGAIN)
00910         LINFO("'%s' Already locked by another process",fileName.c_str());
00911       else if(errno == EBADF)
00912         LINFO("'%s' not a valid open file descriptor",fileName.c_str());
00913       else if(errno == EINVAL)
00914         LINFO("'%s In a locking operation, fildes refers to a file with a type that does not support locking, or the struct flock pointed to by the third argument has an incorrect form",fileName.c_str());
00915       else if(errno == EMFILE)
00916         LINFO("'%s' process has already reached its maximum number of file descriptors",fileName.c_str());
00917       else
00918       LINFO("Cannot lock file '%s' Error code '%d'",fileName.c_str(),errno);
00919     }
00920   }
00921 }
00922 
00923 // #####################################################################
00924 void SimulationViewerNerdCam::unlockFile(const std::string fileName,
00925                                          const int fd,
00926                                          struct flock &fl) const
00927 {
00928   // unlockfile
00929   fl.l_type   = F_UNLCK;
00930   fl.l_whence = SEEK_SET;
00931   fl.l_start  = 0;
00932   fl.l_len    = 0;
00933   if (fcntl(fd, F_SETLK, &fl) == -1)
00934   {
00935     LINFO("Cannot unlock file '%s'",fileName.c_str());
00936   }
00937   close(fd);
00938 }
00939 
00940 // #####################################################################
00941 void SimulationViewerNerdCam::nlog(const std::string logData) const
00942 {
00943   time_t rawtime; struct tm * timeinfo;
00944   time ( &rawtime ); timeinfo = localtime ( &rawtime );
00945 
00946   int fd; struct flock fl;
00947   lockFile(itsLogFile,fd,fl);
00948   std::ofstream logFile(itsLogFile.c_str(),std::ios::app);
00949 
00950   logFile << asctime (timeinfo)  << " - " << logData << "\n";
00951 
00952   logFile.close();
00953   unlockFile(itsLogFile,fd,fl);
00954 }
00955 
00956 // #####################################################################
00957 void SimulationViewerNerdCam::drawDateTime(Image<PixRGB<byte> >& image) const
00958 {
00959   time_t rawtime; struct tm * timeinfo;
00960   time ( &rawtime ); timeinfo = localtime ( &rawtime );
00961 
00962   writeText(image, Point2D<int>(0, 0), asctime (timeinfo));
00963 }
00964 
00965 // ######################################################################
00966 void SimulationViewerNerdCam::drawFOA()
00967 {
00968   if (itsCurrFOA.isValid() == false) return;
00969 
00970   // select a drawing color:
00971   PixRGB<byte> col(itsColorNormal.getVal());
00972   if (itsCurrFOA.boring) col -= itsColorBoring.getVal();
00973 
00974   // draw patch at current eye position:
00975   drawPatch(itsTraj, itsCurrFOA.p, itsFOApsiz.getVal(), col);
00976 
00977   // display focus of attention, possibly object-shaped:
00978   if (itsDisplayFOA.getVal())
00979     drawMaskOutline(itsTraj, itsCurrFOAmask, col, itsFOAthick.getVal(),
00980                     itsCurrFOA.p, itsMetrics->getFOAradius());
00981 }
00982 
00983 // ######################################################################
00984 void SimulationViewerNerdCam::linkFOAs()
00985 {
00986   if (itsCurrFOA.isValid() == false) return;
00987 
00988   const PixRGB<byte> col = itsColorLink.getVal();
00989   if (itsPrevFOA.isValid())
00990     {
00991       int d = int(itsPrevFOA.p.distance(itsCurrFOA.p));
00992       if (d > 0) drawArrow(itsTraj, itsPrevFOA.p, itsCurrFOA.p,
00993                            col, itsFOAlinkThick.getVal());
00994     }
00995 }
00996 
00997 // #####################################################################
00998 Image< PixRGB<byte> > SimulationViewerNerdCam::
00999 drawMegaCombo(SimEventQueue& q) const
01000 {
01001   LINFO("Drawing Mega Combo");
01002 
01003   const PixRGB<byte> bg(128, 128, 255);
01004   const short XWW = itsTraj.getWidth() * 2;
01005   const short XWH = itsTraj.getHeight() * 2;
01006   Image< PixRGB<byte> > xwi(XWW/2, XWH/2, ZEROS);
01007   Image< PixRGB<byte> > xwin(XWW, XWH, ZEROS);
01008 
01009   Rectangle r(Point2D<int>(0,0), Dims(XWW/2, XWH/2));
01010   inplaceEmbed(xwi, itsTraj, r, bg, true);
01011   inplacePaste(xwin, xwi, Point2D<int>(0, 0));
01012 
01013   // get the normalized SM:
01014   const Image<float> agm = getMap(q);
01015   Image< PixRGB<byte> > xwi2(XWW/2, XWH/2, NO_INIT);
01016 
01017   // get the non-normalized TRM (neutral is 1.0):
01018   Image<float> trm;
01019   if (SeC<SimEventTaskRelevanceMapOutput> e =
01020       q.check<SimEventTaskRelevanceMapOutput>(this, SEQ_ANY))
01021     trm = e->trm(1.0F);
01022   else LFATAL("Cannot find a TRM!");
01023 
01024   // useful range is 0.0 .. 3.0; let's show values smaller
01025   // than 1 as red and those larger that 1 as green:
01026   Image<byte> rr, gg, bb;
01027   Image<float> trmfac(trm);
01028   inplaceClamp(trmfac, 0.0F, 1.0F);
01029   trmfac *= -1.0F; trmfac += 1.0F;
01030   rr = trmfac * 255.0F; // the redder, the lower the relevance
01031   trmfac = trm;
01032   inplaceClamp(trmfac, 1.0F, 3.0F);
01033   trmfac -= 1.0F;
01034   gg = trmfac * 127.5F; // the greener, the higher the relevance
01035   bb = agm;  // in blue is the AGM
01036 
01037   // place the agm into our result image:
01038   Image<PixRGB<byte> > cbtmp = rescale(makeRGB(rr, gg, bb), XWW/2, XWH/2);
01039   inplaceEmbed(xwi2, cbtmp, r, PixRGB<byte>(192, 192, 192), true);
01040   writeText(xwi2, Point2D<int>(0,0), " Attention Map ");
01041   inplacePaste(xwin, xwi2, Point2D<int>(XWW/2, 0));
01042 
01043   // now do the conspicuity maps:
01044   r = Rectangle::tlbrI(0, 0, XWH/4 - 1, XWW/4 - 1);
01045   xwi2.resize(XWW/4, XWH/4);
01046 
01047   LFATAL("FIXME I should derive from SimulationViewerStd");
01048   /*
01049   const nub::ref<VisualCortex> vc = itsBrain->getVC();
01050 
01051   if (vc->hasSubChan("color")) {
01052     Image<float> ftmp = vc->subChan("color")->getOutput();
01053     ftmp = rescale(ftmp, XWW / 4, XWH / 4);
01054     inplaceNormalize(ftmp, 0.0f, 255.0f);
01055     Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Color ");
01056     inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01057     drawRect(xwi2, r, PixRGB<byte>(255), 1);
01058     inplacePaste(xwin, xwi2, Point2D<int>(0, XWH/2));
01059   }
01060 
01061   if (vc->hasSubChan("intensity")) {
01062     Image<float> ftmp = vc->subChan("intensity")->getOutput();
01063     ftmp = rescale(ftmp, XWW/4, XWH/4);
01064     inplaceNormalize(ftmp, 0.0f, 255.0f);
01065     Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Intensity ");
01066     inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01067     drawRect(xwi2, r, PixRGB<byte>(255), 1);
01068     inplacePaste(xwin, xwi2, Point2D<int>(XWW/4, XWH/2));
01069   }
01070 
01071   if (vc->hasSubChan("orientation")) {
01072     Image<float> ftmp = vc->subChan("orientation")->getOutput();
01073     ftmp = rescale(ftmp, XWW/4, XWH/4);
01074     inplaceNormalize(ftmp, 0.0f, 255.0f);
01075     Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Orientation ");
01076     inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01077     drawRect(xwi2, r, PixRGB<byte>(255), 1);
01078     inplacePaste(xwin, xwi2, Point2D<int>(XWW/2, XWH/2));
01079   }
01080 
01081   if (vc->hasSubChan("flicker")) {
01082     Image<float> ftmp = vc->subChan("flicker")->getOutput();
01083     ftmp = rescale(ftmp, XWW/4, XWH/4);
01084     inplaceNormalize(ftmp, 0.0f, 255.0f);
01085     Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Flicker ");
01086     inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01087     drawRect(xwi2, r, PixRGB<byte>(255), 1);
01088     inplacePaste(xwin, xwi2, Point2D<int>(XWW/4+XWW/2, XWH/2));
01089   }
01090 
01091   if (vc->hasSubChan("motion")) {
01092     nub::soft_ref<MotionChannel> mc; dynCastWeakToFrom(mc, vc->subChan("motion"));
01093     if (mc.isInvalid()) LFATAL("Channel named 'motion' not a MotionChannel");
01094     if (mc->numChans() == 4) {
01095       Image<float> ftmp = mc->dirChan(2).getOutput();
01096       ftmp = rescale(ftmp, XWW/4, XWH/4);
01097       inplaceNormalize(ftmp, 0.0f, 255.0f);
01098       Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionLeft ");
01099       inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01100       drawRect(xwi2, r, PixRGB<byte>(255), 1);
01101       inplacePaste(xwin, xwi2, Point2D<int>(0, XWH/4 + XWH/2));
01102 
01103       ftmp = mc->dirChan(1).getOutput();
01104       ftmp = rescale(ftmp, XWW/4, XWH/4);
01105       inplaceNormalize(ftmp, 0.0f, 255.0f);
01106       btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionDown ");
01107       inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01108       drawRect(xwi2, r, PixRGB<byte>(255), 1);
01109       inplacePaste(xwin, xwi2, Point2D<int>(XWW/4, XWH/4 + XWH/2));
01110 
01111       ftmp = mc->dirChan(3).getOutput();
01112       ftmp = rescale(ftmp, XWW/4, XWH/4);
01113       inplaceNormalize(ftmp, 0.0f, 255.0f);
01114       btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionUp ");
01115       inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01116       drawRect(xwi2, r, PixRGB<byte>(255), 1);
01117       inplacePaste(xwin, xwi2, Point2D<int>(XWW/2, XWH/4 + XWH/2));
01118 
01119       ftmp = mc->dirChan(0).getOutput();
01120       ftmp = rescale(ftmp, XWW/4, XWH/4);
01121       inplaceNormalize(ftmp, 0.0f, 255.0f);
01122       btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionRight ");
01123       inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true);
01124       drawRect(xwi2, r, PixRGB<byte>(255), 1);
01125       inplacePaste(xwin, xwi2, Point2D<int>(XWW/2 + XWW/4, XWH/4 + XWH/2));
01126     }
01127   }
01128   */
01129   return xwin;
01130 }
01131 
01132 // ######################################################################
01133 void SimulationViewerNerdCam::drawMaskOutline(Image< PixRGB<byte> >& traj,
01134                                               const Image<byte> mask,
01135                                               const PixRGB<byte>& col,
01136                                               const int thick,
01137                                               const Point2D<int>& pos,
01138                                               const int radius) const
01139 {
01140   if (traj.initialized() == false) return; // can't draw...
01141 
01142   // object-shaped drawing
01143   Image<byte> om(mask);
01144   inplaceLowThresh(om, byte(128)); // cut off fuzzy (interpolated) object boundaries
01145   om = contour2D(om);       // compute binary contour image
01146   const int w = traj.getWidth();
01147   const int h = traj.getHeight();
01148   Point2D<int> ppp;
01149   for (ppp.j = 0; ppp.j < h; ppp.j ++)
01150     for (ppp.i = 0; ppp.i < w; ppp.i ++)
01151       if (om.getVal(ppp.i, ppp.j))  // got a contour point -> draw here
01152         drawDisk(traj, ppp, thick, col);  // small disk for each point
01153   // OBSOLETE: drawCircle(traj, pos, radius, col, thick);
01154 }
01155 
01156 // ######################################################################
01157 /* So things look consistent in everyone's emacs... */
01158 /* Local Variables: */
01159 /* indent-tabs-mode: nil */
01160 /* End: */
Generated on Sun May 8 08:05:26 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3