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/SimulationViewerEyeHand.H"
00040
00041 #include "Channels/ChannelBase.H"
00042 #include "Channels/ChannelOpts.H"
00043 #include "Component/OptionManager.H"
00044 #include "Component/ModelOptionDef.H"
00045 #include "Image/ColorOps.H"
00046 #include "Image/CutPaste.H"
00047 #include "Image/DrawOps.H"
00048 #include "Image/FilterOps.H"
00049 #include "Image/MathOps.H"
00050 #include "Image/Transforms.H"
00051 #include "Image/ShapeOps.H"
00052 #include "Neuro/NeuroOpts.H"
00053 #include "Neuro/NeuroSimEvents.H"
00054 #include "Neuro/SpatialMetrics.H"
00055 #include "Psycho/EyeData.H"
00056 #include "Psycho/HandData.H"
00057 #include "Simulation/SimEventQueue.H"
00058 #include "Transport/FrameInfo.H"
00059 #include "Transport/FrameOstream.H"
00060 #include "Util/sformat.H"
00061 #include "rutz/trace.h"
00062
00063 #include <fstream>
00064 #include <iostream>
00065
00066
00067 const ModelOptionDef OPT_SMhistoryQlen =
00068 { MODOPT_ARG(uint), "SMhistoryQ", &MOC_DISPLAY, OPTEXP_CORE,
00069 "Keep a historical queue of salieny maps (one per new input frame), "
00070 "and report the history of saliency values over the entire queue "
00071 "and at a saccade target location, for each saccade",
00072 "sm-history-qlen", '\0', "<uint>", "0" };
00073
00074
00075
00076 SimulationViewerEyeHand::
00077 SimulationViewerEyeHand(OptionManager& mgr, const std::string& descrName,
00078 const std::string& tagName) :
00079 SimulationViewer(mgr, descrName, tagName),
00080 SIMCALLBACK_INIT(SimEventClockTick),
00081 SIMCALLBACK_INIT(SimEventSaveOutput),
00082 itsMetrics(new SpatialMetrics(mgr)),
00083 itsSaveTraj(&OPT_SVsaveTraj, this),
00084 itsDelayCacheSize(&OPT_SVEMdelayCacheSize, this),
00085 itsMaxCacheSize(&OPT_SVEMmaxCacheSize, this),
00086 itsSampleAtStart(&OPT_SVEMsampleAtStart, this),
00087 itsDisplaySacNum(&OPT_SVEMdisplaySacNum, this),
00088 itsDisplayPatch(&OPT_SVdisplayPatch, this),
00089 itsPatchSize(&OPT_SVpatchSize, this),
00090 itsEraseMarker(&OPT_SVeraseMarker, this),
00091 itsDisplayFOA(&OPT_SVdisplayFOA, this),
00092 itsLevelSpec(&OPT_LevelSpec, this),
00093 itsOutFname(&OPT_SVEMoutFname, this),
00094 itsPriorRandomDistro(&OPT_SVEMpriorRandomDistro, this),
00095 itsUseSaccadeInBlink(&OPT_SVEMuseSaccadeInBlink, this),
00096 itsUseDiagColor(&OPT_SVEMuseDiagColors, this),
00097 itsLabelEyePatch(&OPT_SVEMlabelEyePatch, this),
00098 itsNumRandomSamples(&OPT_SVEMnumRandomSamples, this),
00099 itsMaxComboWidth(&OPT_SVEMmaxComboWidth, this),
00100 itsSMhistoryQlen(&OPT_SMhistoryQlen, this),
00101 itsDisplayHand(&OPT_SVHandDisplay, this),
00102 itsSaveCombo(&OPT_SVEMsaveMegaCombo, this),
00103 itsDelayCache(), itsMaxCache(), itsHeadSM(),
00104 itsDrawings(), itsCurrTime(), itsFrameNumber(-1),
00105 itsHeaderCrafted(false), itsOutFields(), itsEyeStyles(),
00106 itsEyeTargets(), itsHandTargets(), itsSMhistory(), itsOutFile(0),
00107 itsRandFile(0),itsRawToRetOffset()
00108 {
00109 GVX_TRACE(__PRETTY_FUNCTION__);
00110
00111 this->addSubComponent(itsMetrics);
00112
00113
00114 LINFO("NOTE: disabling IOR and SE, selecting FixedSaccadeController");
00115 getManager().setOptionValString(&OPT_IORtype, "None");
00116 getManager().setOptionValString(&OPT_ShapeEstimatorMode, "None");
00117
00118
00119 getManager().setOptionValString(&OPT_EyeHeadControllerType, "EyeTrack");
00120
00121
00122 getManager().setOptionValString(&OPT_HandControllerType, "HandTrack");
00123
00124
00125
00126 getManager().setOptionValString(&OPT_SVdisplayAdditive, "false");
00127 }
00128
00129
00130 SimulationViewerEyeHand::~SimulationViewerEyeHand()
00131 {
00132 GVX_TRACE(__PRETTY_FUNCTION__);
00133 }
00134
00135
00136 void SimulationViewerEyeHand::start1()
00137 {
00138 GVX_TRACE(__PRETTY_FUNCTION__);
00139
00140 if (itsDelayCacheSize.getVal())
00141 itsDelayCache.setMaxSize(itsDelayCacheSize.getVal());
00142
00143 if (itsMaxCacheSize.getVal())
00144 itsMaxCache.setMaxSize(itsMaxCacheSize.getVal());
00145
00146
00147 if (itsOutFname.getVal().empty() == false) {
00148 if (itsOutFile) delete itsOutFile;
00149 itsOutFile = new std::ofstream(itsOutFname.getVal().c_str());
00150 if (itsOutFile->is_open() == false)
00151 LFATAL("Cannot open '%s' for writing", itsOutFname.getVal().c_str());
00152 }
00153
00154
00155 if (itsPriorRandomDistro.getVal().empty() == false) {
00156 if (itsRandFile) delete itsRandFile;
00157 itsRandFile = new std::ifstream(itsPriorRandomDistro.getVal().c_str());
00158 if (itsRandFile->is_open() == false)
00159 LFATAL("Cannot open '%s' for reading",
00160 itsPriorRandomDistro.getVal().c_str());
00161 else {
00162 while (! itsRandFile->eof()) {
00163 Point2D<int> pr;
00164 (*itsRandFile) >> pr.i >> pr.j;
00165 randPoints.push_back(pr);
00166 }
00167 itsRandFile->close();
00168 }
00169 }
00170
00171
00172 if (itsSMhistoryQlen.getVal())
00173 itsSMhistory.setMaxSize(itsSMhistoryQlen.getVal());
00174
00175 SimulationViewer::start1();
00176 }
00177
00178
00179 void SimulationViewerEyeHand::stop1()
00180 {
00181 GVX_TRACE(__PRETTY_FUNCTION__);
00182
00183 if (itsOutFile) {delete itsOutFile; itsOutFile = 0;}
00184 if (itsRandFile) {delete itsRandFile; itsRandFile = 0;}
00185 }
00186
00187
00188 void SimulationViewerEyeHand::
00189 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& ect)
00190 {
00191
00192 itsCurrTime = q.now();
00193
00194
00195 bool gotnewinput = false;
00196 if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this)) {
00197 itsDrawings.resize(e->frame().getDims(), true);
00198 gotnewinput = true;
00199 itsFrameNumber++;
00200
00201 }
00202
00203
00204 const Image<float> currsm = getMap(q, false);
00205
00206
00207
00208
00209
00210 if (itsDelayCacheSize.getVal())
00211 {
00212
00213 itsDelayCache.push_back(currsm);
00214
00215
00216 if (int(itsDelayCache.size()) >= itsDelayCacheSize.getVal())
00217 itsHeadSM = itsDelayCache.front();
00218 else
00219 itsHeadSM.resize(currsm.getDims(), true);
00220 }
00221 else
00222 itsHeadSM = currsm;
00223
00224
00225
00226 if (itsSMhistoryQlen.getVal() && gotnewinput)
00227 itsSMhistory.push_back(itsHeadSM);
00228
00229
00230 if (itsMaxCacheSize.getVal()) itsMaxCache.push_back(itsHeadSM);
00231
00232
00233
00234 SeC<SimEventRetinaImage> retev = q.check<SimEventRetinaImage>(this, SEQ_ANY);
00235 if (retev.is_valid() == false)
00236 LFATAL("I need some SimEventRetinaImage in the queue to function.");
00237
00238 itsRawToRetOffset = retev->offset();
00239
00240
00241
00242
00243
00244 SeC<SimEventHandTrackerData> ee = q.check<SimEventHandTrackerData>(this);
00245
00246 while(ee.is_valid()) {
00247
00248 const rutz::shared_ptr<HandData> trackCurrPos = ee->data();
00249 const uint tnum = ee->trackerNum();
00250 const std::string tfn = ee->trackerFilename();
00251
00252 if (itsHandStyles.size() <= tnum) {
00253 itsHandStyles.resize(tnum+1);
00254
00255 itsHandStyles[tnum].pSize = itsPatchSize.getVal();
00256 itsHandStyles[tnum].col = ee->trackerColor();
00257
00258
00259
00260
00261 itsHandStyles[tnum].label = tfn.substr(tfn.find("data")+5,2);
00262 }
00263
00264
00265 if (itsDisplayHand.getVal()) {
00266
00267
00268 if (itsEraseMarker.getVal()) itsDrawings.resize(retev->frame().getDims(), true);
00269
00270
00271 drawHand(trackCurrPos, tnum);
00272 }
00273
00274
00275
00276 extraSampleProcessing(trackCurrPos);
00277
00278
00279 ee = q.check<SimEventHandTrackerData>(this);
00280 }
00281
00282
00283
00284
00285
00286 SeC<SimEventEyeTrackerData> e = q.check<SimEventEyeTrackerData>(this);
00287
00288 while(e.is_valid()) {
00289
00290 const rutz::shared_ptr<EyeData> trackCurrPos = e->data();
00291 const uint tnum = e->trackerNum();
00292 const std::string tfn = e->trackerFilename();
00293
00294 if (itsEyeStyles.size() <= tnum) {
00295 itsEyeStyles.resize(tnum+1);
00296
00297 itsEyeStyles[tnum].pSize = itsPatchSize.getVal();
00298 itsEyeStyles[tnum].col = e->trackerColor();
00299
00300
00301
00302
00303 itsEyeStyles[tnum].label = tfn.substr(tfn.find("data")+5,2);
00304 }
00305
00306
00307 if (itsDisplayPatch.getVal())
00308 {
00309
00310 if (itsEraseMarker.getVal()) itsDrawings.resize(retev->frame().getDims(), true);
00311
00312
00313 drawEye(trackCurrPos, tnum);
00314 }
00315
00316
00317
00318 extraSampleProcessing(trackCurrPos);
00319
00320 bool isUsableTrace = true;
00321
00322 if (itsUseSaccadeInBlink.getVal() == false && trackCurrPos->isInBlink() == true) isUsableTrace = false;
00323
00324
00325
00326 if (trackCurrPos->hasSaccadeTargetData() && isUsableTrace)
00327 {
00328
00329 Point2D<int> dp = rawToRet(trackCurrPos->saccadeTarget());
00330
00331 CLINFO("**** Tracker %03d: Saccade to (%d, %d) at %.1fms ****",
00332 tnum, dp.i, dp.j, q.now().msecs());
00333
00334 if (itsDrawings.coordsOk(dp) == false)
00335 CLINFO("Tracker %03d: Saccade target (%d, %d) out of bounds "
00336 "-- IGNORING", tnum, dp.i, dp.j);
00337 else
00338
00339
00340
00341 itsEyeTargets[tnum] = trackCurrPos;
00342 }
00343
00344
00345
00346
00347
00348
00349 std::map<int, rutz::shared_ptr<EyeData> >::iterator
00350 itr = itsEyeTargets.find(tnum);
00351
00352 if (itr != itsEyeTargets.end() && isUsableTrace &&
00353 (itsSampleAtStart.getVal() || trackCurrPos->isInSaccade() == false))
00354 {
00355
00356 const rutz::shared_ptr<EyeData> trackEventSample = itr->second;
00357 itsEyeTargets.erase(itr);
00358
00359
00360 if(!(trackEventSample->hasSaccadeTargetData()) )
00361 LFATAL("Tracker %03d: Marked event has incomplete targeting data.", tnum);
00362
00363 Point2D<int> trackerTarget = rawToRet(trackEventSample->saccadeTarget());
00364
00365 LINFO("Tracker %03d [%s]: Taking saccade samples at (%d, %d) at time %.1fms",
00366 tnum, tfn.c_str(), trackerTarget.i, trackerTarget.j, q.now().msecs());
00367
00368
00369 if (itsDisplayFOA.getVal()) drawFOA(trackerTarget, tnum);
00370
00371
00372 if (itsDisplaySacNum.getVal())
00373 {
00374 if (tnum == 0) {
00375 std::string fld("typenum");
00376 if (trackCurrPos->hasMetaData(fld.c_str()))
00377 writeText(itsDrawings, Point2D<int>(0, 0),
00378 sformat(" %1g ",
00379 trackEventSample->getMetaDataField("typenum")).c_str(),
00380 PixRGB<byte>(1, 1, 1));
00381 else
00382 LFATAL("--svem-display-sacnum does not have numbered saccades available");
00383 }
00384 else
00385 LFATAL("--svem-display-sacnum only supported with 1 tracker");
00386 }
00387
00388 if (itsOutFile) {
00389 LINFO("writing to file %s........", itsOutFname.getVal().c_str());
00390 (*itsOutFile) << craftSVEMOutput(tfn, trackEventSample) << std::endl;
00391 }
00392 }
00393
00394
00395 e = q.check<SimEventEyeTrackerData>(this);
00396 }
00397
00398
00399 }
00400
00401
00402 void SimulationViewerEyeHand::drawEye(const rutz::shared_ptr<EyeData> rawPos, const uint tN)
00403 {
00404
00405
00406 Point2D<int> currPos = rawToRet(rawPos->position());
00407
00408
00409
00410 PixRGB<byte> col;
00411
00412
00413
00414
00415 if (!itsUseDiagColor.getVal())
00416 {
00417 col = itsEyeStyles[tN].col;
00418
00419 if (rawPos->isInSaccade()) col += byte(64);
00420 if (rawPos->isInBlink()) col -= byte(128);
00421 }
00422 else
00423 {
00424 byte r = 1, g = 1, b = 1;
00425 if (rawPos->isInSaccade()) g = 255;
00426 else if (rawPos->isInSmoothPursuit())
00427 {r = 255;b = 255;}
00428 else if (rawPos->isInFixation()) b = 255;
00429 if (rawPos->isInCombinedSaccade()) {b = 255;g = 255;}
00430
00431 col = PixRGB<byte>(r,g,b);
00432 if (rawPos->isInBlink()) col-=byte(128);
00433 }
00434 drawPatchBB(itsDrawings, currPos, itsEyeStyles[tN].pSize,
00435 col, PixRGB<byte>(1));
00436
00437
00438 if(itsLabelEyePatch.getVal()) {
00439 writeText(itsDrawings, currPos+itsEyeStyles[tN].pSize/2,
00440 itsEyeStyles[tN].label.c_str(),
00441 PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
00442 SimpleFont::FIXED(10), true);
00443 }
00444 }
00445
00446
00447 void SimulationViewerEyeHand::drawHand(const rutz::shared_ptr<HandData> rawPos, const uint tN)
00448 {
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 const Dims dims = itsDrawings.getDims();
00468
00469
00470
00471
00472 const Dims numgrid (80,60);
00473 const Dims grid (dims.w()/numgrid.w(),dims.h()/numgrid.h());
00474
00475 PixRGB<byte> colTransp = PixRGB<byte> ( 0, 0, 0);
00476 PixRGB<byte> colRed = PixRGB<byte> (255, 0, 0);
00477 PixRGB<byte> colB;
00478
00479
00480 if (rawPos->isValid()) {
00481
00482 int rawX = rawPos->getX();
00483 int rawY = rawPos->getY();
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 Point2D<int> X1 (getGridCoord(grid, 2, numgrid.h()-1));
00495 Point2D<int> X2 (getGridCoord(grid, numgrid.w()-1, numgrid.h()-1));
00496 Point2D<int> XC ((127*(X2.i-X1.i)/255)+X1.i,X1.j);
00497 Point2D<int> XD (0,grid.h()/2);
00498 Point2D<int> Y1 (getGridCoord(grid, 1, 1));
00499 Point2D<int> Y2 (getGridCoord(grid, 1, numgrid.h()-2));
00500 Point2D<int> YC (grid.w(),(127*(Y2.j-Y1.j)/255)+Y1.j);
00501 Point2D<int> YD (grid.w()/2,0);
00502
00503 Point2D<int> X_ ((rawX*(X2.i-X1.i)/255)+X1.i, dims.h()-grid.h());
00504 Point2D<int> Y_ (grid.w(), (rawY*(Y2.j-Y1.j)/255)+Y1.j);
00505
00506
00507 const PixRGB<byte> colWhite (255,255,255);
00508
00509 drawLine(itsDrawings, X1, X2, colWhite);
00510 drawLine(itsDrawings, X1-XD, X1+XD, colWhite);
00511 drawLine(itsDrawings, XC-XD, XC+XD, colWhite);
00512 drawLine(itsDrawings, X2-XD, X2+XD, colWhite);
00513
00514 drawLine(itsDrawings, Y1, Y2, colWhite);
00515 drawLine(itsDrawings, Y1-YD, Y1+YD, colWhite);
00516 drawLine(itsDrawings, YC-YD, YC+YD, colWhite);
00517 drawLine(itsDrawings, Y2-YD, Y2+YD, colWhite);
00518
00519
00520
00521 drawPatchBB(itsDrawings, X_, itsHandStyles[tN].pSize,
00522 colWhite, PixRGB<byte>(1));
00523 drawPatchBB(itsDrawings, Y_, itsHandStyles[tN].pSize,
00524 colWhite, PixRGB<byte>(1));
00525
00526
00527 if (rawPos->isButtonEmpty() == false) {
00528 for (uint i = 0; i < rawPos->numButton(); i++) {
00529
00530 if (rawPos->isPressed(i))
00531 colB = colRed;
00532 else
00533 colB = colTransp;
00534
00535
00536
00537
00538
00539 writeText(itsDrawings,
00540 Point2D<int>(getGridCoord(grid, 3*i+10, numgrid.h()-5)),
00541 sformat("%2d",i+1).c_str(),
00542 PixRGB<byte>(255),
00543 colB,
00544 SimpleFont::FIXED(10),
00545 false);
00546
00547
00548
00549 }
00550 }
00551 }
00552
00553
00554 writeText(itsDrawings,
00555 Point2D<int>(getGridCoord(grid, 7, numgrid.h()-8)),
00556 sformat("Mouse: ").c_str(),
00557 PixRGB<byte>(255),
00558 PixRGB<byte>(0),
00559 SimpleFont::FIXED(10),
00560 false);
00561 if (rawPos->isMouseValid()) {
00562
00563 Point2D<int> mousePos;
00564
00565
00566 if (rawPos->getNativeX() > 0 && rawPos->getNativeY() > 0)
00567
00568
00569
00570
00571
00572 if (rawPos->getNativeX() == 1024)
00573 mousePos=Point2D<int>((rawPos->getMouseX()*583/rawPos->getNativeX())+37,
00574 (rawPos->getMouseY()*438/rawPos->getNativeY())+15);
00575 else if (rawPos->getNativeX() == 800)
00576 mousePos=Point2D<int>((rawPos->getMouseX()*602/rawPos->getNativeX())+11,
00577 (rawPos->getMouseY()*439/rawPos->getNativeY())+11);
00578 else
00579 mousePos=Point2D<int>(rawPos->getMouseX()*dims.w()/rawPos->getNativeX(),
00580 rawPos->getMouseY()*dims.h()/rawPos->getNativeY());
00581 else
00582 mousePos=Point2D<int>(rawPos->getMouseX(), rawPos->getMouseY());
00583
00584
00585 drawPatchBB(itsDrawings, mousePos, itsHandStyles[tN].pSize,
00586 PixRGB<byte>(127), PixRGB<byte>(1));
00587
00588
00589
00590 colB = rawPos->getMouseBL()?colRed:colTransp;
00591 writeText(itsDrawings,
00592 Point2D<int>(getGridCoord(grid, 15, numgrid.h()-8)),
00593 sformat("L").c_str(),
00594 PixRGB<byte>(255),
00595 colB,
00596 SimpleFont::FIXED(10),
00597 false);
00598 colB = rawPos->getMouseBM()?colRed:colTransp;
00599 writeText(itsDrawings,
00600 Point2D<int>(getGridCoord(grid, 18, numgrid.h()-8)),
00601 sformat("M").c_str(),
00602 PixRGB<byte>(255),
00603 colB,
00604 SimpleFont::FIXED(10),
00605 false);
00606 colB = rawPos->getMouseBR()?colRed:colTransp;
00607 writeText(itsDrawings,
00608 Point2D<int>(getGridCoord(grid, 21, numgrid.h()-8)),
00609 sformat("R").c_str(),
00610 PixRGB<byte>(255),
00611 colB,
00612 SimpleFont::FIXED(10),
00613 false);
00614 }
00615 else {
00616 writeText(itsDrawings,
00617 Point2D<int>(getGridCoord(grid, 15, numgrid.h()-8)),
00618 sformat("n/a").c_str(),
00619 PixRGB<byte>(255),
00620 PixRGB<byte>(0),
00621 SimpleFont::FIXED(10),
00622 false);
00623 }
00624
00625
00626 writeText(itsDrawings,
00627 Point2D<int>(getGridCoord(grid,25,numgrid.h()-8)),
00628 sformat("Key:").c_str(),
00629 PixRGB<byte>(255),
00630 PixRGB<byte>(0),
00631 SimpleFont::FIXED(10),
00632 false);
00633 if (!rawPos->isKeyboardEmpty()) {
00634
00635 writeText(itsDrawings,
00636 Point2D<int>(getGridCoord(grid,31,numgrid.h()-8)),
00637 sformat(" %s ",rawPos->getKeyboard()).c_str(),
00638
00639 PixRGB<byte>(255),
00640 PixRGB<byte>(0),
00641 SimpleFont::FIXED(10),
00642 false);
00643 }
00644 else {
00645 writeText(itsDrawings,
00646 Point2D<int>(getGridCoord(grid,31,numgrid.h()-8)),
00647 sformat(" ").c_str(),
00648 PixRGB<byte>(255),
00649 PixRGB<byte>(0),
00650 SimpleFont::FIXED(10),
00651 false);
00652 }
00653 }
00654
00655
00656
00657 void SimulationViewerEyeHand::drawFOA(const Point2D<int> target, const uint tN)
00658 {
00659 const PixRGB<byte> col = itsEyeStyles[tN].col;
00660 const int radius = itsMetrics->getFoveaRadius();
00661 drawCircle(itsDrawings, target, radius, col, 2);
00662 }
00663
00664
00665 std::string SimulationViewerEyeHand::craftSVEMOutput(const std::string tfn,
00666 const rutz::shared_ptr<EyeData> data)
00667 {
00668
00669
00670
00671
00672
00673
00674 std::string output =
00675 sformat("%s ", tfn.c_str());
00676 if(!itsHeaderCrafted) itsOutFields.push_back("filename");
00677
00678
00679 output += craftModelFreeOutput(data);
00680
00681
00682
00683 Image<float> smap;
00684 if (itsMaxCacheSize.getVal())
00685 smap = itsMaxCache.getMax();
00686 else smap = itsHeadSM;
00687
00688
00689 output += craftSMSamples(data, smap);
00690
00691
00692 if (itsSMhistoryQlen.getVal()) output += craftSMHistory(data, smap);
00693
00694
00695 if(!itsHeaderCrafted)
00696 {
00697 writeHeader();
00698 itsHeaderCrafted = true;
00699 }
00700 return output;
00701 }
00702
00703
00704 std::string SimulationViewerEyeHand::
00705 craftModelFreeOutput(const rutz::shared_ptr<EyeData> data)
00706 {
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716 Point2D<int> target = rawToRet(data->saccadeTarget());
00717 std::string output = sformat("%d %d ", target.i, target.j);
00718
00719
00720 if(!itsHeaderCrafted)
00721 {
00722 itsOutFields.push_back("ret_targetx");
00723 itsOutFields.push_back("ret_targety");
00724 }
00725
00726
00727
00728
00729
00730
00731
00732 std::string foo;
00733 for (ParamMap::key_iterator iter = data->getMetaData()->keys_begin();
00734 iter != data->getMetaData()->keys_end();
00735 ++iter)
00736 {
00737
00738 foo = *iter;
00739
00740
00741 if(!itsHeaderCrafted) itsOutFields.push_back(foo);
00742 output += sformat (" %g", data->getMetaDataField(foo));
00743 }
00744
00745 return output;
00746 }
00747
00748
00749 std::string SimulationViewerEyeHand::craftSMSamples(const rutz::shared_ptr<EyeData> data,
00750 const Image<float> smap)
00751 {
00752 std::string output;
00753
00754 int sml = itsLevelSpec.getVal().mapLevel();
00755
00756
00757 Point2D<int> target = rawToRet(data->saccadeTarget());
00758
00759
00760
00761 const int radius = itsMetrics->getFoveaRadius();
00762 const int rad = radius >> sml;
00763 Point2D<int> p(target.i >> sml, target.j >> sml);
00764
00765
00766
00767
00768 p.clampToDims(smap.getDims());
00769
00770
00771 float mi, ma, av; getMinMaxAvg(smap, mi, ma, av);
00772
00773
00774 float val = getLocalMax(smap, p, rad);
00775
00776
00777 if(!itsHeaderCrafted)
00778 {
00779 itsOutFields.push_back("sal_val");
00780 itsOutFields.push_back("sal_min");
00781 itsOutFields.push_back("sal_max");
00782 itsOutFields.push_back("sal_av");
00783 }
00784
00785 output = sformat(" %g %g %g %g ", val, mi, ma, av);
00786
00787
00788 if (itsNumRandomSamples.getVal() < smap.getSize())
00789 {
00790
00791
00792 for (int k = 0; k < itsNumRandomSamples.getVal(); ++k)
00793 {
00794 if (itsPriorRandomDistro.getVal().empty())
00795 {
00796 Point2D<int> randp(randomUpToNotIncluding(smap.getWidth()),
00797 randomUpToNotIncluding(smap.getHeight()));
00798 output += sformat(" %g %d %d", getLocalMax(smap, randp, rad),
00799 randp.i, randp.j);
00800 }
00801 else
00802 {
00803 const int randn = randomUpToNotIncluding(randPoints.size());
00804 Point2D<int> randp(randPoints[randn].i >> sml,
00805 randPoints[randn].j >> sml);
00806 output += sformat(" %g %d %d", getLocalMax(smap, randp, rad),
00807 randPoints[randn].i, randPoints[randn].j);
00808 }
00809 if(!itsHeaderCrafted)
00810 {
00811 itsOutFields.push_back("rand_sal");
00812 itsOutFields.push_back("rand_x");
00813 itsOutFields.push_back("rand_y");
00814 }
00815 }
00816 }
00817 else
00818 {
00819
00820
00821 Point2D<int> rp;
00822 for (rp.j = 0; rp.j < smap.getHeight(); ++rp.j)
00823 for (rp.i = 0; rp.i < smap.getWidth(); ++rp.i)
00824 {
00825 output += sformat(" %g %d %d", getLocalMax(smap, rp, rad),
00826 rp.i, rp.j);
00827 if(!itsHeaderCrafted)
00828 {
00829 itsOutFields.push_back("rand_sal");
00830 itsOutFields.push_back("rand_x");
00831 itsOutFields.push_back("rand_y");
00832 }
00833 }
00834 }
00835 return output;
00836 }
00837
00838
00839 std::string SimulationViewerEyeHand::craftSMHistory(const rutz::shared_ptr<EyeData> data,
00840 Image<float> smap)
00841 {
00842 std::string output;
00843
00844 int sml = itsLevelSpec.getVal().mapLevel();
00845
00846
00847 Point2D<int> target = rawToRet(data->saccadeTarget());
00848
00849
00850
00851 const int radius = itsMetrics->getFoveaRadius();
00852 const int rad = radius >> sml;
00853 Point2D<int> p(target.i >> sml, target.j >> sml);
00854
00855
00856 output += std::string(" ");
00857
00858
00859 Point2D<int> pp(data->position());
00860 pp.i >>= sml; pp.j >>= sml; pp.clampToDims(smap.getDims());
00861
00862
00863
00864
00865
00866
00867 size_t ql = itsSMhistory.size();
00868 for (uint i = 0; i < itsSMhistoryQlen.getVal(); ++ i)
00869 {
00870 if (i < ql)
00871 {
00872
00873 float mmi, mma, mmav;
00874 getMinMaxAvg(itsSMhistory[ql - 1 - i], mmi, mma, mmav);
00875
00876
00877 Point2D<int> randp;
00878 if (itsPriorRandomDistro.getVal().empty())
00879 {
00880 randp.i = randomUpToNotIncluding(smap.getWidth());
00881 randp.j = randomUpToNotIncluding(smap.getHeight());
00882 }
00883 else
00884 {
00885 const int randn =
00886 randomUpToNotIncluding(randPoints.size());
00887 randp.i = randPoints[randn].i >> sml;
00888 randp.j = randPoints[randn].j >> sml;
00889 }
00890
00891 output +=
00892 sformat(" %g %g %g %g %g",
00893 getLocalMax(itsSMhistory[ql - 1 - i], p, rad),
00894 getLocalMax(itsSMhistory[ql - 1 - i], pp, rad),
00895 mma, mmav,
00896 getLocalMax(itsSMhistory[ql - 1 - i], randp, rad));
00897 }
00898 else output += std::string(" 0.0 0.0 0.0 0.0 0.0");
00899 if(!itsHeaderCrafted)
00900 {
00901 itsOutFields.push_back("hist_sacendsal");
00902 itsOutFields.push_back("hist_sacstartsal");
00903 itsOutFields.push_back("hist_avgsal");
00904 itsOutFields.push_back("hist_maxsal");
00905 itsOutFields.push_back("hist_randsal");
00906 }
00907 }
00908 return output;
00909 }
00910
00911
00912 void SimulationViewerEyeHand::writeHeader()
00913 {
00914 LINFO("writing header for file %s", itsOutFname.getVal().c_str());
00915 (*itsOutFile) << "#" << itsOutFields[0];
00916 for(uint i = 1; i < itsOutFields.size(); i++)
00917 (*itsOutFile) << " " << itsOutFields[i];
00918 (*itsOutFile) << std::endl;
00919 }
00920
00921
00922 void SimulationViewerEyeHand::extraSampleProcessing(const rutz::shared_ptr<EyeData>) {}
00923
00924
00925
00926 void SimulationViewerEyeHand::extraSampleProcessing(const rutz::shared_ptr<HandData>) {}
00927
00928
00929
00930 Image< PixRGB<byte> > SimulationViewerEyeHand::getTraj(SimEventQueue& q)
00931 {
00932 GVX_TRACE(__PRETTY_FUNCTION__);
00933
00934
00935 Image< PixRGB<byte> > input;
00936 if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this, SEQ_ANY))
00937 input = e->frame().colorByte();
00938 else
00939 LFATAL("Could not find required SimEventRetinaImage");
00940
00941
00942 Image< PixRGB<byte> > comp = composite(itsDrawings, input);
00943
00944
00945 if (itsSaveTraj.getVal()) return comp;
00946
00947
00948 const Dims dims = input.getDims();
00949 Image<float> sm = getMap(q, false);
00950 if (sm.initialized()) sm = rescaleOpt(sm, dims, itsDisplayInterp.getVal());
00951 else sm.resize(dims, true);
00952 Image< PixRGB<byte> > smc = toRGB(Image<byte>(sm));
00953
00954
00955 Image< PixRGB<byte> > smcomp = composite(itsDrawings, smc);
00956
00957
00958
00959
00960 Image< PixRGB<byte> > ret;
00961 if (itsMaxCacheSize.getVal())
00962 {
00963
00964 Image<float> maxsm =
00965 rescaleOpt(itsMaxCache.getMax(), dims, itsDisplayInterp.getVal());
00966 Image< PixRGB<byte> > maxsmc = toRGB(Image<byte>(maxsm));
00967
00968 ret = concatX(concatY(input, smcomp),
00969 concatY(comp, composite(itsDrawings, maxsmc)));
00970
00971 drawGrid(ret, dims.w()-1, dims.h()-1, 3, 3, PixRGB<byte>(128, 128, 128));
00972 }
00973 else
00974 {
00975
00976 ret = concatX(comp, smcomp);
00977 drawLine(ret, Point2D<int>(dims.w()-1, 0), Point2D<int>(dims.w()-1, dims.h()-1),
00978 PixRGB<byte>(255, 255, 0), 1);
00979 drawLine(ret, Point2D<int>(dims.w(), 0), Point2D<int>(dims.w(), dims.h()-1),
00980 PixRGB<byte>(255, 255, 0), 1);
00981 }
00982
00983
00984 while (ret.getWidth() > itsMaxComboWidth.getVal())
00985 ret = decY(lowPass3y(decX(lowPass3x(ret))));
00986
00987 return ret;
00988 }
00989
00990
00991 void SimulationViewerEyeHand::
00992 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00993 {
00994 this->save1(e->sinfo());
00995 }
00996
00997
00998 void SimulationViewerEyeHand::save1(const ModelComponentSaveInfo& sinfo)
00999 {
01000 GVX_TRACE(__PRETTY_FUNCTION__);
01001 SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q;
01002
01003
01004 Image< PixRGB<byte> > res = getTraj(*q);
01005
01006
01007 if (itsSaveCombo.getVal() || itsSaveTraj.getVal())
01008 {
01009
01010
01011 nub::ref<FrameOstream> ofs =
01012 dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs;
01013
01014 ofs->writeRGB(res, "T",
01015 FrameInfo("SimulationViewerEyeHand trajectory", SRC_POS));
01016
01017 }
01018 }
01019
01020
01021
01022
01023
01024