SaliencyCMapMT.C

Go to the documentation of this file.
00001 /*!@file CMapDemo/SaliencyCMapMT.C A class for quick-and-dirty
00002   saliency mapping integrated with cmap CORBA object                    */
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/CMapDemo/SaliencyCMapMT.C $
00035 // $Id: SaliencyCMapMT.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 #include "CMapDemo/SaliencyCMapMT.H"
00039 #include "Demo/DemoOpts.H"
00040 #include "Corba/CorbaUtil.H"
00041 #include "Image/PyrBuilder.H"
00042 #include "Image/OpenCVUtil.H"
00043 
00044 #include <sys/time.h>
00045 #include <errno.h>
00046 
00047 #ifdef HAVE_OPENCV_CV_H
00048 #include <opencv/cv.h>
00049 #endif
00050 
00051 //are we using a local linked cmap server or a remote
00052 //set this if we are running on only one computer
00053 #ifdef LocalCMapServer
00054 //#include "Corba/Objects/CMapServer.H"
00055 #endif
00056 // ######################################################################
00057 // ##### Global options:
00058 // ######################################################################
00059 
00060 
00061 // relative feature weights:
00062 #define IWEIGHT 1.0
00063 #define CWEIGHT 1.0
00064 #define OWEIGHT 1.0
00065 #define FWEIGHT 4.0
00066 #define SWEIGHT 0.7
00067 
00068 // image size vars
00069 #define IMAGEWIDTH 160
00070 #define IMAGEHEIGHT 120
00071 
00072 
00073 #define numthreads 1
00074 
00075 // ######################################################################
00076 void *SaliencyMT_CMAP(void *c)
00077 {
00078   SaliencyMT *d = (SaliencyMT *)c;
00079   d->computeCMAP();
00080   return NULL;
00081 }
00082 
00083 // ######################################################################
00084 SaliencyMT::SaliencyMT(OptionManager& mgr,CORBA::ORB_ptr orb, short saliencyMapLevel,
00085                        const std::string& descrName,
00086                        const std::string& tagName):
00087   ModelComponent(mgr, descrName, tagName), nCmapObj(0),
00088   itsNumThreads(&OPT_SMTnumThreads, this), // see Demo/DemoOpts.{H,C}
00089   SMBias(ImageSet<float>(14))
00090 
00091 {
00092   numWorkers = 0U;
00093 
00094   if (!getMultiObjectRef(orb, "saliency.CMapServers", CMap_ref, nCmapObj)){
00095     LFATAL("Can not find any object to bind with");
00096   }
00097   for(int i=0; i<nCmapObj; i++)
00098     CMap::_narrow(CMap_ref[i])->setSaliencyMapLevel(saliencyMapLevel);
00099   biasSM = false;
00100 }
00101 
00102 void SaliencyMT::setBiasSM(bool val){
00103   biasSM = val;
00104 }
00105 
00106 // ######################################################################
00107 void SaliencyMT::setSaliencyMapLevel(const short saliencyMapLevel){
00108   //set the saliency map level to return
00109   for(int i=0; i<nCmapObj; i++)
00110     CMap::_narrow(CMap_ref[i])->setSaliencyMapLevel(saliencyMapLevel);
00111 }
00112 
00113 
00114 // ######################################################################
00115 //!The current cmap object to send the request to
00116 CMap_ptr SaliencyMT::getCmapRef(){
00117   static int current_obj = 0;
00118 
00119   //just do a round robin
00120   current_obj  = (current_obj+1)%nCmapObj;
00121 
00122   LDEBUG("Using cmap object number %i\n", current_obj);
00123 
00124   return CMap::_narrow(CMap_ref[current_obj]);
00125 }
00126 
00127 // ######################################################################
00128 void SaliencyMT::start1()
00129 {
00130   // start threads. They should go to sleep on the condition since no
00131   // jobs have ben queued up yet:
00132   pthread_mutex_init(&jobLock, NULL);
00133   pthread_mutex_init(&mapLock, NULL);
00134   pthread_mutex_init(&jobStatusLock, NULL);
00135   pthread_cond_init(&jobCond, NULL);
00136   pthread_cond_init(&jobDone, NULL);
00137 
00138   LINFO("Starting with %u threads...", itsNumThreads.getVal());
00139 
00140   // get our processing threads started:
00141   worker = new pthread_t[itsNumThreads.getVal()];
00142   for (uint i = 0; i < itsNumThreads.getVal(); i ++)
00143     {
00144       pthread_create(&worker[i], NULL, SaliencyMT_CMAP, (void *)this);
00145 
00146       // all threads should go and lock against our job condition. Sleep a
00147       // bit to make sure this really happens:
00148       usleep(100000);
00149     }
00150 }
00151 
00152 // ######################################################################
00153 void SaliencyMT::stop2()
00154 {
00155   // should cleanup the threads, mutexes, etc...
00156   pthread_cond_destroy(&jobCond);
00157 
00158   //for (uint i = 0; i < numthreads; i ++)
00159   //  pthread_delete(&worker[i].....
00160 
00161   delete [] worker;
00162 }
00163 
00164 // ######################################################################
00165 SaliencyMT::~SaliencyMT(){ }
00166 
00167 // ######################################################################
00168 void SaliencyMT::newInput(Image< PixRGB<byte> > img)
00169 {
00170   //LINFO("new input.....");
00171   // store current color image:
00172   pthread_mutex_lock(&mapLock);
00173   colima = img;
00174 
00175   // also kill any old output and internals:
00176   outmap.freeMem();
00177   gotLum = false; gotRGBY = false; gotSkin = false;
00178   pthread_mutex_unlock(&mapLock);
00179 
00180   // setup job queue:
00181   pthread_mutex_lock(&jobLock);
00182   jobQueue.clear();
00183 
00184   jobQueue.push_back(jobData(INTENSITY, Gaussian5, IWEIGHT, 0.0F));
00185 
00186   jobQueue.push_back(jobData(REDGREEN, Gaussian5, CWEIGHT, 0.0F));
00187   jobQueue.push_back(jobData(BLUEYELLOW, Gaussian5, CWEIGHT, 0.0F));
00188 
00189   ////jobQueue.push_back(jobData(SKINHUE, Gaussian5, SWEIGHT, 0.0F));
00190 
00191   // jobQueue.push_back(jobData(ORI0, Oriented5, OWEIGHT, 0.0F));
00192   // jobQueue.push_back(jobData(ORI45, Oriented5, OWEIGHT, 45.0F));
00193   // jobQueue.push_back(jobData(ORI90, Oriented5, OWEIGHT, 90.0F));
00194   // jobQueue.push_back(jobData(ORI135, Oriented5, OWEIGHT, 135.0F));
00195 
00196   //jobQueue.push_back(jobData(FLICKER, Gaussian5, FWEIGHT, 0.0F));
00197 
00198   jobsTodo = jobQueue.size();
00199   pthread_mutex_unlock(&jobLock);
00200 
00201   // broadcast on job queue condition to wake up worker threads:
00202   pthread_cond_broadcast(&jobCond);
00203   //LINFO("new input ok.....");
00204 }
00205 
00206 // ######################################################################
00207 bool SaliencyMT::outputReady()
00208 {
00209   bool ret = false;
00210 
00211   pthread_mutex_lock(&jobLock);
00212   if (jobsTodo == 0U) ret = true;
00213   pthread_mutex_unlock(&jobLock);
00214 
00215   return ret;
00216 }
00217 
00218 // ######################################################################
00219 Image<float> SaliencyMT::getOutput()
00220 {
00221   Image<float> ret;
00222 
00223   pthread_mutex_lock(&mapLock);
00224   ret = outmap;
00225   pthread_mutex_unlock(&mapLock);
00226 
00227   return ret;
00228 }
00229 
00230 // ######################################################################
00231 Image<float> SaliencyMT::getSMap(Image< PixRGB<byte> > img)
00232 {
00233   Image<float> ret;
00234 
00235   newInput(img);
00236 
00237   LINFO("Getting smap");
00238   //wait for done signal
00239   pthread_mutex_lock(&jobStatusLock);
00240 
00241   LINFO("Waiting for smap");
00242   struct timeval abstime_tv;
00243   gettimeofday(&abstime_tv, NULL);
00244 
00245   struct timespec abstime;
00246   abstime.tv_sec = abstime_tv.tv_sec;
00247   abstime.tv_sec += 3; //wait 3 seconds for condition
00248   abstime.tv_nsec = 0;
00249 
00250   //pthread_cond_wait(&jobDone, &jobStatusLock);
00251   if (pthread_cond_timedwait(&jobDone, &jobStatusLock, &abstime) == ETIMEDOUT){
00252     LINFO("TIme out");
00253   }
00254   pthread_mutex_unlock(&jobStatusLock);
00255 
00256   LINFO("Getting smap ");
00257 
00258   pthread_mutex_lock(&mapLock);
00259   ret = outmap;
00260   pthread_mutex_unlock(&mapLock);
00261 
00262   return ret;
00263 }
00264 
00265 // ######################################################################
00266 //Bias the main saliency map
00267 void SaliencyMT::setSMBias(ImageSet<float> &bias){
00268 
00269   for(unsigned int i=0; i<bias.size(); i++){
00270     if (bias[i].initialized())
00271       SMBias[i] = bias[i];
00272   }
00273 }
00274 
00275 // ######################################################################
00276 //Bias the CMap
00277 void SaliencyMT::setBias(int type, std::vector<float> &bias)
00278 {
00279 
00280   CMap::BiasSeq *curBias = NULL;
00281   switch (type) {
00282   case REDGREEN:
00283     curBias = &cmapBias.redgreen;
00284     break;
00285   case BLUEYELLOW:
00286     curBias = &cmapBias.blueyellow;
00287     break;
00288   case SKINHUE:
00289     curBias = &cmapBias.skinhue;
00290     break;
00291   case ORI0:
00292     curBias = &cmapBias.ori0;
00293     break;
00294   case ORI45:
00295     curBias = &cmapBias.ori45;
00296     break;
00297   case ORI90:
00298     curBias = &cmapBias.ori90;
00299     break;
00300   case ORI135:
00301     curBias = &cmapBias.ori135;
00302     break;
00303   case INTENSITY:
00304     curBias = &cmapBias.intensity;
00305     break;
00306   case FLICKER:
00307     curBias = &cmapBias.flicker;
00308     break;
00309   default:
00310     LINFO("Unknown type");
00311   }
00312 
00313 
00314   //assign the bias
00315   if (curBias != NULL){
00316     curBias->length(bias.size());
00317     for(unsigned int i=0; i<bias.size(); i++)
00318       (*curBias)[i] = bias[i];
00319   }
00320 
00321 }
00322 
00323 // ######################################################################
00324 // Get the CMap
00325 void SaliencyMT::getBias(Image< PixRGB<byte> > &ima,
00326                          std::vector<float> &bias, int type, Point2D<int> &loc)
00327 {
00328   PyramidType ptype = Gaussian5;
00329   float weight = 0;
00330   float ori = 0;
00331   Image<byte> curImage;
00332 
00333   Image<float> local_lum;        //curent luminance image
00334   Image<byte> local_r, local_g, local_b, local_y;  //curent RGBY images
00335   Image<float> local_skinima;    //skin hue map
00336 
00337   switch (type) {
00338   case REDGREEN:
00339     ptype = Gaussian5;
00340     ori = 0.0F;
00341     getRGBY(ima, local_r, local_g, local_b, local_y, byte(25));
00342     curImage = local_r - local_g;
00343     break;
00344 
00345     // ##################################################
00346   case BLUEYELLOW:
00347     ptype = Gaussian5;
00348     ori = 0.0F;
00349     getRGBY(ima, local_r, local_g, local_b, local_y, byte(25));
00350     curImage = local_b - local_y;
00351     break;
00352 
00353     // ##################################################
00354   case SKINHUE:
00355     ptype = Gaussian5;
00356     ori = 0.0F;
00357     local_skinima = hueDistance(ima, COL_SKIN_MUR, COL_SKIN_MUG,
00358                                 COL_SKIN_SIGR, COL_SKIN_SIGG,
00359                                 COL_SKIN_RHO);
00360     curImage = local_skinima;
00361     break;
00362 
00363     // ##################################################
00364   case ORI0:
00365     ptype = Oriented5;
00366     ori = 0.0F;
00367 
00368     curImage = Image<byte>(luminance(ima));
00369     break;
00370   case ORI45:
00371     ptype = Oriented5;
00372     ori = 45.0F;
00373     curImage = Image<byte>(luminance(ima));
00374     break;
00375   case ORI90:
00376     ptype = Oriented5;
00377     ori = 90.0F;
00378     curImage = Image<byte>(luminance(ima));
00379     break;
00380   case ORI135:
00381     ptype = Oriented5;
00382     ori = 135.0F;
00383     curImage = Image<byte>(luminance(ima));
00384     break;
00385   case INTENSITY:
00386     ptype = Gaussian5;
00387     ori = 0.0F;
00388     curImage = Image<byte>(luminance(ima));
00389     break;
00390 
00391     // ##################################################
00392   case FLICKER:
00393     ptype = Gaussian5;
00394     ori = 0.0F;
00395     curImage = Image<byte>(luminance(ima));
00396     break;
00397 
00398     // ##################################################
00399   default:
00400     LERROR("What is going on around here?");
00401 
00402   }
00403 
00404   CMap_ptr CMap = getCmapRef();
00405   Point2DOrb locOrb;
00406   locOrb.i = loc.i; locOrb.j = loc.j;
00407 
00408   ImageOrb *curImageOrb = image2Orb(curImage);
00409   CMap::BiasSeq *curBias = CMap->getBiasCMAP(*curImageOrb, ptype, ori, weight, locOrb);
00410   delete curImageOrb;
00411 
00412   //assign the bias
00413   if (curBias != NULL){
00414     curBias->length(bias.size());
00415     for(unsigned int i=0; i<bias.size(); i++)
00416       bias[i] = (*curBias)[i];
00417   }
00418   delete curBias;
00419 
00420 }
00421 
00422 // ######################################################################
00423 // the threaded function
00424 void SaliencyMT::computeCMAP()
00425 {
00426 #ifndef HAVE_OPENCV
00427   LFATAL("OpenCV must be installed to use this function");
00428 #else
00429   pthread_mutex_lock(&mapLock);
00430   uint myNum = numWorkers ++;
00431   pthread_mutex_unlock(&mapLock);
00432   LINFO("  ... worker %u ready.", myNum);
00433 
00434   while(true)
00435     {
00436       // wait until there are jobs in the queue that we can process:
00437       pthread_mutex_lock(&jobLock);
00438       jobData current; bool nojobs = true;
00439       if (jobQueue.empty() == false)
00440         {
00441           current = jobQueue.front();
00442           jobQueue.pop_front();
00443           nojobs = false;
00444         }
00445       else
00446         pthread_cond_wait(&jobCond, &jobLock);
00447       pthread_mutex_unlock(&jobLock);
00448 
00449       // if we don't have a job to do, just wait more:
00450       if (nojobs) continue;
00451       LDEBUG("[%u] GOT: job %d", myNum, int(current.jobType));
00452 
00453       // read next entry in job queue and perform desired action on
00454       // current image and record result in output image
00455       // (accumulative)
00456       Image<byte> curImage;
00457 
00458       // The case statement on this end parses the desired action from
00459       // the job queue and performs the needed image pre-processing
00460       pthread_mutex_lock(&mapLock);
00461 
00462       switch(current.jobType)
00463         {
00464           // While shared resources are used here, they are only read,
00465           // so they should not need to be protected by mutexers
00466 
00467           // ##################################################
00468         case REDGREEN:
00469           if (gotRGBY == false)
00470             { getRGBY(colima, r, g, b, y, byte(25)); gotRGBY = true; }
00471           curImage = r - g;
00472           break;
00473 
00474           // ##################################################
00475         case BLUEYELLOW:
00476           if (gotRGBY == false)
00477             { getRGBY(colima, r, g, b, y, byte(25)); gotRGBY = true; }
00478           curImage = b - y;
00479           break;
00480 
00481           // ##################################################
00482         case SKINHUE:
00483           if (gotSkin == false)
00484             {
00485               skinima = hueDistance(colima, COL_SKIN_MUR, COL_SKIN_MUG,
00486                                     COL_SKIN_SIGR, COL_SKIN_SIGG,
00487                                     COL_SKIN_RHO);
00488               gotSkin = true;
00489             }
00490           curImage = skinima;
00491           break;
00492 
00493           // ##################################################
00494         case ORI0:
00495           if (gotLum == false)
00496             { lum = Image<byte>(luminance(colima)); gotLum = true; }
00497           curImage = lum;
00498           break;
00499         case ORI45:
00500           if (gotLum == false)
00501             { lum = Image<byte>(luminance(colima)); gotLum = true; }
00502           curImage = lum;
00503           break;
00504         case ORI90:
00505           if (gotLum == false)
00506             { lum = Image<byte>(luminance(colima)); gotLum = true; }
00507           curImage = lum;
00508           break;
00509         case ORI135:
00510           if (gotLum == false)
00511             { lum = Image<byte>(luminance(colima)); gotLum = true; }
00512           curImage = lum;
00513           break;
00514         case INTENSITY:
00515           if (gotLum == false)
00516             { lum = Image<byte>(luminance(colima)); gotLum = true; }
00517           curImage = lum;
00518           break;
00519 
00520           // ##################################################
00521         case FLICKER:
00522           if (gotLum == false)
00523             { lum = Image<byte>(luminance(colima)); gotLum = true; }
00524           // compute flicker consp map and send to collector:
00525           if (prev.initialized() == false)
00526             {
00527               prev = lum;
00528               curImage.resize(lum.getDims(), true); // clear
00529             }
00530           else
00531             {
00532               curImage = lum - prev;
00533               prev = lum;
00534             }
00535           break;
00536 
00537           // ##################################################
00538         default:
00539           LERROR("What is going on around here?");
00540           curImage = lum;
00541         }
00542       pthread_mutex_unlock(&mapLock);
00543 
00544       /*
00545         CMap_var CMapObj = getCmapRef();        //get the object to send to
00546 
00547         ImageOrb *imgOrb;
00548         ImageOrb *curImageOrb = image2Orb(curImage);
00549 
00550         if (biasSM && curBias != NULL && curBias->length()){
00551         imgOrb = CMapObj->computeBiasCMAP(*curImageOrb,
00552         current.ptyp, current.orientation, current.weight, *curBias);
00553         } else {
00554         imgOrb = CMapObj->computeCMAP(*curImageOrb,
00555         current.ptyp, current.orientation, current.weight);
00556         }
00557         delete curImageOrb;
00558 
00559         Image<float> cmap;
00560         orb2Image(*imgOrb, cmap);
00561         delete imgOrb;
00562       */
00563 
00564       Image<float> cmap = curImage;
00565 
00566       //Image<float> biasedCMap;
00567       Image<float> biasedCMap(cmap.getWidth()-SMBias[current.jobType].getWidth()+1,
00568                               cmap.getHeight()-SMBias[current.jobType].getHeight()+1,
00569                               NO_INIT);
00570 
00571       if (biasSM){
00572         if (SMBias[current.jobType].initialized())
00573           cvMatchTemplate(img2ipl(cmap),
00574                           img2ipl(SMBias[current.jobType]),
00575                           img2ipl(biasedCMap),
00576                           //CV_TM_CCOEFF);
00577                           CV_TM_SQDIFF);
00578 
00579         // biasedCMap = correlation(cmap, SMBias[current.jobType]);
00580       }
00581 
00582 
00583       // Add to saliency map:
00584       pthread_mutex_lock(&mapLock);
00585       cmaps[current.jobType] = cmap;        //save the cmap
00586 
00587       if (biasSM){
00588         if (outmap.initialized()) outmap += biasedCMap;
00589         else outmap = biasedCMap;
00590       } else {
00591         if (outmap.initialized()) outmap += cmap;
00592         else outmap = cmap;
00593       }
00594 
00595       pthread_mutex_unlock(&mapLock);
00596 
00597       pthread_mutex_lock(&jobLock);
00598       -- jobsTodo;
00599       LDEBUG("done with job %d, %u todo...", int(current.jobType),jobsTodo);
00600 
00601       if (jobsTodo == 0U)         //Last job, let know that we are done for block calls
00602         pthread_cond_signal(&jobDone);
00603 
00604 
00605       pthread_mutex_unlock(&jobLock);
00606     }
00607 #endif
00608 }
00609 
00610 // ######################################################################
00611 /* So things look consistent in everyone's emacs... */
00612 /* Local Variables: */
00613 /* indent-tabs-mode: nil */
00614 /* End: */
Generated on Sun May 8 08:04:42 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3