mexSaliencySkin.C

Go to the documentation of this file.
00001 /*!@file Matlab/mexSaliencySkin.C This is the MEX file version of the Saliency program<br>
00002   This file compiles into a MEX file that can be called from within
00003   Matlab for extracting the saliency information from an image. The
00004   call from Matlab is:<BR> <TT>[num_sal, coords, times, salmap,
00005   modfunc, areas, labels] = Saliency(image, targets, max_time, foa_size,
00006   weights, normtype, smoothFactor, levels);</TT><P>
00007 
00008   Compared to mexSaliency.C, this version contains a HueChannel.
00009 
00010   The return values are:
00011 
00012   @param num_sal the number of salient spots found
00013   @param coords (2, num_sal) array that contains the x and y coordinates
00014   of the salient spots in (1,:) and (2,:), respectively
00015   @param times (1, num_sal) array that contains the evolution times
00016   @param salmap the saliency map (normalized between 0 and 1)
00017   @param modfunc (num_sal, height, width) array that contains the modulation
00018   functions for the salient spots, maxnormalized to 1.0
00019   @param areas (1, num_sal) array that contains the number of pixels for
00020   salient spot that have contributed to the modulation function
00021   @param labels {num_sal} cell array containing the label strings from the
00022   size info analysis
00023 
00024   The only <I>required</I> argument is:
00025   @param image the input image
00026 
00027   <I>Optional</I> paramters that have pre-assigned default values are:
00028   @param targets map of the same size as the input image, in which
00029   targets for the focus of attention are 255 and the rest is
00030   zero. Pass a scalar 0 (the default) if you have no targets to look for.
00031   @param max_time the maximum amount of (simulated) time that the saliency map
00032   should evolve in seconds <I>(default: 0.7)</I>
00033   @param foa_size the size of the focus of attention in pixels.
00034   The default is 1/12 of min(height, width) of the input image.
00035   Pass -1 if you want to use the default.
00036   @param weights Vector of length 3 containing the weights for the
00037   following channels (in this order): <TT>[wIntens, wOrient, wColor]</TT>
00038   <I>(default: [1.0 1.0 1.0])</I>
00039   @param normtype normalization type; see fancynorm.H
00040   <I>(default: 2 = VCXNORM_NORM)</I>
00041   @param smoothMethod method used for smoothing the shapeEstimator masks;
00042   see ShapeEstimatorModes.H; (default: 1 = Gaussian Smoothing)
00043   @param levels Vector of length 6 containing the following parameters:
00044   <TT>[sm_level, level_min, level_max, delta_min, delta_max, nborients]</TT>
00045   <I>(default: [4 2 4 3 4 4])</I>
00046 */
00047 
00048 // //////////////////////////////////////////////////////////////////// //
00049 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00050 // University of Southern California (USC) and the iLab at USC.         //
00051 // See http://iLab.usc.edu for information about this project.          //
00052 // //////////////////////////////////////////////////////////////////// //
00053 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00054 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00055 // in Visual Environments, and Applications'' by Christof Koch and      //
00056 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00057 // pending; application number 09/912,225 filed July 23, 2001; see      //
00058 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00059 // //////////////////////////////////////////////////////////////////// //
00060 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00061 //                                                                      //
00062 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00063 // redistribute it and/or modify it under the terms of the GNU General  //
00064 // Public License as published by the Free Software Foundation; either  //
00065 // version 2 of the License, or (at your option) any later version.     //
00066 //                                                                      //
00067 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00068 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00069 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00070 // PURPOSE.  See the GNU General Public License for more details.       //
00071 //                                                                      //
00072 // You should have received a copy of the GNU General Public License    //
00073 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00074 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00075 // Boston, MA 02111-1307 USA.                                           //
00076 // //////////////////////////////////////////////////////////////////// //
00077 //
00078 // Primary maintainer for this file: Dirk Walther <walther@caltech.edu>
00079 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Matlab/mexSaliencySkin.C $
00080 // $Id: mexSaliencySkin.C 14376 2011-01-11 02:44:34Z pez $
00081 //
00082 
00083 #define FPEXCEPTIONSDISABLED
00084 
00085 #include "Channels/ChannelOpts.H"
00086 #include "Channels/SkinHueChannel.H"
00087 #include "Component/GlobalOpts.H"
00088 #include "Component/ModelManager.H"
00089 #include "Component/ModelOptionDef.H"
00090 #include "Image/fancynorm.H"
00091 #include "Image/LevelSpec.H"
00092 #include "Image/MathOps.H"
00093 #include "Image/Pixels.H"
00094 #include "Image/ShapeOps.H"
00095 #include "Matlab/mexConverts.H"
00096 #include "Media/MediaSimEvents.H"
00097 #include "Neuro/NeuroOpts.H"
00098 #include "Neuro/NeuroSimEvents.H"
00099 #include "Neuro/ShapeEstimator.H"
00100 #include "Neuro/StdBrain.H"
00101 #include "Neuro/VisualCortex.H"
00102 #include "Simulation/SimEventQueueConfigurator.H"
00103 #include "Util/StringConversions.H"
00104 
00105 #include <cmath>
00106 #include <mex.h>
00107 #include <sstream>
00108 #include <string>
00109 #include <vector>
00110 
00111 // only used for debugging
00112 //#define DEBUG
00113 #ifdef DEBUG
00114 #include <iostream>
00115 #endif
00116 
00117 
00118 // ##########################################################################
00119 // ############  The main function
00120 // ##########################################################################
00121 void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
00122 {
00123 
00124 #ifdef DEBUG
00125   LOG_FLAGS |= LOG_FULLTRACE;
00126 #else
00127   LOG_FLAGS &= (~LOG_FULLTRACE);
00128 #endif
00129 
00130   // #### check whether # of params is 1..8 and number of returned values <= 7
00131   if (nrhs < 1)  mexErrMsgTxt("At least one parameter required: image");
00132   if (nrhs > 8) mexErrMsgTxt("Too many parameters (max. 8).");
00133   if (nlhs > 7)  mexErrMsgTxt("Too many return values (max. 7).");
00134 
00135   // counter for parameters
00136   int p = 1;
00137 
00138   // #### first input: the image
00139   Image< PixRGB<byte> > img = mexArray2RGBImage<byte>(prhs[p-1]);
00140   p++;
00141 
00142   // #### targets
00143   Image<byte> targets;
00144   if ((nrhs >= p) && (mxGetNumberOfElements(prhs[p-1]) > 1))
00145     targets = mexArray2Image<byte>(prhs[p-1]);
00146   p++;
00147 
00148   // #### maximum evolution time
00149   double max_time = 0.7;
00150   if (nrhs >= p) max_time = (double)mxGetScalar(prhs[p-1]);
00151   p++;
00152 
00153   // #### foa_size
00154   //int foa_size = -1;
00155   //if (nrhs >= p) foa_size = (int)mxGetScalar(prhs[p-1]);
00156   p++;
00157 
00158   // #### weight for all the channels
00159   /*double wIntens = 1.0, wOrient = 1.0, wColor = 1.0;
00160   if (nrhs >= p)
00161     {
00162       std::vector<double> weights = mexArr2Vector<double>(prhs[p-1], 3);
00163       wIntens = weights[0]; wOrient  = weights[1];
00164       wColor  = weights[2];
00165     }*/
00166   p++;
00167 
00168   // #### norm_type
00169   int norm_type = VCXNORM_FANCY;
00170   if (nrhs >= p) norm_type = (int)mxGetScalar(prhs[p-1]);
00171   p++;
00172 
00173 
00174   // #### smoothing method for shapeEstimator
00175   int smoothMethod = 1;
00176   if (nrhs >= p) smoothMethod = (int)mxGetScalar(prhs[p-1]);
00177   p++;
00178 
00179   // #### which levels?
00180   int sml=4, level_min=2, level_max=4, delta_min=3, delta_max=4, nborients=4;
00181   if (nrhs >= p)
00182     {
00183          std::vector<int> lev = mexArr2Vector<int>(prhs[p-1], 6);
00184          sml = lev[0]; level_min = lev[1]; level_max = lev[2];
00185          delta_min = lev[3]; delta_max = lev[4]; nborients = lev[5];
00186     }
00187   p++;
00188 
00189 
00190   // #### make sure, all parameters are within range
00191   if (max_time < 0.0) mexErrMsgTxt("max_time must be positive.");
00192   if ((norm_type < VCXNORM_NONE))
00193     mexErrMsgTxt("norm_type can only have the following values:\n"
00194                  "0  -  no normalization\n"
00195                  "1  -  maximum normalization\n"
00196                  "2  -  fancy normalization (default)\n"
00197                  "3  -  fancy normalization - fast implementation\n"
00198                  "4  -  fancy normalization with one iteration");
00199   if ((smoothMethod < 0) || (smoothMethod >= NBSHAPEESTIMATORSMOOTHMETHODS))
00200     mexErrMsgTxt("smoothing methods can have the following values:\n"
00201                  "0 - no smoothing\n"
00202                  "1 - Gaussian smoothing (default)\n"
00203                  "2 - Chamfer smoothing");
00204   if (nborients <= 0) mexErrMsgTxt("nborients must be positive");
00205   if (level_min > level_max) mexErrMsgTxt("must have level_min <= level_max");
00206   if (delta_min > delta_max) mexErrMsgTxt("must have delta_min <= delta_max");
00207   if (sml < level_max) mexErrMsgTxt("must have sml >= level_max");
00208 
00209 
00210 #ifdef DEBUG
00211   // This is for debugging only
00212   std::cout << "#### mexSaliency\n";
00213   std::cout << "max_time = " << max_time << "\n";
00214   std::cout << "norm_type = " << norm_type <<"\n";
00215   std::cout << "foa_size = " << foa_size <<"\n";
00216   std::cout << "wIntens = " << wIntens <<"\n";
00217   std::cout << "wOrient = " << wOrient <<"\n";
00218   std::cout << "wColor = " << wColor <<"\n";
00219   std::cout << "nborient = " << nborients <<"\n";
00220   std::cout << "level_min = " << level_min <<"\n";
00221   std::cout << "level_max = " << level_max <<"\n";
00222   std::cout << "delta_min = " << delta_min <<"\n";
00223   std::cout << "delta_max = " << delta_max <<"\n";
00224   std::cout << "sml = " << sml <<"\n";
00225   // end debugging
00226 #endif
00227 
00228 
00229   // get a standard brain:
00230   ModelManager manager("Mex Attention Model");
00231   manager.allowOptions(OPTEXP_CORE);
00232 
00233   manager.setOptionValString(&OPT_UsingFPE,"false");
00234 
00235 #ifdef DEBUG
00236   manager.setOptionValString(&OPT_DebugMode,"true");
00237 #else
00238   manager.setOptionValString(&OPT_DebugMode,"false");
00239 #endif
00240 
00241   nub::soft_ref<SimEventQueueConfigurator>
00242     seqc(new SimEventQueueConfigurator(manager));
00243   manager.addSubComponent(seqc);
00244 
00245   nub::soft_ref<StdBrain> brain(new StdBrain(manager));
00246   manager.addSubComponent(brain);
00247   manager.exportOptions(MC_RECURSE);
00248 
00249   // set a few custom defaults for our possible options:
00250   manager.setOptionValString(&OPT_NumOrientations,
00251                              convertToString(nborients));
00252   manager.setOptionValString(&OPT_LevelSpec,
00253                              convertToString(LevelSpec(level_min,level_max,
00254                                                        delta_min,delta_max,sml)));
00255   manager.setOptionValString(&OPT_MaxNormType,
00256                              convertToString(MaxNormType(norm_type)));
00257   //manager.setOptionValString(&OPT_UseRandom, "true");
00258   manager.setOptionValString(&OPT_UseRandom, "false");
00259   manager.setOptionValString(&OPT_IORtype,"ShapeEst");
00260   manager.setOptionValString(&OPT_ShapeEstimatorMode, "FeatureMap");
00261   manager.setOptionValString(&OPT_ShapeEstimatorSmoothMethod,
00262                              convertToString(ShapeEstimatorSmoothMethod
00263                                              (smoothMethod)));
00264   manager.setOptionValString(&OPT_RawVisualCortexChans,"OIC");
00265 
00266   nub::soft_ref<SimEventQueue> seq = seqc->getQ();
00267 
00268   // get started:
00269   manager.start();
00270 
00271   LFATAL("fixme");
00272 
00273   nub::soft_ref<VisualCortex> vc;///////// = brain->getVC();
00274   /*
00275   nub::soft_ref<SkinHueChannel> hue(new SkinHueChannel(manager));
00276   hue->exportOptions(MC_RECURSE);
00277   vc->addSubChan(hue, "hue");
00278   vc->setSubchanTotalWeight("hue", 5.0);
00279   hue->start();
00280 
00281   vc->setSubchanTotalWeight("color", wColor);
00282   vc->setSubchanTotalWeight("intensity", wIntens);
00283   vc->setSubchanTotalWeight("orientation", wOrient);
00284   */
00285   // let everyone (and in particular our TargetChecker) know about our target mask:
00286   seq->post(rutz::make_shared(new SimEventTargetMask(brain.get(), targets)));
00287 
00288   // post the image to the brain:
00289   seq->post(rutz::make_shared(new SimEventInputFrame(brain.get(), GenericFrame(img), 0)));
00290 
00291   Image<float> salmap;//////////// = vc->getOutput();
00292   inplaceNormalize(salmap, 0.0f, 1.0f);
00293   salmap = rescale(salmap,img.getDims());
00294 
00295   std::vector<Point2D<int> > coords;
00296   std::vector<double> times;
00297   std::vector<int> areas;
00298   ImageSet<float> s_vect;
00299   std::vector<std::string> labelstrings;
00300 
00301   int num_sal = 0;
00302 
00303   const bool forever = (targets.initialized() && (max_time == 0.0));
00304 
00305   // time-loop, evolve
00306   while (((seq->now().secs() < max_time)||forever))
00307     {
00308       (void) seq->evolve();
00309 
00310       // we have a winner
00311       if (SeC<SimEventWTAwinner> e = seq->check<SimEventWTAwinner>(0))
00312         {
00313           const Point2D<int> winner = e->winner().p;
00314 
00315           num_sal++;
00316 
00317           coords.push_back(winner);
00318           times.push_back(seq->now().secs());
00319 
00320           //only do the shape estimator stuff if necessary
00321           if (nlhs > 5)
00322             {
00323               Image<float> semask; std::string selabel; int searea;
00324               if (SeC<SimEventShapeEstimatorOutput>
00325                   ese = seq->check<SimEventShapeEstimatorOutput>(0))
00326                 {
00327                   semask = ese->smoothMask();
00328                   selabel = ese->winningLabel();
00329                   searea = ese->objectArea();
00330                 }
00331 
00332               if (!semask.initialized()) semask.resize(img.getDims(),ZEROS);
00333               s_vect.push_back(semask);
00334 
00335               areas.push_back(searea);
00336 
00337               std::ostringstream os;
00338               os << (seq->now().msecs()) << " ms - " << selabel;
00339               labelstrings.push_back(os.str());
00340             }
00341         } // end if (brain->gotCovertShift())
00342     } // end while
00343 
00344 #ifdef DEBUG
00345   // This is for debugging only
00346   std::cout << "#### mexSaliency\n";
00347   std::cout << "x\ty\tt\n";
00348   for (int i = 0; i < num_sal; i++)
00349     std::cout << coords[i].i << "\t" << coords[i].j << "\t" << times[i] << "\n";
00350   // end debugging
00351 #endif
00352 
00353   // get stopped:
00354   manager.stop();
00355 
00356   // ######## create the return variables
00357   p = 1;
00358 
00359   // #### number of salient spots
00360   if (nlhs >= p) plhs[p-1] = mxCreateScalarDouble(num_sal);
00361   p++;
00362 
00363   // #### x and y coordinates of salient spot
00364   if (nlhs >= p) plhs[p-1] = Point2DVec2mexArr(coords);
00365   p++;
00366 
00367   // #### evolution times
00368   if (nlhs >= p) plhs[p-1] = Vector2mexArr(times);
00369   p++;
00370 
00371   // #### the saliency map
00372   if (nlhs >= p) plhs[p-1] = Image2mexArray(salmap);
00373   p++;
00374 
00375   // #### shape info
00376   mxArray* Labels = mxCreateCellArray(1, &num_sal);
00377   if (nlhs >= p)
00378     {
00379       for (int i = 0; i < num_sal; i++)
00380         {
00381           mxSetCell(Labels, i, mxCreateString(labelstrings[i].c_str()));
00382 #ifdef DEBUG
00383           std::cout << labelstrings[i].c_str() << "\n";
00384 #endif
00385         }
00386       plhs[p-1] = ImgVec2mexArr(s_vect);
00387     }
00388   p++;
00389 
00390   // #### area measures of shape info
00391   if (nlhs >= p) plhs[p-1] = Vector2mexArr(areas);
00392   p++;
00393 
00394   // #### label strings
00395   if (nlhs >= p) plhs[p-1] = Labels;
00396   p++;
00397 
00398  // #### done
00399   return;
00400 }
00401 
00402 // ######################################################################
00403 /* So things look consistent in everyone's emacs... */
00404 /* Local Variables: */
00405 /* indent-tabs-mode: nil */
00406 /* End: */
Generated on Sun May 8 08:05:19 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3