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/SimulationViewerEyeMvt.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 "Simulation/SimEventQueue.H"
00057 #include "Transport/FrameInfo.H"
00058 #include "Transport/FrameOstream.H"
00059 #include "Util/sformat.H"
00060 #include "rutz/trace.h"
00061
00062 #include <fstream>
00063 #include <iostream>
00064
00065
00066 const ModelOptionDef OPT_SMhistoryQlen =
00067 { MODOPT_ARG(uint), "SMhistoryQ", &MOC_DISPLAY, OPTEXP_CORE,
00068 "Keep a historical queue of salieny maps (one per new input frame), "
00069 "and report the history of saliency values over the entire queue "
00070 "and at a saccade target location, for each saccade",
00071 "sm-history-qlen", '\0', "<uint>", "0" };
00072
00073
00074 SimulationViewerEyeMvt::
00075 SimulationViewerEyeMvt(OptionManager& mgr, const std::string& descrName,
00076 const std::string& tagName) :
00077 SimulationViewer(mgr, descrName, tagName),
00078 SIMCALLBACK_INIT(SimEventClockTick),
00079 SIMCALLBACK_INIT(SimEventSaveOutput),
00080 itsMetrics(new SpatialMetrics(mgr)),
00081 itsSaveTraj(&OPT_SVsaveTraj, this),
00082 itsSaveMegaCombo(&OPT_SVEMsaveMegaCombo, this),
00083 itsDelayCacheSize(&OPT_SVEMdelayCacheSize, this),
00084 itsMaxCacheSize(&OPT_SVEMmaxCacheSize, this),
00085 itsSampleAtStart(&OPT_SVEMsampleAtStart, this),
00086 itsDisplaySacNum(&OPT_SVEMdisplaySacNum, this),
00087 itsDisplayPatch(&OPT_SVdisplayPatch, this),
00088 itsPatchSize(&OPT_SVpatchSize, this),
00089 itsEraseMarker(&OPT_SVeraseMarker, this),
00090 itsDisplayFOA(&OPT_SVdisplayFOA, this),
00091 itsLevelSpec(&OPT_LevelSpec, this),
00092 itsOutFname(&OPT_SVEMoutFname, this),
00093 itsPriorRandomDistro(&OPT_SVEMpriorRandomDistro, this),
00094 itsUseSaccadeInBlink(&OPT_SVEMuseSaccadeInBlink, this),
00095 itsUseDiagColor(&OPT_SVEMuseDiagColors, this),
00096 itsLabelEyePatch(&OPT_SVEMlabelEyePatch, this),
00097 itsWriteFrameNum(&OPT_SVEMwriteFrameNumber, this),
00098 itsNumRandomSamples(&OPT_SVEMnumRandomSamples, this),
00099 itsMaxComboWidth(&OPT_SVEMmaxComboWidth, this),
00100 itsSMhistoryQlen(&OPT_SMhistoryQlen, this),
00101 itsDelayCache(), itsMaxCache(), itsHeadSM(),
00102 itsDrawings(), itsCurrTime(), itsFrameNumber(-1),
00103 itsHeaderCrafted(false), itsOutFields(), itsEyeStyles(),
00104 itsTargets(), itsSMhistory(), itsOutFile(0),
00105 itsRandFile(0),itsRawToRetOffset()
00106 {
00107 GVX_TRACE(__PRETTY_FUNCTION__);
00108
00109 this->addSubComponent(itsMetrics);
00110
00111
00112 LINFO("NOTE: disabling IOR and SE, selecting FixedSaccadeController");
00113 getManager().setOptionValString(&OPT_IORtype, "None");
00114 getManager().setOptionValString(&OPT_ShapeEstimatorMode, "None");
00115
00116
00117 getManager().setOptionValString(&OPT_EyeHeadControllerType, "EyeTrack");
00118
00119
00120
00121 getManager().setOptionValString(&OPT_SVdisplayAdditive, "false");
00122 }
00123
00124
00125 SimulationViewerEyeMvt::~SimulationViewerEyeMvt()
00126 {
00127 GVX_TRACE(__PRETTY_FUNCTION__);
00128 }
00129
00130
00131 void SimulationViewerEyeMvt::start1()
00132 {
00133 GVX_TRACE(__PRETTY_FUNCTION__);
00134
00135 if (itsDelayCacheSize.getVal())
00136 itsDelayCache.setMaxSize(itsDelayCacheSize.getVal());
00137
00138 if (itsMaxCacheSize.getVal())
00139 itsMaxCache.setMaxSize(itsMaxCacheSize.getVal());
00140
00141
00142 if (itsOutFname.getVal().empty() == false)
00143 {
00144 if (itsOutFile) delete itsOutFile;
00145 itsOutFile = new std::ofstream(itsOutFname.getVal().c_str());
00146 if (itsOutFile->is_open() == false)
00147 LFATAL("Cannot open '%s' for writing", itsOutFname.getVal().c_str());
00148 }
00149
00150
00151 if (itsPriorRandomDistro.getVal().empty() == false)
00152 {
00153 if (itsRandFile) delete itsRandFile;
00154 itsRandFile = new std::ifstream(itsPriorRandomDistro.getVal().c_str());
00155 if (itsRandFile->is_open() == false)
00156 LFATAL("Cannot open '%s' for reading",
00157 itsPriorRandomDistro.getVal().c_str());
00158 else
00159 {
00160 while (! itsRandFile->eof())
00161
00162 {
00163 Point2D<int> pr;
00164 float ii, jj;
00165 (*itsRandFile) >> ii >> jj;
00166 pr = Point2D<int>(ii,jj);
00167 randPoints.push_back(pr);
00168 }
00169 itsRandFile->close();
00170 }
00171 }
00172
00173
00174 if (itsSMhistoryQlen.getVal())
00175 itsSMhistory.setMaxSize(itsSMhistoryQlen.getVal());
00176
00177 SimulationViewer::start1();
00178 }
00179
00180
00181 void SimulationViewerEyeMvt::stop1()
00182 {
00183 GVX_TRACE(__PRETTY_FUNCTION__);
00184
00185 if (itsOutFile) { delete itsOutFile; itsOutFile = 0; }
00186 if (itsRandFile) {delete itsRandFile; itsRandFile = 0;}
00187 }
00188
00189
00190 void SimulationViewerEyeMvt::
00191 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& ect)
00192 {
00193
00194 itsCurrTime = q.now();
00195
00196
00197 bool gotnewinput = false;
00198 if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this)) {
00199 itsDrawings.resize(e->frame().getDims(), true);
00200 gotnewinput = true;
00201 itsFrameNumber++;
00202
00203 }
00204
00205
00206 const Image<float> currsm = getMap(q, false);
00207
00208
00209
00210
00211
00212 if (itsDelayCacheSize.getVal())
00213 {
00214
00215 itsDelayCache.push_back(currsm);
00216
00217
00218 if (int(itsDelayCache.size()) >= itsDelayCacheSize.getVal())
00219 itsHeadSM = itsDelayCache.front();
00220 else
00221 itsHeadSM.resize(currsm.getDims(), true);
00222 }
00223 else
00224 itsHeadSM = currsm;
00225
00226
00227
00228 if (itsSMhistoryQlen.getVal() && gotnewinput)
00229 itsSMhistory.push_back(itsHeadSM);
00230
00231
00232 if (itsMaxCacheSize.getVal()) itsMaxCache.push_back(itsHeadSM);
00233
00234
00235
00236 SeC<SimEventRetinaImage> retev = q.check<SimEventRetinaImage>(this, SEQ_ANY);
00237 if (retev.is_valid() == false)
00238 LFATAL("I need some SimEventRetinaImage in the queue to function.");
00239
00240 itsRawToRetOffset = retev->offset();
00241
00242
00243 SeC<SimEventEyeTrackerData> e = q.check<SimEventEyeTrackerData>(this);
00244
00245 while(e.is_valid()) {
00246
00247 const rutz::shared_ptr<EyeData> trackCurrPos = e->data();
00248 const uint tnum = e->trackerNum();
00249 const std::string tfn = e->trackerFilename();
00250
00251 if (itsEyeStyles.size() <= tnum) {
00252 itsEyeStyles.resize(tnum+1);
00253
00254 itsEyeStyles[tnum].pSize = itsPatchSize.getVal();
00255 itsEyeStyles[tnum].col = e->trackerColor();
00256
00257
00258
00259
00260 itsEyeStyles[tnum].label = tfn.substr(tfn.find("data")+5,2);
00261 }
00262
00263
00264 if (itsDisplayPatch.getVal())
00265 {
00266
00267 if (itsEraseMarker.getVal()) itsDrawings.resize(retev->frame().getDims(), true);
00268
00269
00270 drawEye(trackCurrPos, tnum);
00271 }
00272
00273
00274
00275 extraSampleProcessing(trackCurrPos);
00276
00277 bool isUsableTrace = true;
00278
00279 if (itsUseSaccadeInBlink.getVal() == false && trackCurrPos->isInBlink() == true) isUsableTrace = false;
00280
00281
00282
00283 if (trackCurrPos->hasSaccadeTargetData() && isUsableTrace)
00284 {
00285
00286 Point2D<int> dp = rawToRet(trackCurrPos->saccadeTarget());
00287
00288 CLINFO("**** Tracker %03d: Saccade to (%d, %d) at %.1fms ****",
00289 tnum, dp.i, dp.j, q.now().msecs());
00290
00291 if (itsDrawings.coordsOk(dp) == false)
00292 CLINFO("Tracker %03d: Saccade target (%d, %d) out of bounds "
00293 "-- IGNORING", tnum, dp.i, dp.j);
00294 else
00295
00296
00297
00298 itsTargets[tnum] = trackCurrPos;
00299 }
00300
00301
00302
00303
00304
00305
00306 std::map<int, rutz::shared_ptr<EyeData> >::iterator
00307 itr = itsTargets.find(tnum);
00308
00309 if (itr != itsTargets.end() && isUsableTrace &&
00310 (itsSampleAtStart.getVal() || trackCurrPos->isInSaccade() == false))
00311 {
00312
00313 const rutz::shared_ptr<EyeData> trackEventSample = itr->second;
00314 itsTargets.erase(itr);
00315
00316
00317 if(!(trackEventSample->hasSaccadeTargetData()) )
00318 LFATAL("Tracker %03d: Marked event has incomplete targeting data.", tnum);
00319
00320 Point2D<int> trackerTarget = rawToRet(trackEventSample->saccadeTarget());
00321
00322 LINFO("Tracker %03d [%s]: Taking saccade samples at (%d, %d) at time %.1fms",
00323 tnum, tfn.c_str(), trackerTarget.i, trackerTarget.j, q.now().msecs());
00324
00325
00326 if (itsDisplayFOA.getVal()) drawFOA(trackerTarget, tnum);
00327
00328
00329 if (itsDisplaySacNum.getVal())
00330 {
00331 if (tnum == 0) {
00332 std::string fld("typenum");
00333 if (trackCurrPos->hasMetaData(fld.c_str()))
00334 writeText(itsDrawings, Point2D<int>(0, 0),
00335 sformat(" %1g ",
00336 trackEventSample->getMetaDataField("typenum")).c_str(),
00337 PixRGB<byte>(1, 1, 1));
00338 else
00339 LFATAL("--svem-display-sacnum does not have numbered saccades available");
00340 }
00341 else
00342 LFATAL("--svem-display-sacnum only supported with 1 tracker");
00343 }
00344
00345 if (itsOutFile) {
00346 LINFO("writing to file %s........", itsOutFname.getVal().c_str());
00347
00348
00349 std::string statline = craftSVEMOutput(tfn, trackEventSample);
00350
00351
00352 if(!itsHeaderCrafted)
00353 {
00354 writeHeader();
00355 itsHeaderCrafted = true;
00356 }
00357 (*itsOutFile) << statline << std::endl;
00358 }
00359 }
00360
00361
00362 e = q.check<SimEventEyeTrackerData>(this);
00363 }
00364 }
00365
00366
00367 void SimulationViewerEyeMvt::drawEye(const rutz::shared_ptr<EyeData> rawPos, const uint tN)
00368 {
00369
00370
00371 Point2D<int> currPos = rawToRet(rawPos->position());
00372
00373
00374
00375 PixRGB<byte> col;
00376
00377
00378
00379
00380 if (!itsUseDiagColor.getVal())
00381 {
00382 col = itsEyeStyles[tN].col;
00383
00384 if (rawPos->isInSaccade()) col += byte(64);
00385 if (rawPos->isInBlink()) col -= byte(128);
00386 }
00387 else
00388 {
00389 byte r = 1, g = 1, b = 1;
00390 if (rawPos->isInSaccade()) g = 255;
00391 else if (rawPos->isInSmoothPursuit())
00392 {r = 255;b = 255;}
00393 else if (rawPos->isInFixation()) b = 255;
00394 if (rawPos->isInCombinedSaccade()) {b = 255;g = 255;}
00395
00396 col = PixRGB<byte>(r,g,b);
00397 if (rawPos->isInBlink()) col-=byte(128);
00398 }
00399 drawPatchBB(itsDrawings, currPos, itsEyeStyles[tN].pSize,
00400 col, PixRGB<byte>(1));
00401
00402
00403 if(itsLabelEyePatch.getVal()) {
00404 writeText(itsDrawings, currPos+itsEyeStyles[tN].pSize/2,
00405 itsEyeStyles[tN].label.c_str(),
00406 PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
00407 SimpleFont::FIXED(10), true);
00408 }
00409 }
00410
00411
00412 void SimulationViewerEyeMvt::drawFOA(const Point2D<int> target, const uint tN)
00413 {
00414 PixRGB<byte> col = itsEyeStyles[tN].col; col += byte(64);
00415
00416
00417
00418 const int radius = itsMetrics->getFoveaRadius();
00419 drawCircle(itsDrawings, target, radius, col, 2);
00420 }
00421
00422
00423 std::string SimulationViewerEyeMvt::craftSVEMOutput(const std::string tfn,
00424 const rutz::shared_ptr<EyeData> data)
00425 {
00426
00427
00428
00429
00430
00431
00432 std::string output =
00433 sformat("%s ", tfn.c_str());
00434 if(!itsHeaderCrafted) itsOutFields.push_back("filename");
00435
00436 if(itsWriteFrameNum.getVal()) {
00437 output += sformat("%u ",itsFrameNumber);
00438 if(!itsHeaderCrafted) itsOutFields.push_back("framenum");
00439 }
00440
00441
00442 output += craftModelFreeOutput(data);
00443
00444
00445
00446 Image<float> smap;
00447 if (itsMaxCacheSize.getVal())
00448 smap = itsMaxCache.getMax();
00449 else smap = itsHeadSM;
00450
00451
00452 output += craftSMSamples(data, smap);
00453
00454
00455 if (itsSMhistoryQlen.getVal()) output += craftSMHistory(data, smap);
00456
00457 return output;
00458 }
00459
00460
00461 std::string SimulationViewerEyeMvt::
00462 craftModelFreeOutput(const rutz::shared_ptr<EyeData> data)
00463 {
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 Point2D<int> target = rawToRet(data->saccadeTarget());
00474 std::string output = sformat("%d %d ", target.i, target.j);
00475
00476
00477 if(!itsHeaderCrafted)
00478 {
00479 itsOutFields.push_back("ret_targetx");
00480 itsOutFields.push_back("ret_targety");
00481 }
00482
00483
00484
00485
00486
00487
00488
00489 std::string foo;
00490 for (ParamMap::key_iterator iter = data->getMetaData()->keys_begin();
00491 iter != data->getMetaData()->keys_end();
00492 ++iter)
00493 {
00494
00495 foo = *iter;
00496
00497
00498 if(!itsHeaderCrafted) itsOutFields.push_back(foo);
00499 output += sformat (" %g", data->getMetaDataField(foo));
00500 }
00501
00502 return output;
00503 }
00504
00505
00506 std::string SimulationViewerEyeMvt::craftSMSamples(const rutz::shared_ptr<EyeData> data,
00507 const Image<float> smap)
00508 {
00509 std::string output;
00510
00511 int sml = itsLevelSpec.getVal().mapLevel();
00512
00513
00514 Point2D<int> target = rawToRet(data->saccadeTarget());
00515
00516
00517
00518 const int radius = itsMetrics->getFoveaRadius();
00519 const int rad = radius >> sml;
00520 Point2D<int> p(target.i >> sml, target.j >> sml);
00521
00522
00523
00524
00525 p.clampToDims(smap.getDims());
00526
00527
00528 float mi, ma, av; getMinMaxAvg(smap, mi, ma, av);
00529
00530
00531
00532 float val = getLocalMax(smap, p, rad);
00533
00534
00535 if(!itsHeaderCrafted)
00536 {
00537 itsOutFields.push_back("sal_val");
00538 itsOutFields.push_back("sal_min");
00539 itsOutFields.push_back("sal_max");
00540 itsOutFields.push_back("sal_av");
00541 }
00542
00543 output = sformat(" %g %g %g %g ", val, mi, ma, av);
00544
00545
00546 if (itsNumRandomSamples.getVal() < smap.getSize())
00547 {
00548
00549
00550 for (int k = 0; k < itsNumRandomSamples.getVal(); ++k)
00551 {
00552 if (itsPriorRandomDistro.getVal().empty())
00553 {
00554 Point2D<int> randp(randomUpToNotIncluding(smap.getWidth()),
00555 randomUpToNotIncluding(smap.getHeight()));
00556 output += sformat(" %g %d %d", getLocalMax(smap, randp, rad),
00557 randp.i, randp.j);
00558 }
00559 else
00560 {
00561 const int randn = randomUpToNotIncluding(randPoints.size());
00562 Point2D<int> randp(randPoints[randn].i >> sml,
00563 randPoints[randn].j >> sml);
00564
00565 LINFO("%d %d", randPoints[randn].i, randPoints[randn].j);
00566
00567
00568 randp.clampToDims(smap.getDims());
00569
00570 output += sformat(" %g %d %d", getLocalMax(smap, randp, rad),
00571 randPoints[randn].i, randPoints[randn].j);
00572 }
00573 if(!itsHeaderCrafted)
00574 {
00575 itsOutFields.push_back("rand_sal");
00576 itsOutFields.push_back("rand_x");
00577 itsOutFields.push_back("rand_y");
00578 }
00579 }
00580 }
00581 else
00582 {
00583
00584
00585 Point2D<int> rp;
00586 for (rp.j = 0; rp.j < smap.getHeight(); ++rp.j)
00587 for (rp.i = 0; rp.i < smap.getWidth(); ++rp.i)
00588 {
00589 output += sformat(" %g %d %d", getLocalMax(smap, rp, rad),
00590 rp.i, rp.j);
00591 if(!itsHeaderCrafted)
00592 {
00593 itsOutFields.push_back("rand_sal");
00594 itsOutFields.push_back("rand_x");
00595 itsOutFields.push_back("rand_y");
00596 }
00597 }
00598 }
00599 return output;
00600 }
00601
00602
00603 std::string SimulationViewerEyeMvt::craftSMHistory(const rutz::shared_ptr<EyeData> data,
00604 Image<float> smap)
00605 {
00606 std::string output;
00607
00608 int sml = itsLevelSpec.getVal().mapLevel();
00609
00610
00611 Point2D<int> target = rawToRet(data->saccadeTarget());
00612
00613
00614
00615 const int radius = itsMetrics->getFoveaRadius();
00616 const int rad = radius >> sml;
00617 Point2D<int> p(target.i >> sml, target.j >> sml);
00618 p.clampToDims(smap.getDims());
00619
00620
00621 output += std::string(" ");
00622
00623
00624
00625 Point2D<int> pp(data->position());
00626 pp.i >>= sml; pp.j >>= sml; pp.clampToDims(smap.getDims());
00627
00628
00629
00630
00631
00632
00633 size_t ql = itsSMhistory.size();
00634 for (uint i = 0; i < itsSMhistoryQlen.getVal(); ++ i)
00635 {
00636 if (i < ql)
00637 {
00638
00639 float mmi, mma, mmav;
00640 getMinMaxAvg(itsSMhistory[ql - 1 - i], mmi, mma, mmav);
00641
00642
00643 Point2D<int> randp;
00644 if (itsPriorRandomDistro.getVal().empty())
00645 {
00646 randp.i = randomUpToNotIncluding(smap.getWidth());
00647 randp.j = randomUpToNotIncluding(smap.getHeight());
00648 }
00649 else
00650 {
00651 const int randn =
00652 randomUpToNotIncluding(randPoints.size());
00653 randp.i = randPoints[randn].i >> sml;
00654 randp.j = randPoints[randn].j >> sml;
00655
00656
00657
00658 randp.clampToDims(smap.getDims());
00659 }
00660
00661 output +=
00662 sformat(" %g %g %g %g %g",
00663 getLocalMax(itsSMhistory[ql - 1 - i], p, rad),
00664 getLocalMax(itsSMhistory[ql - 1 - i], pp, rad),
00665 mma, mmav,
00666 getLocalMax(itsSMhistory[ql - 1 - i], randp, rad));
00667 }
00668 else output += std::string(" 0.0 0.0 0.0 0.0 0.0");
00669 if(!itsHeaderCrafted)
00670 {
00671 itsOutFields.push_back("hist_sacendsal");
00672 itsOutFields.push_back("hist_sacstartsal");
00673 itsOutFields.push_back("hist_maxsal");
00674 itsOutFields.push_back("hist_avgsal");
00675 itsOutFields.push_back("hist_randsal");
00676 }
00677 }
00678 return output;
00679 }
00680
00681
00682 void SimulationViewerEyeMvt::writeHeader()
00683 {
00684 LINFO("writing header for file %s (%zu fields)", itsOutFname.getVal().c_str(),
00685 itsOutFields.size());
00686 (*itsOutFile) << "#" << itsOutFields[0];
00687 for(uint i = 1; i < itsOutFields.size(); i++)
00688 (*itsOutFile) << " " << itsOutFields[i];
00689 (*itsOutFile) << std::endl;
00690 }
00691
00692
00693 void SimulationViewerEyeMvt::extraSampleProcessing(const rutz::shared_ptr<EyeData>) {}
00694
00695
00696
00697 Image< PixRGB<byte> > SimulationViewerEyeMvt::getTraj(SimEventQueue& q)
00698 {
00699 GVX_TRACE(__PRETTY_FUNCTION__);
00700
00701
00702 Image< PixRGB<byte> > input;
00703 if (SeC<SimEventRetinaImage> e = q.check<SimEventRetinaImage>(this, SEQ_ANY))
00704 input = e->frame().colorByte();
00705 else
00706 LFATAL("Could not find required SimEventRetinaImage");
00707
00708
00709 Image< PixRGB<byte> > comp = composite(itsDrawings, input, PixRGB<byte>(0,0,0));
00710
00711
00712 if (itsSaveTraj.getVal()) return comp;
00713
00714
00715 const Dims dims = input.getDims();
00716 Image<float> sm = getMap(q, false);
00717 if (sm.initialized()) sm = rescaleOpt(sm, dims, itsDisplayInterp.getVal());
00718 else sm.resize(dims, true);
00719 Image< PixRGB<byte> > smc = toRGB(Image<byte>(sm));
00720
00721
00722 Image< PixRGB<byte> > smcomp = composite(itsDrawings, smc);
00723
00724
00725
00726
00727
00728 Image< PixRGB<byte> > ret;
00729 if (itsMaxCacheSize.getVal())
00730 {
00731
00732 Image<float> maxsm =
00733 rescaleOpt(itsMaxCache.getMax(), dims, itsDisplayInterp.getVal());
00734 Image< PixRGB<byte> > maxsmc = toRGB(Image<byte>(maxsm));
00735
00736 ret = concatX(concatY(input, smcomp),
00737 concatY(comp, composite(itsDrawings, maxsmc)));
00738
00739 drawGrid(ret, dims.w()-1, dims.h()-1, 3, 3, PixRGB<byte>(128, 128, 128));
00740 }
00741 else
00742 {
00743
00744 ret = concatX(comp, smcomp);
00745 drawLine(ret, Point2D<int>(dims.w()-1, 0), Point2D<int>(dims.w()-1, dims.h()-1),
00746 PixRGB<byte>(255, 255, 0), 1);
00747 drawLine(ret, Point2D<int>(dims.w(), 0), Point2D<int>(dims.w(), dims.h()-1),
00748 PixRGB<byte>(255, 255, 0), 1);
00749 }
00750
00751
00752 while (ret.getWidth() > itsMaxComboWidth.getVal())
00753 ret = decY(lowPass3y(decX(lowPass3x(ret))));
00754
00755 return ret;
00756 }
00757
00758
00759 void SimulationViewerEyeMvt::
00760 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00761 {
00762 this->save1(e->sinfo());
00763 }
00764
00765
00766 void SimulationViewerEyeMvt::save1(const ModelComponentSaveInfo& sinfo)
00767 {
00768 GVX_TRACE(__PRETTY_FUNCTION__);
00769 SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q;
00770
00771
00772 Image< PixRGB<byte> > res = getTraj(*q);
00773
00774
00775 if (itsSaveMegaCombo.getVal() || itsSaveTraj.getVal())
00776 {
00777
00778
00779 nub::ref<FrameOstream> ofs =
00780 dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs;
00781
00782 ofs->writeRGB(res, "T",
00783 FrameInfo("SimulationViewerEyeMvt trajectory", SRC_POS));
00784
00785 }
00786 }
00787
00788
00789
00790
00791
00792