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