BorderWatch.C

Go to the documentation of this file.
00001 /*!@file Apps/BorderWatch/BorderWatch.C Border watch */
00002 
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00004 // by the University of Southern California (USC) and the iLab at USC.  //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu>
00032 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Apps/BorderWatch/BorderWatch.C $
00033 // $Id: BorderWatch.C 13039 2010-03-23 02:06:32Z itti $
00034 
00035 #include "Component/JobServerConfigurator.H"
00036 #include "Component/ModelManager.H"
00037 #include "Component/GlobalOpts.H" // for OPT_UseRandom
00038 #include "Channels/ChannelOpts.H" // for OPT_LevelSpec
00039 #include "Media/FrameSeries.H"
00040 #include "Transport/FrameInfo.H"
00041 #include "Raster/GenericFrame.H"
00042 #include "Image/Image.H"
00043 #include "Image/ImageSet.H"
00044 #include "Image/DrawOps.H"
00045 #include "Image/ShapeOps.H"
00046 #include "Image/Layout.H"
00047 #include "GUI/ImageDisplayStream.H"
00048 #include "GUI/XWinManaged.H"
00049 #include "GUI/DebugWin.H"
00050 #include "GUI/SimpleMeter.H"
00051 #include "Neuro/EnvOpts.H" // for OPT_EnvLevelSpec, etc
00052 #include "Neuro/NeuroOpts.H" // for OPT_VisualCortexType
00053 #include "Apps/BorderWatch/ImageInfo.H"
00054 #include "Simulation/SimulationOpts.H"
00055 #include "Simulation/SimEventQueue.H"
00056 #include "Simulation/SimEventQueueConfigurator.H"
00057 #include "Util/Timer.H"
00058 #include <queue>
00059 #include <cmath>
00060 #include <cstdio>
00061 #include <fstream>
00062 
00063 const ModelOptionCateg MOC_BORDERWATCH = {
00064   MOC_SORTPRI_3, "BorderWatch-Related Options" };
00065 
00066 static const ModelOptionDef OPT_ShowDebugWin =
00067   { MODOPT_FLAG, "ShowDebugWin", &MOC_BORDERWATCH, OPTEXP_CORE,
00068     "Whether to show the input image, the saliency maps, and the beliefs. "
00069     "This is used for debugging and setting the thresholds. ",
00070     "show-debug-win", '\0', "", "false" };
00071 
00072 static const ModelOptionDef OPT_ShowThumbs =
00073   { MODOPT_FLAG, "ShowThumbs", &MOC_BORDERWATCH, OPTEXP_CORE,
00074     "Show thumbnails of the most recent frames that had surprise above threshold",
00075     "show-thumbs", '\0', "", "false" };
00076 
00077 static const ModelOptionDef OPT_Threshold =
00078   { MODOPT_ARG(float), "Threshold", &MOC_BORDERWATCH, OPTEXP_CORE,
00079     "The threshold level at which to save images to disk. ",
00080     "threshold", '\0', "<float>", "3.5e-10" };
00081 
00082 static const ModelOptionDef OPT_ImgQLen =
00083   { MODOPT_ARG(uint), "ImgQLen", &MOC_BORDERWATCH, OPTEXP_CORE,
00084     "Length of the queue of images for movie context, in frames",
00085     "imgqlen", '\0', "<uint>", "50" };
00086 
00087 const ModelOptionDef OPT_OutFname =
00088   { MODOPT_ARG_STRING, "OutFname", &MOC_BORDERWATCH, OPTEXP_CORE,
00089     "File name for text output data (or empty to not save output data)",
00090     "out-fname", '\0', "<file>", "" };
00091 
00092 // ######################################################################
00093 void displayOutput(const Image<PixRGB<byte> >& img, nub::ref<OutputFrameSeries> ofs, bool showThumbs)
00094 {
00095   static const uint nx = 15, ny = 12; // hardcoded for 30in display
00096   static ImageSet<PixRGB<byte> > thumbs(nx*ny, Dims(img.getWidth()/2, img.getHeight()/2), ZEROS);
00097 
00098   // do we want to show thumbnail displays?
00099   if (showThumbs) {
00100     thumbs.push_back(quickLocalAvg2x2(img)); while(thumbs.size() > nx*ny) thumbs.pop_front();
00101     Layout<PixRGB<byte> > t = arrcat(thumbs, nx);
00102     ofs->writeRgbLayout(t, "Thumbnails", FrameInfo("Thumbnails", SRC_POS));
00103   }
00104 
00105   // display the full-resolution image:
00106   ofs->writeRGB(img, "Output", FrameInfo("Output", SRC_POS));
00107   ofs->updateNext();
00108 }
00109 
00110 // ######################################################################
00111 int main(const int argc, const char **argv)
00112 {
00113   MYLOGVERB = LOG_INFO;
00114   ModelManager mgr("Border Watch");
00115 
00116   nub::ref<JobServerConfigurator> jsc(new JobServerConfigurator(mgr));
00117   mgr.addSubComponent(jsc);
00118 
00119   nub::ref<SimEventQueueConfigurator> seqc(new SimEventQueueConfigurator(mgr));
00120   mgr.addSubComponent(seqc);
00121 
00122   nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(mgr));
00123   mgr.addSubComponent(ofs);
00124 
00125   nub::ref<InputFrameSeries> ifs(new InputFrameSeries(mgr));
00126   mgr.addSubComponent(ifs);
00127 
00128   nub::ref<ImageInfo> imageInfo(new ImageInfo(mgr));
00129   mgr.addSubComponent(imageInfo);
00130 
00131   OModelParam<bool> optShowDebugWin(&OPT_ShowDebugWin, &mgr);
00132   OModelParam<bool> optShowThumbs(&OPT_ShowThumbs, &mgr);
00133   OModelParam<float> optThreshold(&OPT_Threshold, &mgr);
00134   OModelParam<uint> optQLen(&OPT_ImgQLen, &mgr);
00135   OModelParam<std::string> optOutFname(&OPT_OutFname, &mgr);
00136 
00137   mgr.exportOptions(MC_RECURSE);
00138   mgr.setOptionValString(&OPT_SimulationTimeStep, "30ms"); // avoid feeding inputs too fast
00139   mgr.setOptionValString(&OPT_LevelSpec, "1,3,3,4,4"); // use higher saliency resolution than usual
00140   mgr.setOptionValString(&OPT_VisualCortexType, "Env"); // use envision
00141   mgr.setOptionValString(&OPT_EvcMultithreaded, "true"); // use envision multi-threaded
00142   mgr.setOptionValString(&OPT_EnvLevelSpec, "1,3,3,4,4"); // use higher saliency resolution than usual
00143   mgr.setOptionValString(&OPT_UseRandom, "false"); // enough noise in the videos, no need to add more
00144 
00145   if (mgr.parseCommandLine(argc, argv, "", 0, 0) == false)
00146     { LFATAL("This program takes no non-option command-line argument; try --help"); return 1; }
00147 
00148   nub::ref<SimEventQueue> seq = seqc->getQ();
00149 
00150   // open output file, if any:
00151   std::ofstream *outFile = 0;
00152   if (optOutFname.getVal().empty() == false)
00153     {
00154       outFile = new std::ofstream(optOutFname.getVal().c_str());
00155       if (outFile->is_open() == false)
00156         LFATAL("Cannot open '%s' for writing", optOutFname.getVal().c_str());
00157     }
00158 
00159   // get started:
00160   mgr.start();
00161   MYLOGVERB = LOG_CRIT; // get less verbose...
00162 
00163   std::queue<Image<PixRGB<byte> > > imgQueue;
00164   SimStatus status = SIM_CONTINUE;
00165   Timer tim;
00166 
00167   // main loop:
00168   while(status == SIM_CONTINUE) {
00169     ifs->updateNext();
00170 
00171     // grab the images:
00172     GenericFrame input = ifs->readFrame(); if (!input.initialized()) break;
00173     Image<PixRGB<byte> > img = input.asRgb();
00174 
00175     // process the image and get the results:
00176     ImageInfo::ImageStats stats = imageInfo->update(seq, img, ifs->frame());
00177 
00178     float mi, ma;
00179     Image<float> smapf = stats.smap; inplaceNormalize(smapf, 0.0F, 255.0F, mi, ma);
00180     Image<byte> smap = smapf; smap = rescaleNI(smap, img.getDims());
00181 
00182     // time-stamp the image:
00183     char msg[255]; time_t rawtime; time(&rawtime);
00184     struct tm *timeinfo; timeinfo = localtime(&rawtime);
00185     sprintf(msg, " %s- S=%g %d", asctime(timeinfo), stats.score, ifs->frame());
00186     writeText(img, Point2D<int>(0,0), msg, PixRGB<byte>(255,0,0), PixRGB<byte>(0), SimpleFont::FIXED(6), true);
00187     sprintf(msg, " Saliency [%.4g .. %.4g] %d ", mi, ma, ifs->frame());
00188     writeText(smap, Point2D<int>(0,0), msg, byte(255), byte(0), SimpleFont::FIXED(6));
00189 
00190     // mark most salient point:
00191     const Point2D<int> sp = stats.salpoint * img.getWidth() / smapf.getWidth();
00192     if (stats.score > optThreshold.getVal()) drawCircle(img, sp, 15, PixRGB<byte>(255,255,0), 2);
00193     else drawCircle(img, sp, 5, PixRGB<byte>(0,128,0), 1);
00194 
00195     // push the image into our context queue:
00196     imgQueue.push(img);
00197     if (imgQueue.size() > optQLen.getVal()) imgQueue.pop();
00198 
00199     // show a debug window with saliency maps and such?
00200     if (optShowDebugWin.getVal())
00201       {
00202         if (stats.belief1.initialized() && stats.belief2.initialized()) {
00203           Image<float> b1f = stats.belief1; inplaceNormalize(b1f, 0.0F, 255.0F, mi, ma);
00204           Image<byte> b1 = b1f; b1 = rescaleNI(b1, img.getDims());
00205           sprintf(msg, " Beliefs 1 [%.4g .. %.4g] ", mi, ma);
00206           writeText(b1, Point2D<int>(0,0), msg, byte(255), byte(0), SimpleFont::FIXED(6));
00207           drawLine(b1, Point2D<int>(0,0), Point2D<int>(0, b1.getHeight()-1), byte(255));
00208 
00209           Image<float> b2f = stats.belief2; inplaceNormalize(b2f, 0.0F, 255.0F, mi, ma);
00210           Image<byte> b2 = b2f; b2 = rescaleNI(b1, img.getDims());
00211           sprintf(msg, " Beliefs 2 [%.4g .. %.4g] ", mi, ma);
00212           writeText(b2, Point2D<int>(0,0), msg, byte(255), byte(0), SimpleFont::FIXED(6));
00213           drawLine(b2, Point2D<int>(0,0), Point2D<int>(0, b2.getHeight()-1), byte(255));
00214 
00215           Layout<byte> smapDisp;
00216           smapDisp = hcat(hcat(smap, b1), b2);
00217           ofs->writeGrayLayout(smapDisp, "Smap", FrameInfo("Smap", SRC_POS));
00218         } else ofs->writeGray(smap, "Smap", FrameInfo("Smap", SRC_POS));
00219 
00220         const MeterInfo infos[] = {
00221           { "", stats.score, optThreshold.getVal()*3, optThreshold.getVal(), PixRGB<byte>(0, 255, 0) }
00222         };
00223         Image<PixRGB<byte> > meterImg =
00224           drawMeters(&infos[0], sizeof(infos) / sizeof(infos[0]), 1, Dims(img.getWidth(),20));
00225 
00226         Layout<PixRGB<byte> > inputDisp;
00227         inputDisp = vcat(img, meterImg);
00228         ofs->writeRgbLayout(inputDisp, "Input", FrameInfo("Input", SRC_POS));
00229       }
00230 
00231     if (stats.score > optThreshold.getVal())
00232       {
00233         if (imgQueue.size() == optQLen.getVal()) // buffer is full, place a title
00234           {
00235             Image<PixRGB<byte> > title = imgQueue.back();
00236 
00237             sprintf(msg, "Date: %s                   ", asctime(timeinfo));
00238             writeText(title, Point2D<int>(0,title.getHeight()-40), msg, PixRGB<byte>(255), PixRGB<byte>(0));
00239             sprintf(msg, "Surprise: %e                              ", stats.score);
00240             writeText(title, Point2D<int>(0,title.getHeight()-20), msg, PixRGB<byte>(255), PixRGB<byte>(0));
00241 
00242             for (int i = 0; i < 3; ++i) displayOutput(title, ofs, optShowThumbs.getVal());
00243           }
00244 
00245         while(!imgQueue.empty())
00246           {
00247             Image<PixRGB<byte> > tImg = imgQueue.front(); imgQueue.pop();
00248             displayOutput(tImg, ofs, optShowThumbs.getVal());
00249           }
00250       }
00251 
00252     // print framerate:
00253     if (ifs->frame() > 0 && (ifs->frame() % 100) == 0) {
00254       printf("Frame %06d - %.2ffps\n", ifs->frame(), 100.0 / tim.getSecs());
00255       tim.reset();
00256     }
00257 
00258     // save text output if desired, for later use:
00259     if (outFile)
00260       (*outFile)<<sformat("of=%i if=%i score=%e x=%d y=%d sal=%e ener=%e uniq=%e entr=%e rand=%e kls=%e msds=%e %s",
00261                           ofs->frame(), ifs->frame(), stats.score, sp.i, sp.j, stats.saliency, stats.energy,
00262                           stats.uniqueness, stats.entropy, stats.rand, stats.KLsurprise, stats.MSDsurprise,
00263                           asctime(timeinfo));
00264 
00265     // Evolve for one time step and switch to the next one:
00266     status = seq->evolve();
00267   }
00268 
00269   LINFO("Simulation terminated.");
00270   mgr.stop();
00271   if (outFile) { outFile->close(); delete outFile; }
00272 
00273   return 0;
00274 }
00275 
00276 
Generated on Sun May 8 08:40:11 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3