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/SimulationViewerStd.H"
00039
00040 #include "Channels/ChannelMaps.H"
00041 #include "Channels/ChannelOpts.H"
00042 #include "Component/OptionManager.H"
00043 #include "Image/ColorOps.H"
00044 #include "Image/DrawOps.H"
00045 #include "Image/MathOps.H"
00046 #include "Image/PyramidOps.H"
00047 #include "Image/ShapeOps.H"
00048 #include "Image/Transforms.H"
00049 #include "Neuro/AttentionGuidanceMap.H"
00050 #include "Neuro/Brain.H"
00051 #include "Neuro/NeuroOpts.H"
00052 #include "Neuro/NeuroSimEvents.H"
00053 #include "Neuro/SaliencyMap.H"
00054 #include "Neuro/SpatialMetrics.H"
00055 #include "Neuro/TaskRelevanceMap.H"
00056 #include "Neuro/VisualCortex.H"
00057 #include "Simulation/SimEventQueue.H"
00058 #include "Simulation/SimulationOpts.H"
00059 #include "Transport/FrameInfo.H"
00060 #include "Transport/FrameOstream.H"
00061 #include "Util/StringUtil.H"
00062 #include "Util/TransientStatus.H"
00063 #include "Util/sformat.H"
00064
00065
00066 SimulationViewerStd::SimulationViewerStd(OptionManager& mgr,
00067 const std::string& descrName,
00068 const std::string& tagName) :
00069 SimulationViewerAdapter(mgr, descrName, tagName),
00070 SIMCALLBACK_INIT(SimEventSaccadeStatusEye),
00071 SIMCALLBACK_INIT(SimEventSaccadeStatusHead),
00072 SIMCALLBACK_INIT(SimEventSaveOutput),
00073 SIMCALLBACK_INIT(SimEventITOutput),
00074 itsTimeStep(&OPT_SimulationTimeStep, this),
00075 itsLevelSpec(&OPT_LevelSpec, this),
00076 itsMetrics(new SpatialMetrics(mgr)),
00077 itsFontSize(&OPT_SVfontSize, this),
00078 itsSaveTraj(&OPT_SVsaveTraj, this),
00079 itsSaveXcombo(&OPT_SVsaveXcombo, this),
00080 itsSaveYcombo(&OPT_SVsaveYcombo, this),
00081 itsSaveTRMXcombo(&OPT_SVsaveTRMXcombo, this),
00082 itsSaveTRMYcombo(&OPT_SVsaveTRMYcombo, this),
00083 itsSaveTRMmegaCombo(&OPT_SVsaveTRMmegaCombo, this),
00084 itsWarp3D(&OPT_SVwarp3D, this),
00085 itsMegaCombo(&OPT_SVmegaCombo, this),
00086 itsMegaComboZoom(&OPT_SVmegaComboZoom, this),
00087 itsMegaComboTopCMapsOnly(&OPT_SVmegaComboTopCMapsOnly, this),
00088 itsCropFOA(&OPT_SVcropFOA, this),
00089 itsFoveateTraj(&OPT_SVfoveateTraj, this),
00090 itsDisplayFOA(&OPT_SVdisplayFOA, this),
00091 itsDisplayPatch(&OPT_SVdisplayPatch, this),
00092 itsDisplayFOAnum(&OPT_SVdisplayFOAnum, this),
00093 itsDisplayFOALinks(&OPT_SVdisplayFOALinks, this),
00094 itsDisplayEye(&OPT_SVdisplayEye, this),
00095 itsDisplayEyeLinks(&OPT_SVdisplayEyeLinks, this),
00096 itsDisplayHead(&OPT_SVdisplayHead, this),
00097 itsDisplayHeadLinks(&OPT_SVdisplayHeadLinks, this),
00098 itsDisplayTime(&OPT_SVdisplayTime, this),
00099 itsDisplayAdditive(&OPT_SVdisplayAdditive, this),
00100 itsDisplayHighlights(&OPT_SVdisplayHighlights, this),
00101 itsDisplaySMmodulate(&OPT_SVdisplaySMmodulate, this),
00102 itsDisplayBoring(&OPT_SVdisplayBoring, this),
00103 itsDisplayShapeEstimator("SVdisplayShapeEstimator", this, false),
00104 itsColorNormal("SVcolorNormal", this, PixRGB<byte>(255, 255, 0)),
00105 itsColorBoring("SVcolorBoring", this, PixRGB<byte>(127, 0, 0)),
00106 itsColorBlink("SVcolorBlink", this, PixRGB<byte>(0, 128, 255)),
00107 itsColorSaccade("SVcolorSaccade", this, PixRGB<byte>(255, 128, 255)),
00108 itsColorSmoothPursuit("SVcolorSmoothPursuit", this,
00109 PixRGB<byte>(128, 255, 255)),
00110 itsColorLink("SVcolorLink", this, PixRGB<byte>(255, 0, 0)),
00111 itsColorText("SVcolorText", this, PixRGB<byte>(192, 255, 64)),
00112 itsHighlightMax("SVhighlightMax", this, 320),
00113 itsShapeEstimatorBaseContrast("SVShapeEstimatorBaseContrast", this, 0.1F),
00114 itsShapeEstimatorBaseBright("SVShapeEstimatorBaseBright", this, 128),
00115 itsWarp3Dpitch("SVwarp3DInitialPitch", this, -25.0F),
00116 itsWarp3Dyaw("SVwarp3DInitialYaw", this, -15.0F),
00117 itsWarp3DpitchRate("SVwarp3DpitchRate", this, 0.0F),
00118 itsWarp3DyawRate("SVwarp3DyawRate", this, 15.0F),
00119 itsWarp3DpitchMax("SVwarp3DpitchMax", this, 0.0F),
00120 itsWarp3DyawMax("SVwarp3DyawMax", this, 20.0F),
00121 itsHeadRadius(&OPT_HeadMarkerRadius, this),
00122 itsMultiRetinaDepth(&OPT_MultiRetinaDepth, this),
00123 itsFOApsiz("SVfoapsiz", this, 3),
00124 itsFOAthick("SVfoathick", this, 3),
00125 itsFOAlinkThick("SVfoalinkthick", this, 2),
00126 itsFOVpsiz("SVfovpsiz", this, 3),
00127 itsFOVpthick("SVfovpthick", this, 1),
00128 itsFOVthick("SVfovthick", this, 2),
00129 itsFOVlinkThick("SVfovlinkthick", this, 1),
00130 itsHEDpsiz("SVhedpsiz", this, 9),
00131 itsHEDpthick("SVhedpthick", this, 1),
00132 itsHEDthick("SVhedthick", this, 1),
00133 itsHEDlinkThick("SVhedlinkthick", this, 1),
00134 itsUseLargerDrawings(&OPT_SVuseLargerDrawings, this),
00135 itsObsolete1(&OPT_SVxwindow, this),
00136 itsTraj(),
00137 itsFOAshiftNum(0U),
00138 itsCurrFOAmask(),
00139 itsCumFOAmask(),
00140 itsCurrEye(-1, -1),
00141 itsCurrFoveaMask(),
00142 itsCumFoveaMask(),
00143 itsCurrHead(-1, -1),
00144 itsCurrHeadMask(),
00145 itsCumHeadMask(),
00146 itsPrevEye(-1, -1),
00147 itsPrevHead(-1, -1),
00148 itsCurrTime(),
00149 itsEyeSaccade(false),
00150 itsEyeSmoothPursuit(false),
00151 itsHeadSaccade(false),
00152 itsHeadSmoothPursuit(false),
00153 itsEyeBlink(false),
00154 itsMultiTraj(),
00155 itsDims3D(),
00156 itsPitch3D(-1.0e10F),
00157 itsYaw3D(-1.0e10F),
00158 itsHasNewInput(false),
00159 itsFont(SimpleFont::FIXED(10))
00160 {
00161 this->addSubComponent(itsMetrics);
00162 }
00163
00164
00165 SimulationViewerStd::~SimulationViewerStd()
00166 { }
00167
00168
00169 void SimulationViewerStd::reset1()
00170 {
00171
00172 itsTraj.freeMem();
00173 itsFOAshiftNum = 0U;
00174 itsCurrFOAmask.freeMem();
00175 itsCumFOAmask.freeMem();
00176 itsCurrEye = Point2D<int>(-1, -1);
00177 itsCurrFoveaMask.freeMem();
00178 itsCumFoveaMask.freeMem();
00179 itsCurrHead = Point2D<int>(-1, -1);
00180 itsCurrHeadMask.freeMem();
00181 itsCumHeadMask.freeMem();
00182 itsPrevEye = Point2D<int>(-1, -1);
00183 itsPrevHead = Point2D<int>(-1, -1);
00184 itsCurrTime = SimTime::ZERO();
00185 itsEyeSaccade = false;
00186 itsEyeSmoothPursuit = false;
00187 itsHeadSaccade = false;
00188 itsHeadSmoothPursuit = false;
00189 itsEyeBlink = false;
00190 itsMultiTraj.reset();
00191 itsDims3D = Dims();
00192 itsPitch3D = -1.0e10F;
00193 itsYaw3D = -1.0e10F;
00194 itsHasNewInput = false;
00195
00196
00197 SimulationViewerAdapter::reset1();
00198
00199 }
00200
00201
00202 void SimulationViewerStd::start2()
00203 {
00204
00205 if (itsUseLargerDrawings.getVal())
00206 {
00207 itsFOApsiz.setVal(5);
00208 itsFOVpsiz.setVal(5);
00209 itsFOVpthick.setVal(2);
00210 itsHEDpsiz.setVal(12);
00211 itsHEDpthick.setVal(2);
00212 }
00213
00214 itsFont = SimpleFont::fixedMaxWidth(itsFontSize.getVal());
00215 }
00216
00217
00218 void SimulationViewerStd::
00219 doEventRetinaImage(SimEventQueue& q, rutz::shared_ptr<SimEventRetinaImage>& e)
00220 {
00221
00222
00223
00224 itsTraj.resize(itsInput.getDims(), true);
00225
00226
00227 if (itsFoveateTraj.getVal())
00228 itsMultiTraj = buildPyrGaussian(itsInput, 0, itsMultiRetinaDepth.getVal(), 9);
00229
00230
00231
00232
00233 itsHasNewInput = true;
00234 }
00235
00236
00237 void SimulationViewerStd::
00238 doEventWTAwinner(SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e)
00239 {
00240
00241 Image<byte> foaMask;
00242 if (SeC<SimEventShapeEstimatorOutput> ee = q.check<SimEventShapeEstimatorOutput>(this))
00243 {
00244 foaMask = Image<byte>(ee->smoothMask() * 255.0F);
00245 foaMask = inverseRetinal(foaMask);
00246 if (foaMask.isSameSize(itsInput) == false)
00247 LFATAL("Dimensions of FOAmask must match those of input");
00248 }
00249
00250
00251 itsFOAshiftNum = e->shiftNum();
00252
00253 if (foaMask.initialized())
00254 itsCurrFOAmask = foaMask;
00255 else
00256 {
00257
00258 itsCurrFOAmask.resize(itsInput.getDims(), true);
00259 if (itsCurrFOA.isValid())
00260 drawDisk(itsCurrFOAmask, itsCurrFOA.p,
00261 itsMetrics->getFOAradius(), byte(255));
00262 }
00263
00264
00265 if (itsDisplayAdditive.getVal() &&
00266 itsCumFOAmask.initialized() &&
00267 itsCumFOAmask.isSameSize(itsCurrFOAmask))
00268 itsCumFOAmask = takeMax(itsCumFOAmask, itsCurrFOAmask);
00269 else
00270 itsCumFOAmask = itsCurrFOAmask;
00271
00272
00273 if (itsTraj.initialized() == false) return;
00274
00275
00276 if (itsDisplayFOA.getVal() || itsDisplayPatch.getVal()) drawFOA();
00277
00278
00279 if (itsDisplayFOALinks.getVal()) linkFOAs();
00280 }
00281
00282
00283 void SimulationViewerStd::
00284 onSimEventSaccadeStatusEye(SimEventQueue& q, rutz::shared_ptr<SimEventSaccadeStatusEye>& e)
00285 {
00286
00287 itsEyeSaccade = transientStatusIsOn(e->saccadeStatus());
00288 itsEyeSmoothPursuit = transientStatusIsOn(e->smoothPursuitStatus());
00289 itsEyeBlink = transientStatusIsOn(e->blinkStatus());
00290
00291
00292 if (e->position() == itsCurrEye) return;
00293
00294
00295 itsPrevEye = itsCurrEye; itsCurrEye = e->position();
00296
00297
00298 itsCurrFoveaMask.resize(itsInput.getDims(), true);
00299 if (itsCurrEye.isValid())
00300 drawDisk(itsCurrFoveaMask, itsCurrEye,
00301 itsMetrics->getFoveaRadius(), byte(255));
00302
00303
00304 if (itsDisplayAdditive.getVal() &&
00305 itsCumFoveaMask.initialized() &&
00306 itsCumFoveaMask.isSameSize(itsCurrFoveaMask))
00307 itsCumFoveaMask = takeMax(itsCumFoveaMask, itsCurrFoveaMask);
00308 else
00309 itsCumFoveaMask = itsCurrFoveaMask;
00310
00311
00312 if (itsTraj.initialized() == false) return;
00313
00314
00315 if (itsDisplayEye.getVal()) drawEye();
00316
00317
00318 if (itsDisplayEyeLinks.getVal()) linkEyes();
00319 }
00320
00321
00322 void SimulationViewerStd::
00323 onSimEventSaccadeStatusHead(SimEventQueue& q, rutz::shared_ptr<SimEventSaccadeStatusHead>& e)
00324 {
00325
00326 itsHeadSaccade = transientStatusIsOn(e->saccadeStatus());
00327 itsHeadSmoothPursuit = transientStatusIsOn(e->smoothPursuitStatus());
00328
00329
00330 if (e->position() == itsCurrHead) return;
00331
00332
00333 itsPrevHead = itsCurrHead; itsCurrHead = e->position();
00334
00335
00336 itsCurrHeadMask.resize(itsInput.getDims(), true);
00337 if (itsCurrHead.isValid())
00338 drawDisk(itsCurrHeadMask, itsCurrHead, itsHeadRadius.getVal(), byte(255));
00339
00340
00341 if (itsDisplayAdditive.getVal() &&
00342 itsCumHeadMask.initialized() &&
00343 itsCumHeadMask.isSameSize(itsCurrHeadMask))
00344 itsCumHeadMask = takeMax(itsCumHeadMask, itsCurrHeadMask);
00345 else
00346 itsCumHeadMask = itsCurrHeadMask;
00347
00348
00349 if (itsTraj.initialized() == false) return;
00350
00351
00352 if (itsDisplayHead.getVal()) drawHead();
00353
00354
00355 if (itsDisplayHeadLinks.getVal()) linkHeads();
00356 }
00357
00358
00359 void SimulationViewerStd::
00360 onSimEventITOutput(SimEventQueue& q, rutz::shared_ptr<SimEventITOutput>& e)
00361 {
00362 LINFO("The match found is: %s", e->getObjData()->name.c_str());
00363
00364 if (itsTraj.initialized() == false) return;
00365 else
00366 {
00367 drawOutlinedPolygon(itsTraj, e->getObjData()->polygon, PixRGB<byte>(255,128,128), Point2D<int>(0, 0), 0 , 1, 0, 0, 5 );
00368 Point2D<int> postxtobj (e->getObjData()->polygon[3].i, e->getObjData()->polygon[3].j+1);
00369 writeText(itsTraj, postxtobj, e->getObjData()->name.c_str(), PixRGB<byte>(1,1,1),
00370 PixRGB<byte>(255,255,255), SimpleFont::FIXED(10), false, ANCHOR_BOTTOM_LEFT);
00371 }
00372 }
00373
00374
00375 Image< PixRGB<byte> > SimulationViewerStd::getTraj(SimEventQueue& q)
00376 {
00377
00378 if (itsWarp3D.getVal()) {
00379 const SimTime t = q.now();
00380 const SimTime dt = SimTime::computeDeltaT((t - itsCurrTime), itsTimeStep.getVal());
00381 const double dts = dt.secs();
00382
00383 for (SimTime tt = itsCurrTime; tt < t; tt += dt) {
00384 if (itsPitch3D == -1.0e10F) itsPitch3D = itsWarp3Dpitch.getVal();
00385 if (itsYaw3D == -1.0e10F) itsYaw3D = itsWarp3Dyaw.getVal();
00386
00387 itsPitch3D += itsWarp3DpitchRate.getVal() * dts;
00388 itsYaw3D += itsWarp3DyawRate.getVal() * dts;
00389
00390 if (itsYaw3D >= itsWarp3DyawMax.getVal() || itsYaw3D <= -itsWarp3DyawMax.getVal())
00391 itsWarp3DyawRate.setVal(- itsWarp3DyawRate.getVal());
00392 if (itsPitch3D >= itsWarp3DpitchMax.getVal() || itsPitch3D <= -itsWarp3DpitchMax.getVal())
00393 itsWarp3DpitchRate.setVal(- itsWarp3DpitchRate.getVal());
00394 }
00395 }
00396
00397 itsCurrTime = q.now();
00398 if (itsTraj.initialized() == false) return itsTraj;
00399
00400
00401
00402 if (itsDisplayAdditive.getVal() == false)
00403 itsTraj.resize(itsInput.getDims(), true);
00404
00405
00406
00407
00408 Image< PixRGB<byte> > ret;
00409
00410
00411 if (itsDisplayShapeEstimator.getVal())
00412 ret = contrastModulate(itsInput, itsCumFOAmask,
00413 itsShapeEstimatorBaseContrast.getVal(),
00414 itsShapeEstimatorBaseBright.getVal());
00415
00416
00417 if (itsDisplayHighlights.getVal() && itsCumFoveaMask.initialized())
00418 ret = highlightRegions(itsInput, itsCumFoveaMask,
00419 itsHighlightMax.getVal());
00420
00421
00422 if (itsDisplaySMmodulate.getVal())
00423 {
00424 const float fac = 0.001F;
00425 Image<float> sm = rescaleOpt(getMap(q) * fac,
00426 itsTraj.getDims(),
00427 itsDisplayInterp.getVal());
00428 float mi, ma; getMinMax(sm, mi, ma);
00429 LINFO("SM-based contrast modulation range: [%.3f .. %.3f]", mi, ma);
00430
00431 ret = contrastModulate(itsInput, sm, 0.5F, byte(127));
00432 }
00433
00434
00435 if (itsFoveateTraj.getVal())
00436 ret = foveate(itsCumFoveaMask, itsMultiTraj);
00437
00438
00439
00440
00441 if (ret.initialized() == false) ret = itsInput;
00442
00443
00444
00445
00446 if (itsHasNewInput)
00447 {
00448 if (itsDisplayFOA.getVal() || itsDisplayPatch.getVal() ||
00449 itsDisplayFOAnum.getVal()) drawFOA();
00450 if (itsDisplayEye.getVal()) drawEye();
00451 if (itsDisplayHead.getVal()) drawHead();
00452 itsHasNewInput = false;
00453 }
00454
00455
00456 ret = composite(itsTraj, ret, PixRGB<byte>(0, 0, 0));
00457
00458
00459 if (itsMegaCombo.getVal()) ret = drawMegaCombo(q, ret);
00460
00461
00462
00463 else if (itsCropFOA.getVal().isNonEmpty())
00464 {
00465 Dims crop_dims = itsCropFOA.getVal();
00466 Rectangle crect =
00467 Rectangle::tlbrI(itsCurrFOA.p.j - crop_dims.h() / 2,
00468 itsCurrFOA.p.i - crop_dims.w() / 2,
00469 itsCurrFOA.p.j + crop_dims.h() / 2 - 1,
00470 itsCurrFOA.p.i + crop_dims.w() / 2 - 1);
00471 ret = crop(ret, crect, true);
00472 }
00473
00474
00475 else if (itsWarp3D.getVal()) {
00476 drawGrid(ret, ret.getWidth() / 6, ret.getHeight() / 6, 3, 3,
00477 itsColorNormal.getVal());
00478 drawRect(ret, Rectangle::tlbrI(1, 1, ret.getHeight()-2, ret.getWidth()-2),
00479 itsColorNormal.getVal(), 3);
00480 ret = warp3Dmap(ret, getMap(q), itsPitch3D, itsYaw3D, itsDims3D);
00481 }
00482
00483
00484 else if ((itsSaveXcombo.getVal() || itsSaveYcombo.getVal()))
00485 ret = colGreyCombo(ret, getMap(q),
00486 itsSaveXcombo.getVal(), itsDisplayInterp.getVal());
00487
00488
00489 else if ((itsSaveTRMXcombo.getVal() || itsSaveTRMYcombo.getVal()))
00490 {
00491 ret = colGreyCombo(ret, getMap(q),
00492 itsSaveTRMXcombo.getVal(), itsDisplayInterp.getVal());
00493
00494 Image<float> trm;
00495 if (SeC<SimEventTaskRelevanceMapOutput> e =
00496 q.check<SimEventTaskRelevanceMapOutput>(this, SEQ_ANY))
00497 trm = e->trm(1.0F);
00498 else LFATAL("Cannot find a TRM!");
00499
00500
00501 trm = inverseMap(trm);
00502 Image<PixRGB<float> > highlight_trm = toRGB(trm);
00503 highlight_trm = rescaleOpt(trm, itsInput.getDims(), itsDisplayInterp.getVal());
00504
00505
00506 ret = colColCombo(ret, (Image<PixRGB<byte> >)highlight_trm,
00507 itsSaveTRMXcombo.getVal(), itsDisplayInterp.getVal());
00508 }
00509
00510
00511 else if (itsSaveTRMmegaCombo.getVal())
00512 {
00513 Image<float> sm;
00514 if (SeC<SimEventSaliencyMapOutput> e =
00515 q.check<SimEventSaliencyMapOutput>(this, SEQ_ANY))
00516 sm = e->sm(0.0F);
00517 else LFATAL("Cannot find a SM!");
00518 sm = inverseMap(sm);
00519 Image<PixRGB<float> > highlight_sm = toRGB(sm);
00520 highlight_sm = rescaleOpt(highlight_sm,
00521 itsInput.getDims(), itsDisplayInterp.getVal());
00522 Image<PixRGB<float> > xcombo1 = colColCombo(ret, highlight_sm,
00523 1, itsDisplayInterp.getVal());
00524
00525 Image<float> trm;
00526 if (SeC<SimEventTaskRelevanceMapOutput> e =
00527 q.check<SimEventTaskRelevanceMapOutput>(this, SEQ_ANY))
00528 trm = e->trm(1.0F);
00529 else LFATAL("Cannot find a TRM!");
00530 trm = inverseMap(trm);
00531 Image<PixRGB<float> > highlight_trm = toRGB(trm);
00532 highlight_trm = rescaleOpt(highlight_trm,
00533 itsInput.getDims(), itsDisplayInterp.getVal());
00534
00535 Image<float> agm;
00536 if (SeC<SimEventAttentionGuidanceMapOutput> e =
00537 q.check<SimEventAttentionGuidanceMapOutput>(this, SEQ_ANY))
00538 agm = e->agm(0.0F);
00539 else LFATAL("Cannot find a AGM!");
00540 agm = inverseMap(agm);
00541 Image<PixRGB<float> > highlight_agm = toRGB(agm);
00542 highlight_agm = rescaleOpt(highlight_agm,
00543 itsInput.getDims(), itsDisplayInterp.getVal());
00544
00545 Image<PixRGB<float> > xcombo2 = colColCombo(highlight_trm, highlight_agm,
00546 1, itsDisplayInterp.getVal());
00547 ret = colColCombo(xcombo1, xcombo2, 0, itsDisplayInterp.getVal());
00548 }
00549
00550
00551 if (itsDisplayTime.getVal()) drawTime(ret);
00552
00553
00554 return ret;
00555 }
00556
00557
00558 void SimulationViewerStd::
00559 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00560 {
00561 this->save1(e->sinfo());
00562 }
00563
00564
00565 void SimulationViewerStd::save1(const ModelComponentSaveInfo& sinfo)
00566 {
00567
00568
00569 nub::ref<FrameOstream> ofs =
00570 dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs;
00571
00572
00573 SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q;
00574
00575
00576 Image< PixRGB<byte> > res = getTraj(*q);
00577
00578
00579 if (itsSaveTraj.getVal() || itsSaveXcombo.getVal() ||
00580 itsSaveYcombo.getVal() || itsSaveTRMXcombo.getVal() ||
00581 itsSaveTRMYcombo.getVal() || itsSaveTRMmegaCombo.getVal() ||
00582 itsWarp3D.getVal() || itsMegaCombo.getVal())
00583 {
00584 ofs->writeRGB(res, "T",
00585 FrameInfo("SimulationViewerStd trajectory", SRC_POS));
00586 }
00587 }
00588
00589
00590 void SimulationViewerStd::drawFOA()
00591 {
00592 if (itsCurrFOA.isValid() == false) return;
00593
00594
00595 PixRGB<byte> col(itsColorNormal.getVal());
00596 if (itsCurrFOA.boring) col -= itsColorBoring.getVal();
00597
00598
00599 if (itsDisplayFOA.getVal())
00600 drawMaskOutline(itsTraj, itsCurrFOAmask, col, itsFOAthick.getVal(), itsCurrFOA.p, itsMetrics->getFOAradius());
00601
00602
00603 if (itsDisplayFOAnum.getVal())
00604 {
00605 const PixRGB<byte> col2(itsColorText.getVal());
00606 const int rad = 2 + int(itsMetrics->getFOAradius() / M_SQRT2 + 0.5);
00607 const std::string txt = sformat("%d", itsFOAshiftNum);
00608 Point2D<int> pp = itsCurrFOA.p + Point2D<int>(rad + 3 + itsFOAthick.getVal(), rad + 3 + itsFOAthick.getVal());
00609 drawLine(itsTraj, itsCurrFOA.p, pp, col2);
00610 drawLine(itsTraj, pp, pp + Point2D<int>(txt.size() * itsFont.w() + 2, 0), col2);
00611
00612 writeText(itsTraj, pp + Point2D<int>(1, 2), txt.c_str(), col2, PixRGB<byte>(0), itsFont, true);
00613 }
00614
00615
00616 if (itsDisplayPatch.getVal()) drawPatch(itsTraj, itsCurrFOA.p, itsFOApsiz.getVal(), col);
00617 }
00618
00619
00620 void SimulationViewerStd::linkFOAs()
00621 {
00622 if (itsCurrFOA.isValid() == false) return;
00623
00624 PixRGB<byte> col = itsColorLink.getVal();
00625 if (itsPrevFOA.isValid())
00626 {
00627 int d = int(itsPrevFOA.p.distance(itsCurrFOA.p));
00628 if (d > 0) drawArrow(itsTraj, itsPrevFOA.p, itsCurrFOA.p,
00629 col, itsFOAlinkThick.getVal());
00630 }
00631 }
00632
00633
00634 void SimulationViewerStd::drawEye()
00635 {
00636 if (itsCurrEye.isValid() == false) return;
00637
00638 int psiz = itsFOVpsiz.getVal();
00639
00640
00641 PixRGB<byte> col(itsColorNormal.getVal());
00642 if (itsEyeSmoothPursuit) col = itsColorSmoothPursuit.getVal();
00643 if (itsEyeSaccade) { col = itsColorSaccade.getVal(); psiz += 2; }
00644 if (itsEyeBlink) { col = itsColorBlink.getVal(); psiz += 4; }
00645 if (itsCurrFOA.boring) col -= itsColorBoring.getVal();
00646
00647
00648 Rectangle r =
00649 Rectangle::tlbrI(itsCurrEye.j - psiz, itsCurrEye.i - psiz,
00650 itsCurrEye.j + psiz, itsCurrEye.i + psiz);
00651 r = r.getOverlap(itsTraj.getBounds());
00652 drawRect(itsTraj, r, col, itsFOVpthick.getVal());
00653
00654
00655 if (itsDisplayFOA.getVal())
00656 drawMaskOutline(itsTraj, itsCurrFoveaMask, col,
00657 itsFOVthick.getVal(), itsCurrEye,
00658 itsMetrics->getFoveaRadius());
00659 }
00660
00661
00662 void SimulationViewerStd::linkEyes()
00663 {
00664 if (itsCurrEye.isValid() == false) return;
00665
00666 PixRGB<byte> col = itsColorLink.getVal();
00667
00668
00669 if (itsPrevEye.isValid())
00670 drawLine(itsTraj, itsPrevEye, itsCurrEye, col,
00671 itsFOVlinkThick.getVal());
00672 }
00673
00674
00675 void SimulationViewerStd::drawHead()
00676 {
00677 if (itsCurrHead.isValid() == false) return;
00678
00679 int psiz = itsHEDpsiz.getVal();
00680
00681
00682 PixRGB<byte> col(itsColorNormal.getVal());
00683 if (itsHeadSmoothPursuit) col = itsColorSmoothPursuit.getVal();
00684 if (itsHeadSaccade) { col = itsColorSaccade.getVal(); psiz += 3; }
00685 if (itsCurrFOA.boring) col -= itsColorBoring.getVal();
00686
00687
00688 Rectangle r =
00689 Rectangle::tlbrI(itsCurrHead.j - psiz, itsCurrHead.i - psiz,
00690 itsCurrHead.j + psiz, itsCurrHead.i + psiz);
00691 r = r.getOverlap(itsTraj.getBounds());
00692 drawRect(itsTraj, r, col, itsHEDpthick.getVal());
00693
00694
00695 if (itsDisplayFOA.getVal())
00696 drawMaskOutline(itsTraj, itsCurrHeadMask, col, itsHEDthick.getVal(),
00697 itsCurrHead, itsHeadRadius.getVal());
00698 }
00699
00700
00701 void SimulationViewerStd::linkHeads()
00702 {
00703 if (itsCurrHead.isValid() == false) return;
00704
00705 PixRGB<byte> col = itsColorLink.getVal();
00706
00707
00708 if (itsPrevHead.isValid())
00709 drawLine(itsTraj, itsPrevHead, itsCurrHead, col,
00710 itsHEDlinkThick.getVal());
00711 }
00712
00713
00714 void SimulationViewerStd::drawTime(Image<PixRGB<byte> >& image)
00715 {
00716 const std::string txt = sformat(" %dms ", int(itsCurrTime.msecs() + 0.4999));
00717 writeText(image, Point2D<int>(0, 0), txt.c_str(),
00718 PixRGB<byte>(0), PixRGB<byte>(255), itsFont);
00719 }
00720
00721
00722 Image< PixRGB<byte> > SimulationViewerStd::drawMegaCombo(SimEventQueue& q,
00723 const Image< PixRGB<byte> >& in)
00724 {
00725 Image<byte> rr, gg, bb;
00726 std::string rng;
00727 if (itsMapType.getVal().compare("AGM") == 0)
00728 {
00729
00730 Image<float> agm;
00731 if (SeC<SimEventAttentionGuidanceMapOutput> e = q.check<SimEventAttentionGuidanceMapOutput>(this, SEQ_ANY))
00732 agm = e->agm(1.0F);
00733 else LFATAL("Cannot find an AGM!");
00734 agm = inverseMap(agm);
00735
00736
00737 float mini, maxi; getMinMax(agm, mini, maxi);
00738 rng = sformat("AGM=[%.03f .. %.03f]mV", mini * 1000.0F, maxi * 1000.0F);
00739 if (itsMapFactor.getVal() == 0.0F) inplaceNormalize(agm, 0.0F, 255.0F);
00740 else if (itsMapFactor.getVal() != 1.0F) agm *= itsMapFactor.getVal();
00741
00742
00743 Image<float> trm;
00744 if (SeC<SimEventTaskRelevanceMapOutput> ee = q.check<SimEventTaskRelevanceMapOutput>(this, SEQ_ANY))
00745 trm = ee->trm(1.0F);
00746 else
00747 {
00748 LINFO("WARNING: Cannot find a TRM, assuming blank.");
00749 trm.resize(agm.getDims(), false); trm.clear(1.0F);
00750 }
00751
00752 trm = inverseMap(trm);
00753
00754
00755 getMinMax(trm, mini, maxi);
00756 rng += sformat(", TRM=[%.03f .. %.03f]", mini, maxi);
00757
00758
00759
00760 Image<float> trmfac(trm);
00761 inplaceClamp(trmfac, 0.0F, 1.0F);
00762 trmfac *= -1.0F; trmfac += 1.0F;
00763 rr = trmfac * 255.0F;
00764 trmfac = trm;
00765 inplaceClamp(trmfac, 1.0F, 3.0F);
00766 trmfac -= 1.0F;
00767 gg = trmfac * 127.5F;
00768 bb = agm;
00769 }
00770 else
00771 {
00772
00773 Image<float> m = getMap(q);
00774 rr = m; gg = m; bb = m;
00775 }
00776
00777
00778 Image<PixRGB<byte> > cbtmp = rescaleOpt(makeRGB(rr, gg, bb), in.getDims(), itsDisplayInterp.getVal());
00779
00780
00781 cbtmp = composite(itsTraj, cbtmp, PixRGB<byte>(0));
00782 drawRect(cbtmp, Rectangle(Point2D<int>(0, 0), cbtmp.getDims()), PixRGB<byte>(128, 128, 255));
00783 writeText(cbtmp, Point2D<int>(1,1), " Attention Map ", itsColorText.getVal(), PixRGB<byte>(0), itsFont, true);
00784 writeText(cbtmp, Point2D<int>(3, cbtmp.getHeight() - 3), rng.c_str(), itsColorText.getVal(),
00785 PixRGB<byte>(0), SimpleFont::FIXED(6), true, ANCHOR_BOTTOM_LEFT);
00786
00787
00788 Layout< PixRGB<byte> > output = hcat(in, cbtmp);
00789
00790
00791 rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this));
00792 q.request(vcxm);
00793 rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps();
00794
00795
00796 ImageSet< PixRGB<byte> > cmaps;
00797 getMegaComboMaps(chm, cmaps);
00798
00799
00800 if (cmaps.size() > 0)
00801 {
00802 Layout< PixRGB<byte> > lmaps = arrcat(cmaps, output.getWidth() / cmaps[0].getWidth());
00803 return vcat(output, lmaps).render();
00804 }
00805 else
00806 return output.render();
00807 }
00808
00809
00810 void SimulationViewerStd::getMegaComboMaps(const rutz::shared_ptr<ChannelMaps>& chm,
00811 ImageSet< PixRGB<byte> >& cmaps, const uint depth)
00812 {
00813 for (uint i = 0; i < chm->numSubchans(); ++i)
00814 {
00815 rutz::shared_ptr<ChannelMaps> subchm = chm->subChanMaps(i);
00816
00817 NamedImage<float> m = subchm->getMap();
00818 if (m.initialized() == false) m.resize(chm->getMap().getDims(), true);
00819 m = inverseMap(m);
00820 Image< PixRGB<byte> > mm = prepMapForDisplay(m);
00821 cmaps.push_back(mm);
00822
00823 if (itsMegaComboTopCMapsOnly.getVal() == false && subchm->numSubchans() > 0)
00824 getMegaComboMaps(subchm, cmaps, depth + 1);
00825 }
00826 }
00827
00828
00829 Image< PixRGB<byte> > SimulationViewerStd::prepMapForDisplay(const NamedImage<float>& m) const
00830 {
00831 const uint zoomfac = itsMegaComboZoom.getVal();
00832
00833
00834 float mini, maxi; getMinMax(m, mini, maxi);
00835 const std::string rng = sformat("[%.03f .. %.03f]", mini, maxi);
00836
00837
00838
00839 std::vector<std::string> tokens;
00840 split(m.name(), ":", std::back_inserter(tokens));
00841
00842
00843 Image<float> ftmp = rescaleOpt(m, m.getWidth() * zoomfac, m.getHeight() * zoomfac, itsDisplayInterp.getVal());
00844 inplaceNormalize(ftmp, 0.0f, 255.0f); Image<byte> btmp = ftmp;
00845 Image< PixRGB<byte> > cbtmp = btmp;
00846
00847
00848 drawRect(cbtmp, Rectangle(Point2D<int>(0, 0), cbtmp.getDims()), PixRGB<byte>(128, 128, 255));
00849 for (size_t i = 1; i < tokens.size(); ++i)
00850 writeText(cbtmp, Point2D<int>(1, 1+(i-1) * itsFont.h()), tokens[i].c_str(), itsColorText.getVal(),
00851 PixRGB<byte>(0), itsFont, true, ANCHOR_TOP_LEFT);
00852 writeText(cbtmp, Point2D<int>(1, cbtmp.getHeight() - 2), rng.c_str(), itsColorText.getVal(),
00853 PixRGB<byte>(0), SimpleFont::FIXED(6), true, ANCHOR_BOTTOM_LEFT);
00854
00855 return cbtmp;
00856 }
00857
00858
00859 void SimulationViewerStd::drawMaskOutline(Image< PixRGB<byte> >& traj,
00860 const Image<byte> mask,
00861 const PixRGB<byte>& col,
00862 const int thick,
00863 const Point2D<int>& pos,
00864 const int radius)
00865 {
00866 if (traj.initialized() == false) return;
00867
00868
00869
00870 Image<byte> om(mask);
00871 inplaceLowThresh(om, byte(128));
00872 om = contour2D(om);
00873 int w = traj.getWidth(), h = traj.getHeight();
00874 Point2D<int> ppp;
00875 for (ppp.j = 0; ppp.j < h; ppp.j ++)
00876 for (ppp.i = 0; ppp.i < w; ppp.i ++)
00877 if (om.getVal(ppp.i, ppp.j))
00878 drawDisk(traj, ppp, thick, col);
00879
00880 }
00881
00882
00883
00884
00885