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