SaliencyMT.C

Go to the documentation of this file.
00001 /*!@file Demo/SaliencyMT.C A class for quick-and-dirty saliency mapping */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // 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: Zack Gossman <gossman@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Demo/SaliencyMT.C $
00035 // $Id: SaliencyMT.C 8095 2007-03-12 01:14:23Z lior $
00036 //
00037 
00038 #include "Demo/SaliencyMT.H"
00039 #include "Demo/DemoOpts.H"
00040 
00041 // ######################################################################
00042 // ##### Global options:
00043 // ######################################################################
00044 
00045 #define sml        2
00046 #define delta_min  3
00047 #define delta_max  4
00048 #define level_min  0
00049 #define level_max  2
00050 #define maxdepth   (level_max + delta_max + 1)
00051 #define normtyp    (VCXNORM_MAXNORM)
00052 
00053 // relative feature weights:
00054 #define IWEIGHT 0.7
00055 #define CWEIGHT 1.0
00056 #define OWEIGHT 1.0
00057 #define FWEIGHT 1.0
00058 #define SWEIGHT 0.7
00059 
00060 // image size vars
00061 #define IMAGEWIDTH 160
00062 #define IMAGEHEIGHT 120
00063 
00064 // action definitions CHANGE TO ENUM? FIX?
00065 #define RETINA     1
00066 #define WINNER     2
00067 #define LUMINANCE  3
00068 #define REDGREEN   4
00069 #define BLUEYELLOW 5
00070 #define ORI0       6
00071 #define ORI45      7
00072 #define ORI90      8
00073 #define ORI135     9
00074 #define CMAP       10
00075 #define FLICKER    11
00076 #define INTENSITY  12
00077 #define SKINHUE    13
00078 
00079 #define numthreads 1
00080 
00081 // ######################################################################
00082 void *SaliencyMT_CMAP(void *c)
00083 {
00084   SaliencyMT *d = (SaliencyMT *)c;
00085   d->computeCMAP();
00086   return NULL;
00087 }
00088 
00089 // ######################################################################
00090 SaliencyMT::SaliencyMT(OptionManager& mgr,
00091            const std::string& descrName,
00092            const std::string& tagName):
00093   ModelComponent(mgr, descrName, tagName),
00094   itsNumThreads(&OPT_SMTnumThreads, this)  // see Demo/DemoOpts.{H,C}
00095 
00096 {
00097 
00098   numWorkers = 0U;
00099 
00100 }
00101 
00102 // ######################################################################
00103 void SaliencyMT::start1()
00104 {
00105   // start threads. They should go to sleep on the condition since no
00106   // jobs have ben queued up yet:
00107   pthread_mutex_init(&jobLock, NULL);
00108   pthread_mutex_init(&mapLock, NULL);
00109   pthread_cond_init(&jobCond, NULL);
00110 
00111   LINFO("Starting with %u threads...", itsNumThreads.getVal());
00112 
00113   // get our processing threads started:
00114   worker = new pthread_t[itsNumThreads.getVal()];
00115   for (uint i = 0; i < itsNumThreads.getVal(); i ++)
00116     {
00117       pthread_create(&worker[i], NULL, SaliencyMT_CMAP, (void *)this);
00118 
00119       // all threads should go and lock against our job condition. Sleep a
00120       // bit to make sure this really happens:
00121       usleep(100000);
00122     }
00123 }
00124 
00125 // ######################################################################
00126 void SaliencyMT::stop2()
00127 {
00128   // should cleanup the threads, mutexes, etc...
00129   pthread_cond_destroy(&jobCond);
00130 
00131   //for (uint i = 0; i < numthreads; i ++)
00132   //  pthread_delete(&worker[i].....
00133 
00134   delete [] worker;
00135 }
00136 
00137 // ######################################################################
00138 SaliencyMT::~SaliencyMT()
00139 { }
00140 
00141 // ######################################################################
00142 void SaliencyMT::newInput(Image< PixRGB<byte> > img, bool procFlicker)
00143 {
00144   //LINFO("new input.....");
00145   // store current color image:
00146   pthread_mutex_lock(&mapLock);
00147   colima = img;
00148 
00149   // also kill any old output and internals:
00150   outmap.freeMem();
00151   gotLum = false; gotRGBY = false; gotSkin = false;
00152   pthread_mutex_unlock(&mapLock);
00153 
00154   // setup job queue:
00155   pthread_mutex_lock(&jobLock);
00156   jobQueue.clear();
00157 
00158   jobQueue.push_back(jobData(INTENSITY, Gaussian5, IWEIGHT, 0.0F));
00159 
00160   jobQueue.push_back(jobData(REDGREEN, Gaussian5, CWEIGHT, 0.0F));
00161 
00162  // jobQueue.push_back(jobData(SKINHUE, Gaussian5, SWEIGHT, 0.0F));
00163 
00164   jobQueue.push_back(jobData(ORI0, Oriented5, OWEIGHT, 0.0F));
00165   jobQueue.push_back(jobData(ORI45, Oriented5, OWEIGHT, 45.0F));
00166   jobQueue.push_back(jobData(ORI90, Oriented5, OWEIGHT, 90.0F));
00167   jobQueue.push_back(jobData(ORI135, Oriented5, OWEIGHT, 135.0F));
00168 
00169   if (procFlicker)
00170     jobQueue.push_back(jobData(FLICKER, Gaussian5, FWEIGHT, 0.0F));
00171 
00172   jobQueue.push_back(jobData(BLUEYELLOW, Gaussian5, CWEIGHT, 0.0F));
00173 
00174   jobsTodo = jobQueue.size();
00175   pthread_mutex_unlock(&jobLock);
00176 
00177   // broadcast on job queue condition to wake up worker threads:
00178   pthread_cond_broadcast(&jobCond);
00179   //LINFO("new input ok.....");
00180 }
00181 
00182 // ######################################################################
00183 bool SaliencyMT::outputReady()
00184 {
00185   bool ret = false;
00186 
00187   pthread_mutex_lock(&jobLock);
00188   if (jobsTodo == 0U) ret = true;
00189   pthread_mutex_unlock(&jobLock);
00190 
00191   return ret;
00192 }
00193 
00194 // ######################################################################
00195 Image<float> SaliencyMT::getOutput()
00196 {
00197   Image<float> ret;
00198 
00199   pthread_mutex_lock(&mapLock);
00200   ret = outmap;
00201   pthread_mutex_unlock(&mapLock);
00202 
00203   return ret;
00204 }
00205 
00206 // ######################################################################
00207 //The threaded function
00208 void SaliencyMT::computeCMAP()
00209 {
00210   pthread_mutex_lock(&mapLock);
00211   uint myNum = numWorkers ++;
00212   pthread_mutex_unlock(&mapLock);
00213   LINFO("  ... worker %u ready.", myNum);
00214 
00215   while(true)
00216     {
00217       // wait until there are jobs in the queue that we can process:
00218       pthread_mutex_lock(&jobLock);
00219       jobData current(0, Gaussian5, 0.0F, 0.0F); bool nojobs = true;
00220       if (jobQueue.empty() == false)
00221         {
00222           current = jobQueue.front();
00223           jobQueue.pop_front();
00224           nojobs = false;
00225         }
00226       else
00227         pthread_cond_wait(&jobCond, &jobLock);
00228       pthread_mutex_unlock(&jobLock);
00229 
00230       // if we don't have a job to do, just wait more:
00231       if (nojobs) continue;
00232       //LINFO("[%u] GOT: job %d", myNum, int(current.jobType));
00233 
00234       // read next entry in job queue and perform desired action on
00235       // current image and record result in output image
00236       // (accumulative)
00237       Image<float> curImage;
00238 
00239       // The case statement on this end parses the desired action from
00240       // the job queue and performs the needed image pre-processing
00241       pthread_mutex_lock(&mapLock);
00242       switch(current.jobType)
00243         {
00244           // While shared resources are used here, they are only read,
00245           // so they should not need to be protected by mutexers
00246 
00247           // ##################################################
00248         case REDGREEN:
00249           if (gotRGBY == false)
00250             { getRGBY(colima, r, g, b, y, byte(25)); gotRGBY = true; }
00251           curImage = r - g;
00252           break;
00253 
00254           // ##################################################
00255         case BLUEYELLOW:
00256           if (gotRGBY == false)
00257             { getRGBY(colima, r, g, b, y, byte(25)); gotRGBY = true; }
00258           curImage = b - y;
00259           break;
00260 
00261           // ##################################################
00262         case SKINHUE:
00263           if (gotSkin == false)
00264             {
00265               skinima = hueDistance(colima, COL_SKIN_MUR, COL_SKIN_MUG,
00266                                     COL_SKIN_SIGR, COL_SKIN_SIGG,
00267                                     COL_SKIN_RHO);
00268               gotSkin = true;
00269             }
00270           curImage = skinima;
00271           break;
00272 
00273           // ##################################################
00274         case ORI0:
00275         case ORI45:
00276         case ORI90:
00277         case ORI135:
00278         case INTENSITY:
00279           if (gotLum == false)
00280             { lum = Image<float>(luminance(colima)); gotLum = true; }
00281           curImage = lum;
00282           break;
00283 
00284           // ##################################################
00285         case FLICKER:
00286           if (gotLum == false)
00287             { lum = Image<float>(luminance(colima)); gotLum = true; }
00288           // compute flicker consp map and send to collector:
00289           if (prev.initialized() == false)
00290             {
00291               prev = lum;
00292               curImage.resize(lum.getDims(), true); // clear
00293             }
00294           else
00295             {
00296               curImage = lum - prev;
00297               prev = lum;
00298             }
00299           break;
00300 
00301           // ##################################################
00302         default:
00303           LERROR("What is going on around here?");
00304           curImage = lum;
00305         }
00306       pthread_mutex_unlock(&mapLock);
00307 
00308       // compute pyramid:
00309       ImageSet<float> pyr =
00310         buildPyrGeneric(curImage, 0, maxdepth,
00311                         current.ptyp, current.orientation);
00312 
00313       // alloc conspicuity map and clear it:
00314       Image<float> cmap(pyr[sml].getDims(), ZEROS);
00315 
00316       // intensities is the max-normalized weighted sum of IntensCS:
00317       for (int delta = delta_min; delta <= delta_max; delta ++)
00318         for (int lev = level_min; lev <= level_max; lev ++)
00319           {
00320             Image<float> tmp = centerSurround(pyr, lev, lev + delta, true);
00321             tmp = downSize(tmp, cmap.getWidth(), cmap.getHeight());
00322             tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp);
00323             cmap += tmp;
00324           }
00325 
00326       inplaceAddBGnoise(cmap, 25.0F);
00327 
00328       if (normtyp == VCXNORM_MAXNORM)
00329         cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp);
00330       else
00331         cmap = maxNormalize(cmap, 0.0f, 0.0f, normtyp);
00332 
00333       // multiply by conspicuity coefficient:
00334       if (current.weight != 1.0F) cmap *= current.weight;
00335 
00336       // Add to saliency map:
00337       pthread_mutex_lock(&mapLock);
00338       if (outmap.initialized()) outmap += cmap;
00339       else outmap = cmap;
00340       pthread_mutex_unlock(&mapLock);
00341 
00342       pthread_mutex_lock(&jobLock);
00343       -- jobsTodo;
00344       //LINFO("done with job %d, %u todo...", int(current.jobType),jobsTodo);
00345       pthread_mutex_unlock(&jobLock);
00346     }
00347 }
00348 
00349 // ######################################################################
00350 /* So things look consistent in everyone's emacs... */
00351 /* Local Variables: */
00352 /* indent-tabs-mode: nil */
00353 /* End: */
Generated on Sun May 8 08:40:11 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3