00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "Neuro/VisualCortexEyeMvt.H"
00040
00041 #include "Channels/InputFrame.H"
00042 #include "Channels/ChannelOpts.H"
00043 #include "Component/OptionManager.H"
00044 #include "Image/Kernels.H"
00045 #include "Image/MathOps.H"
00046 #include "Media/MediaOpts.H"
00047 #include "Neuro/NeuroOpts.H"
00048 #include "Neuro/NeuroSimEvents.H"
00049 #include "Psycho/EyeTrace.H"
00050 #include "Simulation/SimEventQueue.H"
00051 #include "Transport/FrameInfo.H"
00052 #include "Transport/FrameOstream.H"
00053 #include "Util/SimTime.H"
00054 #include "Util/sformat.H"
00055 #include "Util/StringUtil.H"
00056
00057 #include <algorithm>
00058 #include <cctype>
00059 #include <cstdio>
00060
00061
00062 VisualCortexEyeMvt::VisualCortexEyeMvt(OptionManager& mgr,
00063 const std::string& descrName,
00064 const std::string& tagName) :
00065 VisualCortex(mgr, descrName, tagName),
00066 SIMCALLBACK_INIT(SimEventClockTick),
00067 SIMCALLBACK_INIT(SimEventRetinaImage),
00068 SIMCALLBACK_INIT(SimEventSaveOutput),
00069 SIMREQHANDLER_INIT(SimReqVCXfeatures),
00070 SIMREQHANDLER_INIT(SimReqVCXmaps),
00071 itsFnames(&OPT_VCEMeyeFnames, this),
00072 itsSigma(&OPT_VCEMsigma, this),
00073 itsForgetFac(&OPT_VCEMforgetFac, this),
00074 itsDelay(&OPT_VCEMdelay, this),
00075 itsUseMax(&OPT_VCEMuseMax, this),
00076 itsSaccadeOnly(&OPT_VCEMsaccadeOnly, this),
00077 itsLevelSpec(&OPT_LevelSpec, this),
00078 itsSaveOutput(&OPT_RawVisualCortexSaveOutput, this),
00079 itsOutputFactor(&OPT_RawVisualCortexOutputFactor, this),
00080 itsMaps(), itsEyeTrace(), itsEyeSample(), itsOutputCache()
00081 { }
00082
00083
00084 VisualCortexEyeMvt::~VisualCortexEyeMvt()
00085 { }
00086
00087
00088 void VisualCortexEyeMvt::start1()
00089 {
00090 VisualCortex::start1();
00091
00092
00093 std::vector<std::string> tok;
00094 split(itsFnames.getVal(), ",", std::back_inserter(tok));
00095 if (tok.empty()) LFATAL("I cannot run without at least one eyetrace.");
00096
00097 for (uint i = 0; i < tok.size(); i ++)
00098 {
00099 LINFO("Instantiating EyeTrace %03d with file '%s'", i, tok[i].c_str());
00100 rutz::shared_ptr<EyeTrace> et(new EyeTrace(tok[i], PixRGB<byte>(255)));
00101 itsEyeTrace.push_back(et);
00102 itsEyeSample.push_back(itsDelay.getVal());
00103 }
00104
00105
00106 itsMaps.reset(itsEyeTrace.size());
00107 }
00108
00109
00110 void VisualCortexEyeMvt::
00111 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& e)
00112 {
00113 const SimTime t = q.now();
00114 const uint sml = itsLevelSpec.getVal().mapLevel();
00115
00116
00117 if (itsForgetFac.getVal() != 1.0f) {
00118 for (uint i = 0; i < itsMaps.size(); ++i) itsMaps[i] *= itsForgetFac.getVal();
00119 itsOutputCache.freeMem();
00120 }
00121
00122
00123 bool keepgoing = true;
00124 while(keepgoing) {
00125 keepgoing = false;
00126
00127
00128 for (uint i = 0; i < itsEyeTrace.size(); i ++)
00129 if (itsEyeTrace[i]->hasData(itsEyeSample[i] - itsDelay.getVal(), t)) {
00130
00131 keepgoing = true;
00132
00133
00134 rutz::shared_ptr<EyeData> data = itsEyeTrace[i]->data(itsEyeSample[i]);
00135
00136 CLDEBUG("Eye trace %03u [%07"ZU"] (%d, %d) at %.1fms",
00137 i, itsEyeSample[i], data->position().i, data->position().j,
00138 itsEyeSample[i] * itsEyeTrace[i]->period().msecs());
00139
00140
00141
00142
00143 float ex, ey;
00144 if (itsSaccadeOnly.getVal()) {
00145 if (data->hasSaccadeTargetData() == false) { ++ itsEyeSample[i]; continue; }
00146 data->getSaccadeTarget(ex, ey);
00147 } else data->getPosition(ex, ey);
00148
00149
00150 Point2D<int> p(int(ex / float(1 << sml) + 0.4999f), int(ey / float(1 << sml) + 0.4999f));
00151
00152
00153 if (itsMaps[i].coordsOk(p))
00154 {
00155 if (itsSigma.getVal() > 0.0f)
00156 {
00157
00158 Image<float> blob = gaussianBlob<float>(itsMaps[i].getDims(), p, itsSigma.getVal(), itsSigma.getVal());
00159
00160
00161 itsMaps[i] = takeMax(itsMaps[i], blob);
00162 }
00163 else
00164
00165 itsMaps[i].setVal(p, itsMaps[i].getVal(p) + 1.0f);
00166
00167
00168 itsOutputCache.freeMem();
00169 }
00170
00171
00172 ++ itsEyeSample[i];
00173 }
00174 }
00175 }
00176
00177
00178 void VisualCortexEyeMvt::
00179 onSimEventRetinaImage(SimEventQueue& q, rutz::shared_ptr<SimEventRetinaImage>& e)
00180 {
00181
00182 if (itsMaps[0].initialized() == false)
00183 {
00184
00185 const int w = e->frame().getWidth() >> itsLevelSpec.getVal().mapLevel();
00186 const int h = e->frame().getHeight() >> itsLevelSpec.getVal().mapLevel();
00187
00188 for (uint i = 0; i < itsMaps.size(); i ++) itsMaps[i].resize(w, h, true);
00189
00190
00191 itsOutputCache.freeMem();
00192 }
00193
00194
00195
00196
00197
00198 q.post(rutz::make_shared(new SimEventVisualCortexOutput(this, getOutput())));
00199 }
00200
00201
00202 void VisualCortexEyeMvt::handleSimReqVCXfeatures(SimEventQueue& q, rutz::shared_ptr<SimReqVCXfeatures>& r)
00203 {
00204
00205 const uint sml = itsLevelSpec.getVal().mapLevel();
00206 const Image<float> out = getOutput();
00207 Point2D<int> p((r->loc().i + sml/2) >> sml, (r->loc().j + sml/2) >> sml);
00208 if (out.coordsOk(p)) r->features().push_back(out.getVal(p));
00209 else r->features().push_back(0.0F);
00210 }
00211
00212
00213 void VisualCortexEyeMvt::handleSimReqVCXmaps(SimEventQueue& q, rutz::shared_ptr<SimReqVCXmaps>& r)
00214 {
00215 r->populateChannelMaps(this);
00216 }
00217
00218
00219 Image<float> VisualCortexEyeMvt::getOutput()
00220 {
00221
00222 if (itsOutputCache.initialized()) return itsOutputCache;
00223
00224
00225 Image<float> out = itsMaps[0];
00226 if (itsUseMax.getVal()) for (uint idx = 1; idx < itsMaps.size(); idx ++) out = takeMax(out, itsMaps[idx]);
00227 else for (uint idx = 1; idx < itsMaps.size(); idx ++) out += itsMaps[idx];
00228
00229
00230 out *= 50.0f * itsOutputFactor.getVal();
00231 float mi, ma; getMinMax(out, mi, ma);
00232 LINFO("Salmap input range is [%f .. %f] nA", mi * 1.0e9F, ma * 1.0e9F);
00233 LINFO("Computed VisualCortex output.");
00234
00235 itsOutputCache = out;
00236
00237 return out;
00238 }
00239
00240
00241 void VisualCortexEyeMvt::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00242 {
00243
00244
00245 nub::ref<FrameOstream> ofs = dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs;
00246
00247
00248 if (itsSaveOutput.getVal())
00249 ofs->writeFloat(getOutput(), FLOAT_NORM_PRESERVE, "VCO",
00250 FrameInfo("visual cortex eyemvt output (input to saliency map)", SRC_POS));
00251 }
00252
00253
00254
00255
00256
00257