ShapeEstimator.C

Go to the documentation of this file.
00001 /*!@file Neuro/ShapeEstimator.C Estimate the shape/size of an attended object */
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 //
00032 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/ShapeEstimator.C $
00034 // $Id: ShapeEstimator.C 14762 2011-05-03 01:13:16Z siagian $
00035 //
00036 
00037 #include "Neuro/ShapeEstimator.H"
00038 
00039 #include "Component/ModelOptionDef.H"
00040 #include "Component/GlobalOpts.H"
00041 #include "Channels/ChannelMaps.H"
00042 #include "Component/OptionManager.H"
00043 #include "Image/DrawOps.H"
00044 #include "Image/FilterOps.H"
00045 #include "Image/ImageSet.H"
00046 #include "Image/MathOps.H"
00047 #include "Image/MorphOps.H"     // for openImg()
00048 #include "Image/Pixels.H"
00049 #include "Image/Point2D.H"
00050 #include "Image/Transforms.H"
00051 #include "Neuro/NeuroOpts.H"
00052 #include "Neuro/NeuroSimEvents.H"
00053 #include "Neuro/VisualCortex.H"
00054 #include "Neuro/SpatialMetrics.H"
00055 #include "Simulation/SimEventQueue.H"
00056 #include "Transport/FrameInfo.H"
00057 #include "Transport/FrameOstream.H"
00058 #include "Util/Assert.H"
00059 #include "Util/log.H"
00060 #include "Util/sformat.H"
00061 #include "Util/TextLog.H"
00062 
00063 #include "Raster/Raster.H"
00064 #include "Image/ShapeOps.H"
00065 #include "Image/CutPaste.H"
00066 #include "Util/Timer.H"
00067 
00068 #define SIGMA 20
00069 #define CLAMP 0.4f
00070 
00071 const ModelOptionDef OPT_ShapeEstimatorUseLargeNeigh =
00072   { MODOPT_FLAG, "ShapeEstimatorUseLargeNeigh", &MOC_BRAIN, OPTEXP_CORE,
00073     "Use a larger 3x3 neighborhood to track down a local maximum across "
00074     "scales when true, otherwise use a 2x2 neighborhood.",
00075     "shape-estim-largeneigh", '\0', "", "true" };
00076 
00077 // ######################################################################
00078 ShapeEstimator::ShapeEstimator(OptionManager& mgr,
00079                                const std::string& descrName,
00080                                const std::string& tagName,
00081                                const nub::soft_ref<VisualCortex> vcx) :
00082   SimModule(mgr, descrName, tagName),
00083   SIMCALLBACK_INIT(SimEventWTAwinner),
00084   SIMCALLBACK_INIT(SimEventSaveOutput),
00085   itsMetrics(new SpatialMetrics(mgr)),
00086   itsLogFile(&OPT_TextLogFile, this),
00087   itsMode(&OPT_ShapeEstimatorMode, this),
00088   itsSmMethod(&OPT_ShapeEstimatorSmoothMethod, this),
00089   itsSaveObjMask(&OPT_BrainSaveObjMask, this), // Neuro/NeuroOpts.{H,C}
00090   itsUseLargeNeigh(&OPT_ShapeEstimatorUseLargeNeigh, this),
00091   structEl(), itsSmoothMask(), itsCumMask(),
00092   itsSalientRegionSegmenter(new SalientRegionSegmenter())
00093 {
00094   this->addSubComponent(itsMetrics);
00095 }
00096 
00097 
00098 // ######################################################################
00099 void ShapeEstimator::reset1()
00100 {
00101   // reset some stuff for ShapeEstimator
00102   itsSmoothMask.freeMem();
00103   itsCumMask.freeMem();
00104 
00105   // propagate to our base class:
00106   ModelComponent::reset1();
00107 }
00108 
00109 // ######################################################################
00110 void ShapeEstimator::onSimEventWTAwinner
00111 (SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e)
00112 {
00113   // nothing to do?
00114   if (itsMode.getVal() == SEMnone) return;
00115 
00116   // any new covert attention shift?
00117   const Point2D<int> winner = e->winner().p; // in input coordinates
00118 
00119   // in the following, we are going to try to find good values for
00120   // winmap (the winning map or submap), and winloc (location of
00121   // winner in winmap's coordinates):
00122   NamedImage<float> winmap; Point2D<int> winloc(-1, -1);
00123 
00124   // grab the latest retina image, just to know its dims:
00125   Dims indims;
00126   if (SeC<SimEventRetinaImage> ee = q.check<SimEventRetinaImage>(this, SEQ_ANY)) 
00127     indims = ee->frame().getDims();
00128   else 
00129     LFATAL("Oooops, we have a WTA winner "
00130            "but no retina image in the SimEventQueue");
00131 
00132   // invalidate any previous object mask:
00133   itsSmoothMask.freeMem();
00134 
00135   // grab all the VisualCortex maps:
00136   rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this));
00137   q.request(vcxm); // VisualCortex is now filling-in the maps...
00138   rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps();
00139 
00140   // in case we use MT features map
00141   // we have to have a MotionSpatioTemporalChannel 
00142   if(itsMode.getVal() == SEMMTfeatureMap)
00143     {
00144       getMotionShapeEstimatorMap(q,e);
00145       return;
00146     }
00147   // NOTE: THIS MAY NEED TO BE COMMENTED OUT
00148   getShapeEstimatorMap(q,e);
00149 
00150   // in case we use saliency map, just store the SM as the winning map:
00151   if (itsMode.getVal() == SEMsaliencyMap)
00152     {
00153       winmap = chm->getMap();
00154       locateLocalMax(winmap, winner, indims, winloc);
00155     }
00156   else
00157     {
00158       // loop over the channels:
00159       float mx = 0.0F; rutz::shared_ptr<ChannelMaps> chan;
00160 
00161       for (uint i = 0; i < chm->numSubchans(); ++i)
00162         {
00163           rutz::shared_ptr<ChannelMaps> ch = chm->subChanMaps(i);
00164           NamedImage<float> output = ch->getMap();
00165           if (output.initialized())
00166             {
00167               Point2D<int> w;
00168               const float val = locateLocalMax(output, winner, indims, w);
00169               LINFO("Examining: %s, val = %g", output.name().c_str(), val);
00170 
00171               // do we have a new max?
00172               if (val > mx) { winmap = output; mx = val; chan = ch; winloc = w; }
00173             }
00174         }
00175 
00176       // we did not find a max here? -> resort back to saliency map:
00177       if (mx == 0.0F)
00178         {
00179           winmap = chm->getMap();
00180           locateLocalMax(winmap, winner, indims, winloc);
00181         }
00182       else
00183         {
00184           // ok, we found a max in one of our channel conspicuity
00185           // maps.  If we are using the conspicuity map mode, we
00186           // are done. Otherwise, let's go one level further,
00187           // looking at individual feature maps:
00188 
00189           // NOTE: this code should be truly recursive, instead here
00190           // we are going to flatten the channel hierarchy...
00191 
00192           if (itsMode.getVal() != SEMconspicuityMap)
00193             {
00194               // loop over the submaps of the winning channel:
00195               mx = 0.0F; Point2D<int> winloc2(0, 0); NamedImage<float> winmap2;
00196               for (uint i = 0; i < chan->numSubmaps(); ++i)
00197                 {
00198                   NamedImage<float> submap = chan->getSubmap(i);
00199                   if (submap.initialized())
00200                     {
00201                       Point2D<int> w;
00202                       const float val = locateLocalMax(submap, winloc, winmap.getDims(), w);
00203                       LINFO("Examining: %s, val = %g", submap.name().c_str(), val);
00204 
00205                       // do we have a new max?
00206                       if (val > mx) { winmap2 = submap; mx = val; winloc2 = w; }
00207                     }
00208                 }
00209 
00210               // did not find a max here? then just keep our old
00211               // values for winmap, winloc, and winlabel (which
00212               // are at the conspicuity map level). Otherwise,
00213               // update to the feature map level:
00214               if (mx > 0.0F) { winmap = winmap2; winloc = winloc2; }
00215             }
00216         }
00217     }
00218   postShapeEstimatorMask(winmap, winloc, winner, indims, q);
00219 }
00220 
00221 
00222 // ######################################################################
00223 void ShapeEstimator::postShapeEstimatorMask
00224 (NamedImage<float> winmap, Point2D<int> winloc, 
00225  Point2D<int> winner, Dims indims, SimEventQueue& q)
00226 {
00227   // since we had a winner to start with, one of the detections
00228   // should have worked... So we have winmap, winlabel, and winloc
00229   // all ready to go:
00230   ASSERT(winmap.initialized());
00231 
00232   // Now compute the objectmask:
00233   Image<byte> objmask;
00234   Image<float> winmapnormalized = winmap;
00235   inplaceNormalize(winmapnormalized, 0.0F, 1.0F);
00236 
00237   // if we found a good seed point, use it to segment the
00238   // object. Otherwise, we failed, so let's just return a disk:
00239   const bool goodseed = (winmap.getVal(winloc) > 0.0F);
00240   if (goodseed)
00241     {
00242       LDEBUG("Segmenting object around (%d, %d) in %s.", 
00243              winner.i, winner.j, winmap.name().c_str());
00244       objmask = segmentObjectClean(winmapnormalized, winloc);
00245     }
00246   else
00247     {
00248       LDEBUG("Drawing disk object around (%d, %d) in %s.", 
00249              winner.i, winner.j, winmap.name().c_str());
00250       objmask.resize(winmap.getDims(), true);
00251       drawDisk(objmask, winloc, 
00252                (itsMetrics->getFOAradius() * objmask.getWidth()) / indims.w(), 
00253                byte(255));
00254     }
00255 
00256   // all right, compute the smooth mask:
00257   switch(itsSmMethod.getVal())
00258     {
00259     case SESMgaussian:
00260       {
00261         Image<float> temp = scaleBlock(objmask, indims);
00262         itsSmoothMask = convGauss<float>(temp, SIGMA, SIGMA, 5);
00263         inplaceNormalize(itsSmoothMask, 0.0F, 3.0F);
00264         inplaceClamp(itsSmoothMask, 0.0F, 1.0F);
00265         break;
00266       }
00267 
00268     case SESMchamfer:
00269       {
00270         if (structEl.initialized() == false)
00271           {
00272             //create the structuring element for the opening
00273             const int ss = 8;
00274             structEl = Image<byte>(ss+ss,ss+ss, ZEROS);
00275             drawDisk(structEl, Point2D<int>(ss,ss), ss, byte(1));
00276           }
00277 
00278         const byte cutoff = 100;
00279         Image<byte> temp = scaleBlock(objmask, indims);
00280         temp = chamfer34(openImg(temp, structEl), cutoff);
00281         itsSmoothMask = binaryReverse(Image<float>(temp), 255.0F);
00282         inplaceNormalize(itsSmoothMask, 0.0F, 1.0F);
00283         break;
00284       }
00285 
00286     case SESMnone:
00287       {
00288         itsSmoothMask = scaleBlock(objmask, indims) / 255.0F;
00289         break;
00290       }
00291 
00292     default: LFATAL("Unknown Smoothing Method");
00293     }
00294 
00295   // update the cumulative smooth mask:
00296   if (itsCumMask.initialized()) itsCumMask = takeMax(itsCumMask, itsSmoothMask);
00297   else itsCumMask = itsSmoothMask;
00298 
00299   // finally compute the IOR mask. Basically, we want to take the
00300   // dot product between the binary object mask and the winning
00301   // map, so that we will inhibit stronger the locations which are
00302   // more active. However, let's add some default level of
00303   // inhibition inside the whole object, so that every location
00304   // within the object gets suppressed at least some.  Also note
00305   // that we need to make sure the WTA winner will actually get
00306   // inhibited, so that attention can shift. Indeed, sometimes the
00307   // max of the saliency map (which is the WTAwinner) may not
00308   // belong to the object that has been segmented, e.g., from some
00309   // feature map; so we just force it into the objmask first.
00310   Image<byte> objmask2(objmask);
00311   objmask2.setVal((winner.i * objmask.getWidth()) / indims.w(),
00312                   (winner.j * objmask.getHeight()) / indims.h(),
00313                   byte(255));
00314   Image<byte> iormask = lowPass3(objmask2) * (winmapnormalized + 0.25F);
00315 
00316   // great, let's post an event with all our results:
00317   rutz::shared_ptr<SimEventShapeEstimatorOutput>
00318     e(new SimEventShapeEstimatorOutput(this, winmap, objmask, iormask, itsSmoothMask, itsCumMask,
00319                                        winmap.name(), goodseed));
00320 
00321 
00322 
00323 
00324  Raster::waitForKey();
00325  uint width  = itsSmoothMask.getWidth();
00326  uint height = itsSmoothMask.getHeight();
00327  uint scale  = 4; 
00328  if(itsWin.is_invalid())
00329    itsWin.reset(new XWinManaged(Dims(width*3,height*2), 0, 0, "ShapeEst"));
00330  itsWin->setDims(Dims(width*3, height*2));
00331 
00332  LINFO("%d %d", winmap.getWidth(), winmap.getHeight());
00333  LINFO("%d %d", objmask.getWidth(), objmask.getHeight());
00334  LINFO("%d %d", iormask.getWidth(), iormask.getHeight());
00335  LINFO("%d %d", itsSmoothMask.getWidth(), itsSmoothMask.getHeight());
00336  LINFO("%d %d", itsCumMask.getWidth(), itsCumMask.getHeight());
00337 
00338  Image<float> disp(width*3, height*2, NO_INIT);
00339 
00340  Image<float> dwinmap = zoomXY(winmap,scale);
00341  inplaceNormalize(dwinmap, 0.0F, 1.0F);
00342  inplacePaste(disp, dwinmap, Point2D<int>(0,0));
00343 
00344  Image<float> dobjmask = zoomXY(objmask,scale);
00345  inplaceNormalize(dobjmask, 0.0F, 1.0F);
00346  inplacePaste(disp, dobjmask, Point2D<int>(width,0));
00347 
00348  Image<float> diormask = zoomXY(iormask,scale);
00349  inplaceNormalize(diormask, 0.0F, 1.0F);
00350  inplacePaste(disp, diormask, Point2D<int>(2*width,0));
00351 
00352  Image<float> dsmmask = itsSmoothMask;
00353  inplaceNormalize(dsmmask, 0.0F, 1.0F);
00354  inplacePaste(disp, dsmmask, Point2D<int>(0,height));
00355 
00356  Image<float> dcummask = itsCumMask;
00357  inplaceNormalize(dcummask, 0.0F, 1.0F);
00358  inplacePaste(disp, dcummask, Point2D<int>(width, height));
00359 
00360  itsWin->drawImage(disp,0,0);
00361 
00362  Raster::waitForKey();
00363 
00364 
00365 
00366 
00367   q.post(e);
00368 
00369   // log it:
00370   const std::string msg =
00371     sformat("(%d,%d) %s %s", 
00372             winner.i, winner.j, winmap.name().c_str(), 
00373             goodseed ? "[Shape]" : "[Disk]");
00374 
00375   textLog(itsLogFile.getVal(), "ShapeEstimator", msg);
00376   LINFO("Shape estimated %s", msg.c_str());
00377 }
00378 
00379 // ######################################################################
00380 float ShapeEstimator::locateLocalMax(const Image<float>& submap,
00381                                      const Point2D<int>& winner,
00382                                      const Dims& fulldims,
00383                                      Point2D<int>& winloc,
00384                                      int mini, int maxi)
00385 {
00386   // Scale down the winner coordinates, from input image dims to the
00387   // dims of submap, rounding down:
00388   winloc.i = (winner.i * submap.getWidth()) / fulldims.w();
00389   winloc.j = (winner.j * submap.getHeight()) / fulldims.h();
00390 
00391   // Explore the local neighborhood. Note that here we are only
00392   // interested in positive values:
00393   float maxval = 0.0F; std::vector<Point2D<int> > surr; 
00394 
00395   if (itsUseLargeNeigh.getVal()) mini = -1;
00396 
00397   for (int j = mini; j <= maxi; ++j)
00398     for (int i = mini; i <= maxi; ++i)
00399       surr.push_back(winloc + Point2D<int>(i, j));
00400 
00401   for (uint i = 0; i < surr.size(); ++i)
00402     {
00403       surr[i].clampToDims(submap.getDims());
00404       const float val = submap.getVal(surr[i]);
00405       if (val > maxval) { winloc = surr[i]; maxval = val; }
00406     }
00407   return maxval;
00408 }
00409 
00410 // ######################################################################
00411 void ShapeEstimator::
00412 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00413 {
00414   if (itsSaveObjMask.getVal())
00415     {
00416       // get the OFS to save to, assuming sinfo is of type
00417       // SimModuleSaveInfo (will throw a fatal exception otherwise):
00418       nub::ref<FrameOstream> ofs = dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs;
00419 
00420       if (itsSmoothMask.initialized())
00421         {
00422           const Image<byte> om = itsSmoothMask * 255.0F;
00423           ofs->writeGray(om, "OBJ", FrameInfo("ShapeEstimator object mask", SRC_POS));
00424         }
00425       else
00426         {
00427           if (SeC<SimEventRetinaImage> ee = q.check<SimEventRetinaImage>(this, SEQ_ANY))
00428             ofs->writeGray(Image<byte>(ee->frame().getDims(), ZEROS), "OBJ",
00429                            FrameInfo("ShapeEstimator object mask", SRC_POS));
00430         }
00431     }
00432 }
00433 
00434 // ######################################################################
00435 void ShapeEstimator::getMotionShapeEstimatorMap
00436 (SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e)
00437 {
00438   // any new covert attention shift?
00439   const Point2D<int> winner = e->winner().p; // in input coordinates
00440   LINFO("SEMMTfeatureMap: winner: %d %d", winner.i, winner.j);
00441 
00442   // in the following, we are going to try to find good values for
00443   // winmap (the winning map or submap), and winloc (location of
00444   // winner in winmap's coordinates):
00445   NamedImage<float> winmap; Point2D<int> winloc(-1, -1);
00446 
00447   // grab the latest retina image, just to know its dims:
00448   Dims indims;
00449   if (SeC<SimEventRetinaImage> ee = q.check<SimEventRetinaImage>(this, SEQ_ANY)) 
00450     indims = ee->frame().getDims();
00451   else LFATAL("Oooops, we have a WTA winner but no retina image in the SimEventQueue");
00452 
00453   SeC<SimEventRetinaImage> ee = q.check<SimEventRetinaImage>(this, SEQ_ANY);
00454   Image<PixRGB<byte> > image = ee->frame().colorByte();
00455 
00456   //Raster::waitForKey();
00457   uint width  = image.getWidth();
00458   uint height = image.getHeight();
00459   //uint scale  = 16;
00460   if(itsWin.is_invalid())
00461     itsWin.reset(new XWinManaged(Dims(width*3,height*2), 0, 0, "ShapeEstObj"));
00462   itsWin->setDims(Dims(width*3, height*2));
00463 
00464   Image<PixRGB<byte> > disp = image;
00465   drawCross(disp, winner, PixRGB<byte>(255,0,0), 10, 2);
00466   itsWin->drawImage(disp,0,0);
00467   LINFO("Input Image: %d %d", image.getWidth(), image.getHeight());
00468   Raster::waitForKey();
00469 
00470   // invalidate any previous object mask:
00471   itsSmoothMask.freeMem();
00472 
00473   // grab all the VisualCortex maps:
00474   rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this));
00475   q.request(vcxm); // VisualCortex is now filling-in the maps...
00476   rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps();
00477 
00478 
00479   // Image<float> dwinmap = zoomXY(winmap,scale);
00480   // inplaceNormalize(dwinmap, 0.0F, 1.0F);
00481   // itsWin->drawImage(dwinmap,0,0);
00482   // LINFO("Saliency Map");
00483   // Raster::waitForKey();
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496   // loop over the channels:
00497   float mx = 0.0F; rutz::shared_ptr<ChannelMaps> chan;
00498   uint jmax = 0;
00499 
00500   // get the MotionSpatioTemporalChannel
00501   for (uint i = 0; i < chm->numSubchans(); ++i)
00502     {
00503       rutz::shared_ptr<ChannelMaps> ch = chm->subChanMaps(i);
00504       NamedImage<float> output = ch->getMap();
00505 
00506       // Image<float> doutput = zoomXY(output,16);
00507       // inplaceNormalize(doutput, 0.0F, 1.0F);
00508       // itsWin->drawImage(doutput,0,0);
00509       // LINFO("CMAP[%3d]: %s", i, output.name().c_str());
00510       // Raster::waitForKey(); 
00511 
00512       if(output.name().find(std::string("motionSpatioTemporal")) != 
00513          std::string::npos)
00514         {    
00515           // go through each sub channels
00516           uint nSubchans = ch->numSubchans();
00517           LINFO("num subchans: %d", nSubchans);
00518       
00519           int cDir = -1;
00520           for(uint j = 0; j < nSubchans; j++)
00521             {
00522               rutz::shared_ptr<ChannelMaps> sch = ch->subChanMaps(j);
00523               NamedImage<float> rawcsmap = sch->getRawCSmap(0);                        
00524 
00525               std::string rcsname = rawcsmap.name();
00526               int fupos = rcsname.find_first_of('_') +1;
00527               std::string rcsname2 = rcsname.substr(fupos);
00528               int supos = rcsname2.find_first_of('_')+ fupos;
00529               std::string number = rcsname.substr(fupos,supos-fupos).c_str();
00530               //LINFO("%s %s -> %s", rcsname.c_str(), rcsname2.c_str(), number.c_str());
00531               int dir = atoi(number.c_str());
00532               
00533               if(cDir < dir) 
00534                 {
00535                   cDir = dir;
00536 
00537                   Image<float> drawcsmap = zoomXY(rawcsmap, 4);
00538                   inplaceNormalize(drawcsmap, 0.0F, 1.0F);
00539                   itsWin->drawImage(drawcsmap, 0,0);
00540                   LINFO("RCSMAP[%3d][%3d]:[%d %d]:  %s", 
00541                         i,j, rawcsmap.getWidth(), rawcsmap.getHeight(),
00542                         rawcsmap.name().c_str());
00543                   Raster::waitForKey(); 
00544 
00545                   // check to see if it's a higher saliency value
00546                   if (output.initialized())
00547                     {
00548                       Point2D<int> w;
00549                       const float val = locateLocalMax(rawcsmap, winner, indims, w, -1, 1);
00550                       LINFO("Examining: %s, val = %g", rawcsmap.name().c_str(), val);
00551                       
00552                       // do we have a new max?
00553                       if (val > mx) 
00554                         {
00555                           LINFO("j: %d", j); jmax = j;
00556                           winmap = rawcsmap; mx = val; chan = ch; winloc = w; 
00557                         }
00558                     }
00559                 }
00560             }
00561         }
00562     }
00563 
00564   // we did not find a max here? -> resort back to saliency map:
00565   if (mx == 0.0F)
00566     {
00567       winmap = chm->getMap();
00568       locateLocalMax(winmap, winner, indims, winloc);
00569       LINFO("did not find a max in the map");
00570     }
00571 
00572   LINFO("jmax: %d mx: %f", jmax, mx);
00573   postShapeEstimatorMask(winmap, winloc, winner, indims, q);
00574 
00575   Raster::waitForKey();
00576 }
00577 
00578 // ######################################################################
00579 void ShapeEstimator::getShapeEstimatorMap
00580 (SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e)
00581 {
00582   Timer t(1000000); t.reset();
00583 
00584   // any new covert attention shift?
00585   const Point2D<int> winner = e->winner().p; // in input coordinates
00586 
00587   // in the following, we are going to try to find good values for
00588   // winmap (the winning map or submap), and winloc (location of
00589   // winner in winmap's coordinates):
00590   NamedImage<float> winmap; Point2D<int> winloc(-1, -1);
00591 
00592   // grab the latest retina image, just to know its dims:
00593   Dims indims;
00594   if (SeC<SimEventRetinaImage> ee = q.check<SimEventRetinaImage>(this, SEQ_ANY)) 
00595     indims = ee->frame().getDims();
00596   else LFATAL("Oooops, we have a WTA winner but no retina image in the SimEventQueue");
00597 
00598   SeC<SimEventRetinaImage> ee = q.check<SimEventRetinaImage>(this, SEQ_ANY);
00599   Image<PixRGB<byte> > image = ee->frame().colorByte();
00600 
00601   uint width  = image.getWidth();
00602   uint height = image.getHeight();
00603   uint scale  = 16;
00604   if(itsWin.is_invalid())
00605     itsWin.reset(new XWinManaged(Dims(width*3,height*2), 0, 0, "ShapeEstObj"));
00606   itsWin->setDims(Dims(width*3, height*2));
00607 
00608   Image<PixRGB<byte> > disp = image;
00609   drawCross(disp, winner, PixRGB<byte>(255,0,0), 10, 1);
00610   drawRect(disp, 
00611            Rectangle(Point2D<int>(winner.i-8, winner.j-8), Dims(16, 16)), 
00612            PixRGB<byte>(255,255,0));
00613 
00614   itsWin->drawImage(disp,0,0);
00615   LINFO("winner: %d %d in [%3d %3d]", 
00616         winner.i, winner.j, image.getWidth(), image.getHeight());
00617 
00618   // invalidate any previous object mask:
00619   itsSmoothMask.freeMem();
00620 
00621   // grab all the VisualCortex maps:
00622   rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this));
00623   q.request(vcxm); // VisualCortex is now filling-in the maps...
00624   rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps();
00625 
00626   winmap = chm->getMap();
00627   locateLocalMax(winmap, winner, indims, winloc);  
00628 
00629   Image<float> dwinmap = zoomXY(winmap,scale);
00630   inplaceNormalize(dwinmap, 0.0F, 1.0F);
00631   itsWin->drawImage(dwinmap,0,0);
00632   //inplacePaste(disp, dwinmap, Point2D<int>(0,0));
00633 
00634   // loop over the channels:
00635   rutz::shared_ptr<ChannelMaps> chan;
00636 
00637   // // go through each channel
00638   // for (uint i = 0; i < chm->numSubchans(); ++i)
00639   //   {
00640   //     rutz::shared_ptr<ChannelMaps> ch = chm->subChanMaps(i);
00641   //     NamedImage<float> output = ch->getMap();
00642 
00643   //     Image<float> doutput = zoomXY(output,scale);
00644   //     inplaceNormalize(doutput, 0.0F, 1.0F);
00645   //     itsWin->drawImage(doutput,0,0);
00646   //     LINFO("CMAP[%3d]: %s", i, output.name().c_str());
00647 
00648   //     Raster::waitForKey(); 
00649 
00650   //     // if (output.initialized())
00651   //     //   {
00652   //     //     Point2D<int> w;
00653   //     //     const float val = locateLocalMax(output, winner, indims, w);
00654   //     //     LINFO("Examining: %s, val = %g", output.name().c_str(), val);          
00655   //     //   }
00656     
00657   //     // go through each sub channels
00658   //     uint nSubchans = ch->numSubchans();
00659   //     LINFO("num subchans: %d", nSubchans);
00660       
00661   //     for(uint j = 0; j < nSubchans; j++)
00662   //       {
00663   //         rutz::shared_ptr<ChannelMaps> sch = ch->subChanMaps(j);
00664             
00665   //         // // loop over the submaps of the winning channel:
00666   //         // //float mx2 = 0.0F; Point2D<int> winloc2(0, 0); NamedImage<float> winmap2;
00667   //         // for (uint k = 0; k < sch->numSubmaps(); ++k)
00668   //         //   {
00669   //         //     //NamedImage<float> submap = sch->getRawCSmap(k);
00670   //         //     NamedImage<float> submap = sch->getSubmap(k);
00671   //         //     // if (submap2.initialized())
00672   //         //     //   {
00673   //         //     //     Point2D<int> w2;
00674   //         //     //     const float val2 = locateLocalMax(submap2, winloc2, winmap.getDims(), w2);
00675   //         //     //     LINFO("Examining: %s, val = %g", submap2.name().c_str(), val2);              
00676   //         //     //   }
00677               
00678   //         //     Image<float> dsubmap = zoomXY(submap, scale);
00679   //         //     inplaceNormalize(dsubmap, 0.0F, 1.0F);
00680   //         //     itsWin->drawImage(dsubmap, 0,0);
00681   //         //     LINFO("FMAP[%3d][%3d][%3d]:[%d %d]:  %s", 
00682   //         //           i,j,k, submap.getWidth(), submap.getHeight(),
00683   //         //           submap.name().c_str());
00684   //         //     Raster::waitForKey(); 
00685   //         //   }
00686 
00687   //         uint scale2 = 4;
00688   //         NamedImage<float> rawcsmap = sch->getRawCSmap(0);              
00689   //         Image<float> drawcsmap = zoomXY(rawcsmap, scale2);
00690   //         inplaceNormalize(drawcsmap, 0.0F, 1.0F);
00691   //         itsWin->drawImage(drawcsmap, 0,0);
00692   //         LINFO("RCSMAP[%3d][%3d]:[%d %d]:  %s", 
00693   //               i,j, rawcsmap.getWidth(), rawcsmap.getHeight(),
00694   //               rawcsmap.name().c_str());
00695   //         Raster::waitForKey(); 
00696           
00697   //         // get all the features:
00698   //         ImageSet<float> pyr = sch->getPyramid();
00699   //         LINFO("Rsize: %d", pyr.size());
00700   //         for(uint k = 0; k < pyr.size(); k++)
00701   //           {
00702   //             Image<float> rmap = pyr[k];
00703   //             uint nscale = uint(pow(2.0,k));
00704   //             Image<float> drmap = zoomXY(rmap,nscale);
00705   //             inplaceNormalize(drmap, 0.0F, 1.0F);
00706   //             itsWin->drawImage(drmap,0,0);
00707   //             LINFO("RMAP[%3d][%3d][%3d]: (%3d)-> %d %d --> %d %d", i,j,k, nscale, 
00708   //                   rmap.getWidth(), rmap.getHeight(),
00709   //                   drmap.getWidth(), drmap.getHeight());
00710   //             Raster::waitForKey();                     
00711   //           }
00712   //       }
00713   //   }
00714 
00715   // since we had a winner to start with, one of the detections
00716   // should have worked... So we have winmap, winlabel, and winloc
00717   // all ready to go:
00718   ASSERT(winmap.initialized());
00719 
00720   // ===============================================================
00721   // ===============================================================
00722   // Have: most salient point
00723   //       winning channel, feature map, etc.
00724 
00725   // ===============================================================
00726   // start at the point:
00727   // list all the possible reason why this point is selected
00728   // maybe different strategy for different channels
00729   // intensity/color vs. orientation channel
00730   //       ---> learning ????
00731 
00732   // localize the location of saliency point better: goodseed
00733 
00734   // ===============================================================
00735   // grow in hierarachical manner
00736   // center surround manner (grow both center & surround region)
00737 
00738   // consider both:
00739   //    contour: ---> take boundary evidence into account
00740   //    region uniformity --> keep growing histogram
00741   //                      --> may have GMM (Gaussian Mixture Model) 
00742 
00743   //    how about motion!!!
00744 
00745   // try the PAMI 2011 center surround
00746 
00747   // GROWING SHOULD BE FAST: 100 - 200 ms target
00748 
00749   // does this spread too much ---> IOR but no Object
00750   // check out how that affect the 
00751 
00752   // what scale to spread???
00753 
00754   if(!itsSalientRegionSegmenter->getImage().initialized())
00755     itsSalientRegionSegmenter->setImage(image);
00756 
00757   Image<float> segObjImage = 
00758     itsSalientRegionSegmenter->getSalientRegion(winner);
00759   
00760 
00761 
00762   // ===============================================================
00763   // ===============================================================
00764 
00765   // LINFO("%d %d", winmap.getWidth(), winmap.getHeight());
00766   // LINFO("%d %d", objmask.getWidth(), objmask.getHeight());
00767   // LINFO("%d %d", iormask.getWidth(), iormask.getHeight());
00768   // LINFO("%d %d", itsSmoothMask.getWidth(), itsSmoothMask.getHeight());
00769   // LINFO("%d %d", itsCumMask.getWidth(), itsCumMask.getHeight());
00770 
00771   // Image<float> disp(width*3, height*2, NO_INIT);
00772 
00773   // Image<float> dwinmap = zoomXY(winmap,scale);
00774   // inplaceNormalize(dwinmap, 0.0F, 1.0F);
00775   // inplacePaste(disp, dwinmap, Point2D<int>(0,0));
00776 
00777   // Image<float> dobjmask = zoomXY(objmask,scale);
00778   // inplaceNormalize(dobjmask, 0.0F, 1.0F);
00779   // inplacePaste(disp, dobjmask, Point2D<int>(width,0));
00780 
00781   // Image<float> diormask = zoomXY(iormask,scale);
00782   // inplaceNormalize(diormask, 0.0F, 1.0F);
00783   // inplacePaste(disp, diormask, Point2D<int>(2*width,0));
00784 
00785   // Image<float> dsmmask = itsSmoothMask;
00786   // inplaceNormalize(dsmmask, 0.0F, 1.0F);
00787   // inplacePaste(disp, dsmmask, Point2D<int>(0,height));
00788 
00789   // Image<float> dcummask = itsCumMask;
00790   // inplaceNormalize(dcummask, 0.0F, 1.0F);
00791   // inplacePaste(disp, dcummask, Point2D<int>(width, height));
00792 
00793   // itsWin->drawImage(disp,0,0);
00794   
00795   // Raster::waitForKey();
00796 
00797 
00798 
00799 
00800 
00801   // LINFO("%d %d", winmap.getWidth(), winmap.getHeight());
00802   // LINFO("%d %d", objmask.getWidth(), objmask.getHeight());
00803   // LINFO("%d %d", iormask.getWidth(), iormask.getHeight());
00804   // LINFO("%d %d", itsSmoothMask.getWidth(), itsSmoothMask.getHeight());
00805   // LINFO("%d %d", itsCumMask.getWidth(), itsCumMask.getHeight());
00806 
00807   // winning map : 1/16x1/16 --> probably has no more use
00808   // objmask     : 1/16x1/16 --> coarse version
00809   // iormask     : 1/16x1/16 -->     
00810   // its smooth mask     : org size
00811   // its cumulative mask : org size
00812 
00813   // difference between objmask & iormask is that
00814   // if we realize that this is a background,
00815   // we have small (or none) obj mask 
00816   // but large iormask
00817   
00818   // in prev implementation is performing lowpass3
00819 
00820   // great, let's post an event with all our results:
00821   // rutz::shared_ptr<SimEventShapeEstimatorOutput>
00822   //   e(new SimEventShapeEstimatorOutput
00823   //     (this, winmap, objmask, iormask, itsSmoothMask, itsCumMask,
00824   //                                      winmap.name(), goodseed));
00825 
00826 
00827 
00828   uint64 t2 = t.get();
00829   LINFO("time: %f", t2/1000.0);
00830 }
00831 
00832 // ######################################################################
00833 /* So things look consistent in everyone's emacs... */
00834 /* Local Variables: */
00835 /* indent-tabs-mode: nil */
00836 /* End: */
Generated on Sun May 8 08:05:25 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3