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: */