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 #include "Neuro/VisualBuffer.H"
00039
00040 #include "Channels/ChannelOpts.H"
00041 #include "Component/OptionManager.H"
00042 #include "Image/DrawOps.H"
00043 #include "Image/FilterOps.H"
00044 #include "Image/MathOps.H"
00045 #include "Image/ShapeOps.H"
00046 #include "Image/Transforms.H"
00047 #include "Image/fancynorm.H"
00048 #include "Media/MediaOpts.H"
00049 #include "Neuro/NeuroOpts.H"
00050 #include "Neuro/Retina.H"
00051 #include "Simulation/SimEventQueue.H"
00052 #include "Util/log.H"
00053
00054
00055 VisualBuffer::VisualBuffer(OptionManager& mgr,
00056 const std::string& descrName,
00057 const std::string& tagName) :
00058 SimModule(mgr, descrName, tagName)
00059 { }
00060
00061
00062 VisualBuffer::~VisualBuffer()
00063 { }
00064
00065
00066 VisualBufferStub::VisualBufferStub(OptionManager& mgr,
00067 const std::string& descrName,
00068 const std::string& tagName) :
00069 VisualBuffer(mgr, descrName, tagName)
00070 { }
00071
00072
00073 VisualBufferStub::~VisualBufferStub()
00074 { }
00075
00076
00077 VisualBufferConfigurator::
00078 VisualBufferConfigurator(OptionManager& mgr,
00079 const std::string& descrName,
00080 const std::string& tagName) :
00081 ModelComponent(mgr, descrName, tagName),
00082 itsVBtype(&OPT_VisualBufferType, this),
00083 itsVB(new VisualBufferStub(mgr))
00084 {
00085 addSubComponent(itsVB);
00086 }
00087
00088
00089 VisualBufferConfigurator::~VisualBufferConfigurator()
00090 { }
00091
00092
00093 nub::ref<VisualBuffer> VisualBufferConfigurator::getVB() const
00094 {
00095 return itsVB;
00096 }
00097
00098
00099 void VisualBufferConfigurator::paramChanged(ModelParamBase* const param,
00100 const bool valueChanged,
00101 ParamClient::ChangeStatus* status)
00102 {
00103 ModelComponent::paramChanged(param, valueChanged, status);
00104
00105
00106 if (param == &itsVBtype) {
00107
00108
00109
00110 removeSubComponent(*itsVB);
00111
00112
00113 if (itsVBtype.getVal().compare("None") == 0 ||
00114 itsVBtype.getVal().compare("Stub") == 0)
00115 itsVB.reset(new VisualBufferStub(getManager()));
00116 else if (itsVBtype.getVal().compare("Std") == 0)
00117 itsVB.reset(new VisualBufferStd(getManager()));
00118 else
00119 LFATAL("Unknown VB type %s", itsVBtype.getVal().c_str());
00120
00121
00122
00123
00124
00125 addSubComponent(itsVB);
00126
00127
00128 itsVB->exportOptions(MC_RECURSE);
00129
00130
00131 LINFO("Selected VB of type %s", itsVBtype.getVal().c_str());
00132 }
00133 }
00134
00135
00136 VisualBufferStd::VisualBufferStd(OptionManager& mgr,
00137 const std::string& descrName,
00138 const std::string& tagName) :
00139 VisualBuffer(mgr, descrName, tagName),
00140 SIMCALLBACK_INIT(SimEventAttentionGuidanceMapOutput),
00141 SIMCALLBACK_INIT(SimEventRetinaImage),
00142 itsFOAradius(&OPT_FOAradius, this),
00143 itsIgnoreBoring(&OPT_VBignoreBoring, this),
00144 itsObjectBased(&OPT_VBobjectBased, this),
00145 itsBufferDims(&OPT_VBdims, this),
00146 itsLevelSpec(&OPT_LevelSpec, this),
00147 itsInputDims(&OPT_InputFrameDims, this),
00148 itsTimePeriod(&OPT_VBtimePeriod, this),
00149 itsDecayFactor(&OPT_VBdecayFactor, this),
00150 itsNormType(&OPT_VBmaxNormType, this),
00151 itsBuffer(), itsSMdims(), itsSaliencyMask(), itsTime(),
00152 itsLastInteractTime(), itsRetinaOffset(0, 0)
00153 { }
00154
00155
00156 void VisualBufferStd::start1()
00157 {
00158
00159 Dims d = itsBufferDims.getVal();
00160 if (d.isNonEmpty())
00161 {
00162 itsBuffer.resize(d, true);
00163 LINFO("Using buffer dims of (%d, %d)", d.w(), d.h());
00164 }
00165 LINFO("Using internal maxnorm of type %s, decay %f",
00166 itsNormType.getValString().c_str(), itsDecayFactor.getVal());
00167 }
00168
00169
00170 VisualBufferStd::~VisualBufferStd()
00171 { }
00172
00173
00174 void VisualBufferStd::
00175 onSimEventRetinaImage(SimEventQueue& q, rutz::shared_ptr<SimEventRetinaImage>& e)
00176 {
00177
00178 itsRetinaOffset = e->offset();
00179 }
00180
00181
00182 void VisualBufferStd::
00183 onSimEventAttentionGuidanceMapOutput(SimEventQueue& q, rutz::shared_ptr<SimEventAttentionGuidanceMapOutput>& e)
00184 {
00185
00186 Image<float> agm = e->agm();
00187
00188
00189
00190
00191 if (isObjectBased() == false)
00192 input(WTAwinner(Point2D<int>(0, 0), q.now(), 0.0, false), agm, Image<byte>());
00193 else if (SeC<SimEventWTAwinner> e = q.check<SimEventWTAwinner>(this))
00194 {
00195 const WTAwinner& win = e->winner();
00196
00197
00198 Image<byte> foaMask;
00199 if (SeC<SimEventShapeEstimatorOutput> e = q.check<SimEventShapeEstimatorOutput>(this))
00200 foaMask = Image<byte>(e->smoothMask() * 255.0F);
00201
00202
00203 input(win, agm, foaMask);
00204 }
00205
00206
00207 this->evolve(q);
00208 }
00209
00210
00211 void VisualBufferStd::input(const WTAwinner& win, const Image<float>& sm,
00212 const Image<byte>& objmask)
00213 {
00214
00215 itsSMdims = sm.getDims();
00216
00217
00218
00219 if (itsBuffer.initialized() == false) {
00220 itsBuffer.resize(itsSMdims, true);
00221 LINFO("Using buffer dims of (%d, %d)", itsSMdims.w(), itsSMdims.h());
00222 }
00223
00224
00225 if (win.boring && itsIgnoreBoring.getVal())
00226 { LINFO("Ignoring boring attention shift"); return; }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 Image<float> maskedsm;
00237 Image<float> mask;
00238
00239 if (itsObjectBased.getVal()) {
00240
00241
00242 Image<byte> maskb;
00243
00244 if (objmask.initialized()) {
00245
00246 maskb = objmask;
00247 inplaceLowThresh(maskb, byte(255));
00248 } else {
00249
00250 maskb.resize(itsInputDims.getVal(), true);
00251 drawDisk(maskb, win.p, itsFOAradius.getVal(), byte(255));
00252 }
00253
00254 maskb = chamfer34(maskb);
00255 mask = maskb;
00256 mask = rescale(mask, sm.getDims());
00257 mask = binaryReverse(mask, 255.0F);
00258 mask = squash(mask, 0.0F, 0.0F, 128.0F, 0.25F, 255.0F, 1.0F);
00259 maskedsm = sm * mask;
00260 } else {
00261
00262 maskedsm = sm;
00263 mask.resize(sm.getDims()); mask.clear(1.0F);
00264 }
00265
00266
00267
00268
00269
00270 Point2D<int> tl = retinalToBuffer(Point2D<int>(0, 0));
00271 Image<float> newbuf(itsBuffer.getDims(), ZEROS);
00272 pasteImage(newbuf, maskedsm, 0.0F, tl);
00273
00274 itsBuffer = takeMax(itsBuffer, newbuf);
00275
00276
00277 internalDynamics();
00278
00279
00280 itsSaliencyMask = Image<byte>(mask * 255.0F);
00281
00282
00283 }
00284
00285
00286 Image<byte> VisualBufferStd::getSaliencyMask() const
00287 { return itsSaliencyMask; }
00288
00289
00290 void VisualBufferStd::evolve(SimEventQueue& q)
00291 {
00292 itsTime = q.now();
00293
00294 if (itsTime - itsLastInteractTime >= itsTimePeriod.getVal())
00295 internalDynamics();
00296
00297
00298
00299 }
00300
00301
00302 void VisualBufferStd::inhibit(const Point2D<int>& loc)
00303 {
00304 Image<float> mask(itsBuffer.getDims(), ZEROS);
00305 drawDisk(mask, loc, itsFOAradius.getVal() >> itsLevelSpec.getVal().mapLevel(), 1.0F);
00306 inhibit(mask);
00307 }
00308
00309
00310 void VisualBufferStd::inhibit(const Image<float>& mask)
00311 {
00312 Image<float> inhib = binaryReverse(mask, 1.0F);
00313 itsBuffer *= inhib;
00314 }
00315
00316
00317 Point2D<int> VisualBufferStd::findMostInterestingTarget(const Point2D<int>& p)
00318 {
00319
00320
00321 Image<float> buf = itsBuffer; float mi, ma; getMinMax(buf, mi, ma);
00322 Image<byte> bin = makeBinary(buf, ma * 0.25F, 0, 1);
00323
00324
00325
00326
00327
00328 Image<byte> dmap(bin.getDims(), ZEROS);
00329 dmap.setVal(p, 255); dmap = chamfer34(dmap);
00330 Image<byte> prod = bin * dmap;
00331 inplaceReplaceVal(prod, 0, 255);
00332
00333 Point2D<int> minp; byte minval;
00334 findMin(prod, minp, minval);
00335
00336
00337
00338 Image<byte> obj; flood(bin, obj, minp, byte(1), byte(1));
00339 Image<float> objf = itsBuffer * obj;
00340
00341 return centroid(objf);
00342 }
00343
00344
00345 Point2D<int> VisualBufferStd::findMostInterestingTargetLocMax(const Point2D<int>& p)
00346 {
00347
00348
00349 Image<float> buf = lowPass9(itsBuffer);
00350 float mi, ma; getMinMax(buf, mi, ma);
00351 float thresh = ma * 0.25F;
00352
00353
00354
00355
00356
00357
00358 int w = buf.getWidth(), h = buf.getHeight();
00359 Point2D<int> best(-1, -1); float bestdist(1.0e10);
00360 for (int j = 1; j < h - 1; j ++)
00361 for (int i = 1; i < w - 1; i ++)
00362 {
00363 int index = i + w * j;
00364 float val = buf.getVal(index);
00365 if (val >= thresh &&
00366 val > buf.getVal(index - w) &&
00367 val > buf.getVal(index + w) &&
00368 val > buf.getVal(index - 1) &&
00369 val > buf.getVal(index + 1) &&
00370 p.distance(Point2D<int>(i, j)) < bestdist)
00371 { best.i = i; best.j = j; bestdist = p.distance(best); }
00372 }
00373 return best;
00374 }
00375
00376
00377 Image<float> VisualBufferStd::getBuffer() const
00378 { return itsBuffer; }
00379
00380
00381 Point2D<int> VisualBufferStd::retinalToBuffer(const Point2D<int>& p) const
00382 {
00383 return retinalToVisualBuffer(p, itsRetinaOffset, itsLevelSpec.getVal().mapLevel(), itsSMdims, itsBuffer.getDims());
00384 }
00385
00386
00387 Point2D<int> VisualBufferStd::bufferToRetinal(const Point2D<int>& p) const
00388 {
00389 return visualBufferToRetinal(p, itsRetinaOffset, itsLevelSpec.getVal().mapLevel(), itsSMdims, itsBuffer.getDims());
00390 }
00391
00392
00393 bool VisualBufferStd::isObjectBased() const
00394 { return itsObjectBased.getVal(); }
00395
00396
00397 void VisualBufferStd::internalDynamics()
00398 {
00399 float mi, ma; getMinMax(itsBuffer, mi, ma);
00400 itsBuffer = maxNormalize(itsBuffer, 0.0F, 0.0F, itsNormType.getVal());
00401 inplaceNormalize(itsBuffer, mi, ma);
00402 if (itsDecayFactor.getVal() != 1.0F) itsBuffer *= itsDecayFactor.getVal();
00403 itsLastInteractTime = itsTime;
00404 }
00405
00406
00407
00408
00409
00410
00411