00001 /*!@file Neuro/PrefrontalCortex.C a human PrefrontalCortex */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 00005 // by the 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: Lior Elazary 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/PrefrontalCortex.C $ 00035 // $Id: PrefrontalCortex.C 13065 2010-03-28 00:01:00Z itti $ 00036 // 00037 00038 #include "Neuro/PrefrontalCortex.H" 00039 00040 #include "Component/OptionManager.H" 00041 #include "Component/ModelOptionDef.H" 00042 #include "Channels/GuidedSearch.H" 00043 #include "Channels/OptimalGains.H" 00044 #include "Image/DrawOps.H" 00045 #include "Learn/Bayes.H" 00046 #include "Media/MediaSimEvents.H" 00047 #include "Media/TestImages.H" 00048 #include "Neuro/NeuroOpts.H" 00049 #include "Neuro/NeuroSimEvents.H" 00050 #include "Neuro/VisualCortex.H" 00051 #include "ObjRec/BayesianBiaser.H" 00052 #include "Simulation/SimEventQueue.H" 00053 00054 // ###################################################################### 00055 // ###################################################################### 00056 // ########## PrefrontalCortex implementation 00057 // ###################################################################### 00058 // ###################################################################### 00059 PrefrontalCortex::PrefrontalCortex(OptionManager& mgr, 00060 const std::string& descrName, 00061 const std::string& tagName) : 00062 SimModule(mgr, descrName, tagName) 00063 { } 00064 00065 // ###################################################################### 00066 PrefrontalCortex::~PrefrontalCortex() 00067 { } 00068 00069 // ###################################################################### 00070 // ###################################################################### 00071 // ########## PrefrontalCortexConfigurator implementation 00072 // ###################################################################### 00073 // ###################################################################### 00074 PrefrontalCortexConfigurator:: 00075 PrefrontalCortexConfigurator(OptionManager& mgr, 00076 const std::string& descrName, 00077 const std::string& tagName) : 00078 ModelComponent(mgr, descrName, tagName), 00079 itsType(&OPT_PrefrontalCortexType, this), 00080 itsPFC(new PrefrontalCortexStub(mgr)) 00081 { 00082 addSubComponent(itsPFC); 00083 } 00084 00085 // ###################################################################### 00086 PrefrontalCortexConfigurator::~PrefrontalCortexConfigurator() 00087 { } 00088 00089 // ###################################################################### 00090 nub::ref<PrefrontalCortex> PrefrontalCortexConfigurator::getPFC() const 00091 { return itsPFC; } 00092 00093 // ###################################################################### 00094 void PrefrontalCortexConfigurator::paramChanged(ModelParamBase* const param, 00095 const bool valueChanged, 00096 ParamClient::ChangeStatus* status) 00097 { 00098 ModelComponent::paramChanged(param, valueChanged, status); 00099 00100 // was that a change of our baby's name? 00101 if (param == &itsType) { 00102 // let's unregister our existing PrefrontalCortex: 00103 removeSubComponent(*itsPFC); 00104 00105 // instantiate a PrefrontalCortex of the appropriate type (when the old 00106 // PrefrontalCortex is destroyed, it will un-export its command-line 00107 // options): 00108 if (itsType.getVal().compare("Stub") == 0) // stub 00109 itsPFC.reset(new PrefrontalCortexStub(getManager())); 00110 else if (itsType.getVal().compare("OG") == 0) // Optimal Gains 00111 itsPFC.reset(new PrefrontalCortexOG(getManager())); 00112 else if (itsType.getVal().compare("GS") == 0) // Guided Search 00113 itsPFC.reset(new PrefrontalCortexGS(getManager())); 00114 else if (itsType.getVal().compare("SB") == 0) // SalBayes 00115 itsPFC.reset(new PrefrontalCortexSB(getManager())); 00116 else 00117 LFATAL("Unknown PrefrontalCortex type %s", itsType.getVal().c_str()); 00118 00119 // add our baby as a subcomponent of us so that it will become 00120 // linked to the manager through us (hopefully we are registered 00121 // with the manager), which in turn will allow it to export its 00122 // command-line options and get configured: 00123 addSubComponent(itsPFC); 00124 00125 // tell the controller to export its options: 00126 itsPFC->exportOptions(MC_RECURSE); 00127 00128 // some info message: 00129 LINFO("Selected PFC of type %s", itsType.getVal().c_str()); 00130 } 00131 } 00132 00133 // ###################################################################### 00134 // ###################################################################### 00135 // ########## PrefrontalCortexStub implementation 00136 // ###################################################################### 00137 // ###################################################################### 00138 PrefrontalCortexStub::PrefrontalCortexStub(OptionManager& mgr, 00139 const std::string& descrName, 00140 const std::string& tagName) : 00141 PrefrontalCortex(mgr, descrName, tagName) 00142 { } 00143 00144 // ###################################################################### 00145 PrefrontalCortexStub::~PrefrontalCortexStub() 00146 { } 00147 00148 // ###################################################################### 00149 // ###################################################################### 00150 // ########## PrefrontalCortexOG implementation 00151 // ###################################################################### 00152 // ###################################################################### 00153 00154 static const ModelOptionDef OPT_PFCOG_stsdfilename = 00155 { MODOPT_ARG_STRING, "PFCOGstsdfilename", &MOC_PFC, OPTEXP_CORE, 00156 "Name of the file to save computed salienceT and salienceD values, " 00157 "so that they could be later combined across several images.", 00158 "stsd-filename", '\0', "<filename>", "" }; 00159 00160 static const ModelOptionDef OPT_PFCOG_DoMax = 00161 { MODOPT_FLAG, "PFCOGdoMax", &MOC_PFC, OPTEXP_CORE, 00162 "Use the max value from the object as a feature or the mean value.", 00163 "pfc-do-max", '\0', "", "false" }; 00164 00165 static const ModelOptionDef OPT_PFCOG_targetMaskObjName = 00166 { MODOPT_ARG_STRING, "PFCOGtargetMaskObjName", &MOC_PFC, OPTEXP_CORE, 00167 "Name of the object used to build the target mask. The mask is " 00168 "built by looking at all objects matching this name. If no name " 00169 "is specified then every object that is in the xml is used to " 00170 "build the target mask. ", 00171 "target-mask-objName", '\0', "<name>", "" }; 00172 00173 static const ModelOptionDef OPT_PFCOG_distractorMaskObjName = 00174 { MODOPT_ARG_STRING, "PFCOGdistractorMaskObjName", &MOC_PFC, OPTEXP_CORE, 00175 "Name of the object used to build the distractor mask. The mask is " 00176 "built by looking at all objects matching this name. If no name " 00177 "is specified then the distractor is build by taking the " 00178 "complement of the target mask", 00179 "distractor-mask-objName", '\0', "<name>", "" }; 00180 00181 namespace { 00182 // a SimEvent to compute salience of target and distractor 00183 class SimReqOGtrain : public SimReqVCXchanVis { 00184 public: 00185 SimReqOGtrain(SimModule* src, const Image<byte>& tmask, 00186 const Image<byte>& dmask, 00187 rutz::shared_ptr<ParamMap> pmap, 00188 const std::string& fname, const bool domax) : 00189 SimReqVCXchanVis(src, rutz::shared_ptr<ChannelVisitor> 00190 (new OptimalGainsFinder(tmask, dmask, pmap, domax))), 00191 itsPmap(pmap), itsFilename(fname) 00192 { } 00193 00194 virtual ~SimReqOGtrain() 00195 { } 00196 00197 virtual void postProcessing(RawVisualCortex *vcx) 00198 { 00199 if (itsFilename.empty() == false) 00200 { 00201 LINFO("Saving sT and sD values to %s", itsFilename.c_str()); 00202 itsPmap->format(itsFilename); 00203 } 00204 } 00205 00206 private: 00207 rutz::shared_ptr<ParamMap> itsPmap; 00208 const std::string itsFilename; 00209 }; 00210 }; 00211 00212 // ###################################################################### 00213 PrefrontalCortexOG::PrefrontalCortexOG(OptionManager& mgr, 00214 const std::string& descrName, 00215 const std::string& tagName) : 00216 PrefrontalCortex(mgr, descrName, tagName), 00217 SIMCALLBACK_INIT(SimEventInputFrame), 00218 SIMCALLBACK_INIT(SimEventVisualCortexOutput), 00219 itsFilename(&OPT_PFCOG_stsdfilename, this), 00220 itsTargetMaskObjName(&OPT_PFCOG_targetMaskObjName, this), 00221 itsDistractorMaskObjName(&OPT_PFCOG_distractorMaskObjName, this), 00222 itsDoMax(&OPT_PFCOG_DoMax, this), 00223 itsTargetMask(), itsDistractorMask() 00224 { } 00225 00226 // ###################################################################### 00227 void PrefrontalCortexOG:: 00228 onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e) 00229 { 00230 GenericFrame gf = e->frame(); 00231 rutz::shared_ptr<GenericFrame::MetaData> 00232 metaData = gf.getMetaData(std::string("SceneData")); 00233 if (metaData.get() != 0) { 00234 rutz::shared_ptr<TestImages::SceneData> sceneData; 00235 sceneData.dyn_cast_from(metaData); 00236 00237 // Train on all objects in the scene 00238 // Build the target and distractor mask, if multiple objects then add 00239 // which ever matches the target string to the target mask, and distractor string to 00240 // distractor mask. If no strings are spacified, then build from all objects and/or distractor 00241 // that is complmant the object 00242 00243 itsDistractorMask = Image<byte>(sceneData->dims, ZEROS); 00244 itsTargetMask = Image<byte>(sceneData->dims, ZEROS); 00245 00246 for (uint i = 0; i < sceneData->objects.size(); i++) { 00247 TestImages::ObjData objData = sceneData->objects[i]; 00248 00249 // get the target mask, either it was provided as a mask image: 00250 if (objData.objmask.initialized()) 00251 { 00252 LINFO("Drawing target mask from B/W mask file data..."); 00253 itsTargetMask += objData.objmask; 00254 } 00255 00256 // ... and/or with a polygon: 00257 if (objData.polygon.empty() == false) { 00258 LINFO("Drawing target mask from polygon data from %s...", objData.name.c_str()); 00259 if (itsTargetMaskObjName.getVal().size() > 0 && 00260 objData.name == itsTargetMaskObjName.getVal()) 00261 drawFilledPolygon(itsTargetMask, objData.polygon, byte(255)); 00262 00263 if (itsTargetMaskObjName.getVal().size() == 0) 00264 drawFilledPolygon(itsTargetMask, objData.polygon, byte(255)); 00265 } 00266 00267 if (itsDistractorMaskObjName.getVal().size() > 0 && 00268 objData.name == itsDistractorMaskObjName.getVal()) 00269 { 00270 LINFO("Drawing distractor mask from polygon data from %s...", objData.name.c_str()); 00271 drawFilledPolygon(itsDistractorMask, objData.polygon, byte(255)); 00272 } 00273 } 00274 00275 if (itsDistractorMaskObjName.getVal().size() == 0) 00276 { 00277 // Create a distractor mask from 255-targetMask: 00278 itsDistractorMask.clear(255); 00279 itsDistractorMask -= itsTargetMask; 00280 } 00281 } 00282 } 00283 00284 // ###################################################################### 00285 void PrefrontalCortexOG:: 00286 onSimEventVisualCortexOutput(SimEventQueue& q, rutz::shared_ptr<SimEventVisualCortexOutput>& e) 00287 { 00288 rutz::shared_ptr<ParamMap> pmap(new ParamMap()); 00289 rutz::shared_ptr<SimReqVCXchanVis> ev(new SimReqOGtrain(this, itsTargetMask, itsDistractorMask, pmap, 00290 itsFilename.getVal(), itsDoMax.getVal())); 00291 LINFO("Requesting training STSD data from VCX..."); 00292 q.request(ev); 00293 00294 // the resulting sT and sD values will be saved to our 00295 // filename in the form of a ParamMap. 00296 } 00297 00298 // ###################################################################### 00299 PrefrontalCortexOG::~PrefrontalCortexOG() 00300 { } 00301 00302 // ###################################################################### 00303 // ###################################################################### 00304 // ########## PrefrontalCortexGS implementation 00305 // ###################################################################### 00306 // ###################################################################### 00307 // ###################################################################### 00308 static const ModelOptionDef OPT_PFCGS_gainsfilename = 00309 { MODOPT_ARG_STRING, "PFCGSgainsfilename", &MOC_PFC, OPTEXP_CORE, 00310 "Name of the file to load biasing gains.", 00311 "gains-filename", '\0', "<filename>", "" }; 00312 00313 namespace { 00314 // a SimEvent to do guided search from a pmap of gains 00315 class SimReqGSbias : public SimReqVCXchanVis { 00316 public: 00317 SimReqGSbias(SimModule* src, rutz::shared_ptr<ParamMap> pmap) : 00318 SimReqVCXchanVis(src, rutz::shared_ptr<ChannelVisitor>(new GuidedSearchBiaser(pmap))) 00319 { } 00320 00321 virtual ~SimReqGSbias() 00322 { } 00323 }; 00324 }; 00325 00326 00327 // ###################################################################### 00328 PrefrontalCortexGS::PrefrontalCortexGS(OptionManager& mgr, 00329 const std::string& descrName, 00330 const std::string& tagName) : 00331 PrefrontalCortex(mgr, descrName, tagName), 00332 SIMCALLBACK_INIT(SimEventInputFrame), 00333 itsFilename(&OPT_PFCGS_gainsfilename, this) 00334 { } 00335 00336 // ###################################################################### 00337 PrefrontalCortexGS::~PrefrontalCortexGS() 00338 { } 00339 00340 // ###################################################################### 00341 void PrefrontalCortexGS:: 00342 onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e) 00343 { 00344 // load the paramap: 00345 rutz::shared_ptr<ParamMap> pmap = ParamMap::loadPmapFile(itsFilename.getVal()); 00346 00347 // post an event with biasing information: 00348 rutz::shared_ptr<SimReqVCXchanVis> ev(new SimReqGSbias(this, pmap)); 00349 q.request(ev); 00350 } 00351 00352 00353 // ###################################################################### 00354 // ###################################################################### 00355 // ########## PrefrontalCortexSB implementation 00356 // ###################################################################### 00357 // ###################################################################### 00358 00359 static const ModelOptionDef OPT_PFCSalBayes_NetworkFile = 00360 { MODOPT_ARG_STRING, "PFCBaysNetFile", &MOC_PFC, OPTEXP_CORE, 00361 "Name of the file to read the computed Bayesian Network", 00362 "pfc-BayesNet-file", '\0', "<filename>", "SalBayes.net" }; 00363 00364 static const ModelOptionDef OPT_PFCSalBayes_ObjToBias = 00365 { MODOPT_ARG(int), "PFCObjectToBiasFor", &MOC_PFC, OPTEXP_CORE, 00366 "The object ID from the database that we should be biasing for.", 00367 "pfc-obj-to-bias", '\0', "<int>", "0" }; 00368 00369 namespace { 00370 // a SimEvent to do SalBayes biasing 00371 class SimReqSBbias : public SimReqVCXchanVis { 00372 public: 00373 SimReqSBbias(SimModule* src, Bayes& b, const int obj) : 00374 SimReqVCXchanVis(src, rutz::shared_ptr<ChannelVisitor>(new BayesianBiaser(b, obj, -1, true))) 00375 { } 00376 00377 virtual ~SimReqSBbias() 00378 { } 00379 }; 00380 }; 00381 00382 // ###################################################################### 00383 PrefrontalCortexSB::PrefrontalCortexSB(OptionManager& mgr, 00384 const std::string& descrName, 00385 const std::string& tagName) : 00386 PrefrontalCortex(mgr, descrName, tagName), 00387 SIMCALLBACK_INIT(SimEventInputFrame), 00388 itsBayesNetFilename(&OPT_PFCSalBayes_NetworkFile, this), 00389 itsObjToBias(&OPT_PFCSalBayes_ObjToBias, this) 00390 { } 00391 00392 // ###################################################################### 00393 void PrefrontalCortexSB::start1() 00394 { 00395 itsBayesNet.reset(new Bayes(0, 0)); //This will be set by the load 00396 if (!itsBayesNet->load(itsBayesNetFilename.getVal().c_str())) 00397 LFATAL("Cannot load database file %s", 00398 itsBayesNetFilename.getVal().c_str()); 00399 00400 PrefrontalCortex::start1(); 00401 } 00402 00403 // ###################################################################### 00404 void PrefrontalCortexSB:: 00405 onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e) 00406 { 00407 const uint obj = uint(itsObjToBias.getVal()); 00408 if (obj < itsBayesNet->getNumClasses()) { 00409 const char* oname = itsBayesNet->getClassName(obj); 00410 LINFO("Biasing VC for '%s'", oname); 00411 00412 // Post the object we are biasing for so that interested people know: 00413 rutz::shared_ptr<SimEventObjectToBias> 00414 eotb(new SimEventObjectToBias(this, oname)); 00415 q.post(eotb); 00416 00417 // Post the bias visitor to blackboard 00418 rutz::shared_ptr<SimReqVCXchanVis> ebv(new SimReqSBbias(this, *itsBayesNet.get(), obj)); 00419 q.request(ebv); 00420 } else { 00421 LINFO("Cannot find objid %i in the database", obj); 00422 LINFO("Available objects are:"); 00423 for (uint i = 0; i < itsBayesNet->getNumClasses(); i++) 00424 LINFO("%i: %s", i, itsBayesNet->getClassName(i)); 00425 LFATAL("Please specify a valid object id"); 00426 } 00427 } 00428 00429 // ###################################################################### 00430 PrefrontalCortexSB::~PrefrontalCortexSB() 00431 { } 00432 00433 /* So things look consistent in everyone's emacs... */ 00434 /* Local Variables: */ 00435 /* indent-tabs-mode: nil */ 00436 /* End: */