SaliencyMT.C

00001 /*!@file /Robots/Beobot2/LaneFollowing/RG_Lane/SaliencyMT.C 
00002  * A class for quick-and-dirty saliency mapping */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Zack Gossman <gossman@usc.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/Beobot2/LaneFollowing/RG_Lane/SaliencyMT.C $
00036 // $Id: SaliencyMT.C 8095 2007-03-12 01:14:23Z kai $
00037 //
00038 
00039 #include "Robots/Beobot2/LaneFollowing/RG_Lane/SaliencyMT.H"
00040 #include "Demo/DemoOpts.H"
00041 
00042 // ######################################################################
00043 // ##### Global options:
00044 // ######################################################################
00045 
00046 #define sml        2
00047 #define delta_min  3
00048 #define delta_max  4
00049 #define level_min  0
00050 #define level_max  2
00051 #define maxdepth   (level_max + delta_max + 1)
00052 #define normtyp    (VCXNORM_MAXNORM)
00053 
00054 // relative feature weights:
00055 #define IWEIGHT 0.7
00056 #define CWEIGHT 1.0
00057 #define OWEIGHT 1.0
00058 #define FWEIGHT 1.0
00059 #define SWEIGHT 0.7
00060 
00061 // image size vars
00062 #define IMAGEWIDTH 320 
00063 #define IMAGEHEIGHT 240
00064 
00065 // action definitions CHANGE TO ENUM? FIX?
00066 #define RETINA     1
00067 #define WINNER     2
00068 #define LUMINANCE  3
00069 #define REDGREEN   4
00070 #define BLUEYELLOW 5
00071 #define ORI0       6
00072 #define ORI45      7
00073 #define ORI90      8
00074 #define ORI135     9
00075 #define CMAP       10
00076 #define FLICKER    11
00077 #define INTENSITY  12
00078 #define SKINHUE    13
00079 
00080 #define numthreads 1
00081 
00082 // ######################################################################
00083 void *SaliencyMT_CMAP(void *c)
00084 {
00085   SaliencyMT *d = (SaliencyMT *)c;
00086   d->computeCMAP();
00087   return NULL;
00088 }
00089 
00090 // ######################################################################
00091 SaliencyMT::SaliencyMT(OptionManager& mgr,
00092            const std::string& descrName,
00093            const std::string& tagName):
00094   ModelComponent(mgr, descrName, tagName),
00095   itsNumThreads(&OPT_SMTnumThreads, this)  // see Demo/DemoOpts.{H,C}
00096 
00097 {
00098 
00099   numWorkers = 0U;
00100 
00101 }
00102 
00103 // ######################################################################
00104 void SaliencyMT::start1()
00105 {
00106   // start threads. They should go to sleep on the condition since no
00107   // jobs have ben queued up yet:
00108   pthread_mutex_init(&jobLock, NULL);
00109   pthread_mutex_init(&mapLock, NULL);
00110   pthread_cond_init(&jobCond, NULL);
00111 
00112   LINFO("Starting with %u threads...", itsNumThreads.getVal());
00113 
00114   // get our processing threads started:
00115   worker = new pthread_t[itsNumThreads.getVal()];
00116   for (uint i = 0; i < itsNumThreads.getVal(); i ++)
00117     {
00118       pthread_create(&worker[i], NULL, SaliencyMT_CMAP, (void *)this);
00119 
00120       // all threads should go and lock against our job condition. Sleep a
00121       // bit to make sure this really happens:
00122       usleep(100000);
00123     }
00124 }
00125 
00126 // ######################################################################
00127 void SaliencyMT::stop2()
00128 {
00129   // should cleanup the threads, mutexes, etc...
00130   pthread_cond_destroy(&jobCond);
00131 
00132   //for (uint i = 0; i < numthreads; i ++)
00133   //  pthread_delete(&worker[i].....
00134 
00135   delete [] worker;
00136 }
00137 
00138 // ######################################################################
00139 SaliencyMT::~SaliencyMT()
00140 { }
00141 
00142 // ######################################################################
00143 void SaliencyMT::newInput(Image< PixRGB<byte> > img, bool procFlicker)
00144 {
00145   //LINFO("new input.....");
00146   // store current color image:
00147   pthread_mutex_lock(&mapLock);
00148   colima = img;
00149 
00150   // also kill any old output and internals:
00151   outmap.freeMem();
00152   gotLum = false; gotRGBY = false; gotSkin = false;
00153   pthread_mutex_unlock(&mapLock);
00154 
00155   // setup job queue:
00156   pthread_mutex_lock(&jobLock);
00157   jobQueue.clear();
00158 
00159   jobQueue.push_back(jobData(INTENSITY, Gaussian5, IWEIGHT, 0.0F));
00160 
00161   jobQueue.push_back(jobData(REDGREEN, Gaussian5, CWEIGHT, 0.0F));
00162 
00163  // jobQueue.push_back(jobData(SKINHUE, Gaussian5, SWEIGHT, 0.0F));
00164 
00165   jobQueue.push_back(jobData(ORI0, Oriented5, OWEIGHT, 0.0F));
00166   jobQueue.push_back(jobData(ORI45, Oriented5, OWEIGHT, 45.0F));
00167   jobQueue.push_back(jobData(ORI90, Oriented5, OWEIGHT, 90.0F));
00168   jobQueue.push_back(jobData(ORI135, Oriented5, OWEIGHT, 135.0F));
00169 
00170   if (procFlicker)
00171     jobQueue.push_back(jobData(FLICKER, Gaussian5, FWEIGHT, 0.0F));
00172 
00173   jobQueue.push_back(jobData(BLUEYELLOW, Gaussian5, CWEIGHT, 0.0F));
00174 
00175   jobsTodo = jobQueue.size();
00176   pthread_mutex_unlock(&jobLock);
00177 
00178   // broadcast on job queue condition to wake up worker threads:
00179   pthread_cond_broadcast(&jobCond);
00180   //LINFO("new input ok.....");
00181 }
00182 
00183 // ######################################################################
00184 bool SaliencyMT::outputReady()
00185 {
00186   bool ret = false;
00187 
00188   pthread_mutex_lock(&jobLock);
00189   if (jobsTodo == 0U) ret = true;
00190   pthread_mutex_unlock(&jobLock);
00191 
00192   return ret;
00193 }
00194 
00195 // ######################################################################
00196 Image<float> SaliencyMT::getOutput()
00197 {
00198   Image<float> ret;
00199 
00200   pthread_mutex_lock(&mapLock);
00201   ret = outmap;
00202   pthread_mutex_unlock(&mapLock);
00203 
00204   return ret;
00205 }
00206 
00207 // ######################################################################
00208 Image<float> SaliencyMT::getRGOutput()
00209 {
00210   Image<float> ret;
00211 
00212   pthread_mutex_lock(&mapLock);
00213   ret = cmap_rg;
00214   pthread_mutex_unlock(&mapLock);
00215 
00216   return ret;
00217 }
00218 // ######################################################################
00219 Image<float> SaliencyMT::getBYOutput()
00220 {
00221   Image<float> ret;
00222 
00223   pthread_mutex_lock(&mapLock);
00224   ret = cmap_by;
00225   pthread_mutex_unlock(&mapLock);
00226 
00227   return ret;
00228 }
00229 // ######################################################################
00230 Image<float> SaliencyMT::getIntensityOutput()
00231 {
00232   Image<float> ret;
00233 
00234   pthread_mutex_lock(&mapLock);
00235   ret = cmap_intensity;
00236   pthread_mutex_unlock(&mapLock);
00237 
00238   return ret;
00239 }
00240 // ######################################################################
00241 //The threaded function
00242 void SaliencyMT::computeCMAP()
00243 {
00244   pthread_mutex_lock(&mapLock);
00245   uint myNum = numWorkers ++;
00246   pthread_mutex_unlock(&mapLock);
00247   LINFO("  ... worker %u ready.", myNum);
00248 
00249   while(true)
00250     {
00251       // wait until there are jobs in the queue that we can process:
00252       pthread_mutex_lock(&jobLock);
00253       jobData current(0, Gaussian5, 0.0F, 0.0F); bool nojobs = true;
00254       if (jobQueue.empty() == false)
00255         {
00256           current = jobQueue.front();
00257           jobQueue.pop_front();
00258           nojobs = false;
00259         }
00260       else
00261         pthread_cond_wait(&jobCond, &jobLock);
00262       pthread_mutex_unlock(&jobLock);
00263 
00264       // if we don't have a job to do, just wait more:
00265       if (nojobs) continue;
00266       //LINFO("[%u] GOT: job %d", myNum, int(current.jobType));
00267 
00268       // read next entry in job queue and perform desired action on
00269       // current image and record result in output image
00270       // (accumulative)
00271       Image<float> curImage;
00272 
00273       // The case statement on this end parses the desired action from
00274       // the job queue and performs the needed image pre-processing
00275       pthread_mutex_lock(&mapLock);
00276       switch(current.jobType)
00277         {
00278           // While shared resources are used here, they are only read,
00279           // so they should not need to be protected by mutexers
00280 
00281           // ##################################################
00282         case REDGREEN:
00283           if (gotRGBY == false)
00284             { getRGBY(colima, r, g, b, y, byte(25)); gotRGBY = true; }
00285           curImage = r - g;
00286           break;
00287 
00288           // ##################################################
00289         case BLUEYELLOW:
00290           if (gotRGBY == false)
00291             { getRGBY(colima, r, g, b, y, byte(25)); gotRGBY = true; }
00292           curImage = b - y;
00293           break;
00294 
00295           // ##################################################
00296         case SKINHUE:
00297           if (gotSkin == false)
00298             {
00299               skinima = hueDistance(colima, COL_SKIN_MUR, COL_SKIN_MUG,
00300                                     COL_SKIN_SIGR, COL_SKIN_SIGG,
00301                                     COL_SKIN_RHO);
00302               gotSkin = true;
00303             }
00304           curImage = skinima;
00305           break;
00306 
00307           // ##################################################
00308         case ORI0:
00309         case ORI45:
00310         case ORI90:
00311         case ORI135:
00312         case INTENSITY:
00313           if (gotLum == false)
00314             { lum = Image<float>(luminance(colima)); gotLum = true; }
00315           curImage = lum;
00316           break;
00317 
00318           // ##################################################
00319         case FLICKER:
00320           if (gotLum == false)
00321             { lum = Image<float>(luminance(colima)); gotLum = true; }
00322           // compute flicker consp map and send to collector:
00323           if (prev.initialized() == false)
00324             {
00325               prev = lum;
00326               curImage.resize(lum.getDims(), true); // clear
00327             }
00328           else
00329             {
00330               curImage = lum - prev;
00331               prev = lum;
00332             }
00333           break;
00334 
00335           // ##################################################
00336         default:
00337           LERROR("What is going on around here?");
00338           curImage = lum;
00339         }
00340       pthread_mutex_unlock(&mapLock);
00341 
00342       // compute pyramid:
00343       ImageSet<float> pyr =
00344         buildPyrGeneric(curImage, 0, maxdepth,
00345                         current.ptyp, current.orientation);
00346 
00347       // alloc conspicuity map and clear it:
00348       Image<float> cmap(pyr[sml].getDims(), ZEROS);
00349 
00350       // intensities is the max-normalized weighted sum of IntensCS:
00351       for (int delta = delta_min; delta <= delta_max; delta ++)
00352         for (int lev = level_min; lev <= level_max; lev ++)
00353           {
00354             Image<float> tmp = centerSurround(pyr, lev, lev + delta, true);
00355             tmp = downSize(tmp, cmap.getWidth(), cmap.getHeight());
00356             tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp);
00357             cmap += tmp;
00358           }
00359 
00360       inplaceAddBGnoise(cmap, 25.0F);
00361 
00362       if (normtyp == VCXNORM_MAXNORM)
00363         cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp);
00364       else
00365         cmap = maxNormalize(cmap, 0.0f, 0.0f, normtyp);
00366 
00367       // multiply by conspicuity coefficient:
00368       if (current.weight != 1.0F) cmap *= current.weight;
00369 
00370       // Add to saliency map:
00371       pthread_mutex_lock(&mapLock);
00372       if (outmap.initialized()) outmap += cmap;
00373       else outmap = cmap;
00374                         if(current.jobType == REDGREEN)
00375                                 cmap_rg = cmap;
00376                         else if(current.jobType == BLUEYELLOW)
00377                                 cmap_by = cmap;
00378                         else if(current.jobType == INTENSITY)
00379                                 cmap_intensity = cmap;
00380       pthread_mutex_unlock(&mapLock);
00381       pthread_mutex_lock(&jobLock);
00382       -- jobsTodo;
00383       //LINFO("done with job %d, %u todo...", int(current.jobType),jobsTodo);
00384       pthread_mutex_unlock(&jobLock);
00385     }
00386 }
00387 
00388 // ######################################################################
00389 /* So things look consistent in everyone's emacs... */
00390 /* Local Variables: */
00391 /* indent-tabs-mode: nil */
00392 /* End: */
Generated on Sun May 8 08:40:11 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3