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 "MBARI/MbariResultViewer.H"
00040
00041 #include "Component/ModelManager.H"
00042 #include "Component/ModelOptionDef.H"
00043 #include "GUI/XWinManaged.H"
00044 #include "Image/CutPaste.H"
00045 #include "Image/Image.H"
00046 #include "Image/ShapeOps.H"
00047 #include "Image/colorDefs.H"
00048 #include "MBARI/MbariFrameSeries.H"
00049 #include "MBARI/VisualEvent.H"
00050 #include "Media/FrameSeries.H"
00051 #include "Util/Assert.H"
00052 #include "Util/log.H"
00053
00054 #include <cstdio>
00055 #include <fstream>
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 const ModelOptionDef OPT_MRVsaveEvents =
00079 { MODOPT_ARG_STRING, "MRVsaveEvents", &MOC_MBARIRV, OPTEXP_MRV,
00080 "Save the event structure to a text file",
00081 "mbari-save-events", '\0', "fileName", "" };
00082
00083
00084 const ModelOptionDef OPT_MRVloadEvents =
00085 { MODOPT_ARG_STRING, "MRVloadEvents", &MOC_MBARIRV, OPTEXP_MRV,
00086 "Load the event structure from a text file "
00087 "instead of computing it from the frames",
00088 "mbari-load-events", '\0', "fileName", "" };
00089
00090
00091 const ModelOptionDef OPT_MRVsaveProperties =
00092 { MODOPT_ARG_STRING, "MRVsaveProperties", &MOC_MBARIRV, OPTEXP_MRV,
00093 "Save the event property vector to a text file",
00094 "mbari-save-properties", '\0', "fileName", "" };
00095
00096
00097 const ModelOptionDef OPT_MRVloadProperties =
00098 { MODOPT_ARG_STRING, "MRVloadProperties", &MOC_MBARIRV, OPTEXP_MRV,
00099 "Load the event property vector from a text file",
00100 "mbari-load-properties", '\0', "fileName", "" };
00101
00102
00103 const ModelOptionDef OPT_MRVsavePositions =
00104 { MODOPT_ARG_STRING, "MRVsavePositions", &MOC_MBARIRV, OPTEXP_MRV,
00105 "Save the positions of events to a text file",
00106 "mbari-save-positions", '\0', "fileName", "" };
00107
00108
00109 const ModelOptionDef OPT_MRVmarkInteresting =
00110 { MODOPT_ARG(BitObjectDrawMode), "MRVmarkInteresting", &MOC_MBARIRV, OPTEXP_MRV,
00111 "Way to mark interesting events in output frames of MBARI programs",
00112 "mbari-mark-interesting", '\0', "<None|Shape|Outline|BoundingBox>",
00113 "BoundingBox" };
00114
00115
00116 const ModelOptionDef OPT_MRVopacity =
00117 { MODOPT_ARG(float), "MRVopacity", &MOC_MBARIRV, OPTEXP_MRV,
00118 "Opacity of shape or outline markings of events",
00119 "mbari-opacity", '\0', "<0.0 ... 1.0>", "1.0" };
00120
00121
00122 const ModelOptionDef OPT_MRVmarkCandidate =
00123 { MODOPT_FLAG, "MRVmarkCandidate", &MOC_MBARIRV, OPTEXP_MRV,
00124 "Mark candidates for interesting events in output frames of MBARI programs",
00125 "mbari-mark-candidate", '\0', "", "true" };
00126
00127
00128 const ModelOptionDef OPT_MRVmarkPrediction =
00129 { MODOPT_FLAG, "MRVmarkPrediction", &MOC_MBARIRV, OPTEXP_MRV,
00130 "Mark the Kalman Filter's prediction for the location of an object "
00131 "in output frames of MBARI programs",
00132 "mbari-mark-prediction", '\0', "", "false" };
00133
00134
00135 const ModelOptionDef OPT_MRVmarkFOE =
00136 { MODOPT_FLAG, "MRVmarkFOE", &MOC_MBARIRV, OPTEXP_MRV,
00137 "Mark the focus of expansion in the output frames of MBARI programs",
00138 "mbari-mark-foe", '\0', "", "false" };
00139
00140
00141 const ModelOptionDef OPT_MRVsaveResults =
00142 { MODOPT_FLAG, "MRVsaveResults", &MOC_MBARIRV, OPTEXP_MRV,
00143 "Save intermediate results in MBARI programs to disc",
00144 "mbari-save-results", '\0', "", "false" };
00145
00146
00147 const ModelOptionDef OPT_MRVdisplayResults =
00148 { MODOPT_FLAG, "MRVdisplayResults", &MOC_MBARIRV, OPTEXP_MRV,
00149 "Display intermediate results in MBARI programs",
00150 "mbari-display-results", '\0', "", "false" };
00151
00152
00153 const ModelOptionDef OPT_MRVsaveOutput =
00154 { MODOPT_FLAG, "MRVsaveOutput", &MOC_MBARIRV, OPTEXP_MRV,
00155 "Save output frames in MBARI programs",
00156 "mbari-save-output", '\0', "", "true" };
00157
00158
00159 const ModelOptionDef OPT_MRVdisplayOutput =
00160 { MODOPT_FLAG, "MRVdisplayOutput", &MOC_MBARIRV, OPTEXP_MRV,
00161 "Display output frames in MBARI programs",
00162 "mbari-display-output", '\0', "", "false" };
00163
00164
00165 const ModelOptionDef OPT_MRVshowEventLabels =
00166 { MODOPT_FLAG, "MRVshowEventLabels", &MOC_MBARIRV, OPTEXP_MRV,
00167 "Write event labels into the output frames",
00168 "mbari-label-events", '\0', "", "true" };
00169
00170
00171 const ModelOptionDef OPT_MRVrescaleDisplay =
00172 { MODOPT_ARG(Dims), "MRVrescaleDisplay", &MOC_MBARIRV, OPTEXP_MRV,
00173 "Rescale displays to <width>x<height>, or 0x0 for no rescaling",
00174 "mbari-rescale-display", '\0', "<width>x<height>", "0x0" };
00175
00176
00177 const ModelOptionDef OPT_MRVsaveEventNums =
00178 { MODOPT_ARG_STRING, "MRVsaveEventNums", &MOC_MBARIRV, OPTEXP_MRV,
00179 "Save video clips showing specific events",
00180 "mbari-save-event-clip", '\0', "ev1,ev1,...,evN; or: all", "" };
00181
00182
00183 const ModelOptionDef OPT_MRVsizeAvgCache =
00184 { MODOPT_ARG(int), "MRVsizeAvgCache", &MOC_MBARIRV, OPTEXP_MRV,
00185 "The number of frames used to compute the running average",
00186 "mbari-cache-size", '\0', "<int>", "10" };
00187
00188
00189
00190 MbariResultViewer::MbariResultViewer(ModelManager& mgr,
00191 nub::soft_ref<OutputMbariFrameSeries> ofs)
00192 : ModelComponent(mgr, std::string("MbariResultViewer"),
00193 std::string("MbariResultViewer")),
00194 itsSaveResults(&OPT_MRVsaveResults, this),
00195 itsDisplayResults(&OPT_MRVdisplayResults, this),
00196 itsMarkInteresting(&OPT_MRVmarkInteresting, this),
00197 itsOpacity(&OPT_MRVopacity, this),
00198 itsMarkCandidate(&OPT_MRVmarkCandidate, this),
00199 itsMarkPrediction(&OPT_MRVmarkPrediction, this),
00200 itsMarkFOE(&OPT_MRVmarkFOE, this),
00201 itsSaveOutput(&OPT_MRVsaveOutput, this),
00202 itsDisplayOutput(&OPT_MRVdisplayOutput, this),
00203 itsShowEventLabels(&OPT_MRVshowEventLabels, this),
00204 itsRescaleDisplay(&OPT_MRVrescaleDisplay, this),
00205 itsSizeAvgCache(&OPT_MRVsizeAvgCache, this),
00206 itsSaveEventsName(&OPT_MRVsaveEvents, this),
00207 itsLoadEventsName(&OPT_MRVloadEvents, this),
00208 itsSavePropertiesName(&OPT_MRVsaveProperties, this),
00209 itsLoadPropertiesName(&OPT_MRVloadProperties, this),
00210 itsSavePositionsName(&OPT_MRVsavePositions, this),
00211 itsSaveEventNumString(&OPT_MRVsaveEventNums, this),
00212 resFrameWindow(NULL),
00213 itsOfs(ofs),
00214 colInteresting(COL_INTERESTING),
00215 colCandidate(COL_CANDIDATE),
00216 colPrediction(COL_PREDICTION),
00217 colFOE(COL_FOE)
00218 {
00219
00220 if (!mgr.hasSubComponent(ofs)) mgr.addSubComponent(ofs);
00221 }
00222
00223
00224 MbariResultViewer::~MbariResultViewer()
00225 {
00226
00227 freeMem();
00228 }
00229
00230
00231 void MbariResultViewer::paramChanged(ModelParamBase* const param,
00232 const bool valueChanged,
00233 ParamClient::ChangeStatus* status)
00234 {
00235 ModelComponent::paramChanged(param, valueChanged, status);
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 if (param == &itsMarkCandidate)
00246 {
00247 if (itsMarkCandidate.getVal()) colCandidate = COL_CANDIDATE;
00248 else colCandidate = COL_TRANSPARENT;
00249 }
00250
00251
00252 else if (param == &itsMarkPrediction)
00253 {
00254 if (itsMarkPrediction.getVal()) colPrediction = COL_PREDICTION;
00255 else colPrediction = COL_TRANSPARENT;
00256 }
00257
00258
00259 else if (param == &itsMarkFOE)
00260 {
00261 if (itsMarkFOE.getVal()) colFOE = COL_FOE;
00262 else colFOE = COL_TRANSPARENT;
00263 }
00264
00265
00266 else if (param == &itsSaveEventNumString)
00267 parseSaveEventNums(itsSaveEventNumString.getVal());
00268 }
00269
00270
00271 void MbariResultViewer::reset1()
00272 {
00273
00274 freeMem();
00275
00276
00277 ModelComponent::reset1();
00278 }
00279
00280
00281 void MbariResultViewer::freeMem()
00282 {
00283 for (uint i = 0; i < itsResultWindows.size(); ++i)
00284 if (itsResultWindows[i] != NULL) delete itsResultWindows[i];
00285
00286 if (resFrameWindow != NULL) delete resFrameWindow;
00287
00288 itsResultNames.clear();
00289 itsResultWindows.clear();
00290
00291 itsSaveEventsName.setVal("");
00292 itsLoadEventsName.setVal("");
00293 itsSavePropertiesName.setVal("");
00294 itsLoadPropertiesName.setVal("");
00295 }
00296
00297
00298 template <class T>
00299 void MbariResultViewer::output(const Image<T>& img, const uint frameNum,
00300 const std::string& resultName, const int resNum)
00301 {
00302 if (itsDisplayResults.getVal()) display(img, frameNum, resultName, resNum);
00303 if (itsSaveResults.getVal()) save(img, frameNum, resultName, resNum);
00304 }
00305
00306
00307 template <class T>
00308 void MbariResultViewer::display(const Image<T>& img, const uint frameNum,
00309 const std::string& resultName, const int resNum)
00310 {
00311 uint num = getNumFromString(resultName);
00312 itsResultWindows[num] = displayImage(img, itsResultWindows[num],
00313 getLabel(num, frameNum, resNum).c_str());
00314 }
00315
00316
00317 void MbariResultViewer::save(const Image< PixRGB<byte> >& img,
00318 const uint frameNum,
00319 const std::string& resultName,
00320 const int resNum)
00321 {
00322
00323 itsOfs->writeMbariRGB(img,getFileStem(resultName, resNum),frameNum);
00324 }
00325
00326
00327 void MbariResultViewer::save(const Image<byte>& img,
00328 const uint frameNum,
00329 const std::string& resultName,
00330 const int resNum)
00331 {
00332
00333 itsOfs->writeMbariGray(img,getFileStem(resultName, resNum),frameNum);
00334 }
00335
00336
00337 void MbariResultViewer::save(const Image<float>& img,
00338 const uint frameNum,
00339 const std::string& resultName,
00340 const int resNum)
00341 {
00342
00343 itsOfs->writeMbariFloat(img,getFileStem(resultName, resNum),
00344 FLOAT_NORM_0_255,frameNum);
00345 }
00346
00347
00348 void MbariResultViewer::outputResultFrame(const Image< PixRGB<byte> >& resultImg,
00349 const std::string& frameStem,
00350 const uint frameNum,
00351 VisualEventSet& evts,
00352 PropertyVectorSet& pvs,
00353 const int circleRadius)
00354 {
00355 Image< PixRGB<byte> > img = resultImg;
00356
00357 if (itsDisplayOutput.getVal() || itsSaveOutput.getVal())
00358 evts.drawTokens(img, frameNum, pvs, circleRadius,
00359 itsMarkInteresting.getVal(), itsOpacity.getVal(),
00360 colInteresting, colCandidate, colPrediction,
00361 colFOE, itsShowEventLabels.getVal());
00362
00363
00364 if (itsDisplayOutput.getVal())
00365 {
00366
00367 char label[2048];
00368 sprintf(label,"%s%06d",itsOfs->getFileStem().c_str(),frameNum);
00369
00370 resFrameWindow = displayImage(img,resFrameWindow,label);
00371 }
00372
00373
00374 if (itsSaveOutput.getVal()) itsOfs->writeMbariRGB(img,frameStem,frameNum);
00375 }
00376
00377
00378 bool MbariResultViewer::isLoadEventsNameSet() const
00379 {
00380 return (itsLoadEventsName.getVal().length() > 0);
00381 }
00382
00383
00384
00385 void MbariResultViewer::loadVisualEventSet(VisualEventSet& ves) const
00386 {
00387 std::ifstream ifs(itsLoadEventsName.getVal().c_str());
00388 ves.readFromStream(ifs);
00389 ifs.close();
00390 }
00391
00392 bool MbariResultViewer::isLoadPropertiesNameSet() const
00393 {
00394 return (itsLoadPropertiesName.getVal().length() > 0);
00395 }
00396
00397
00398 void MbariResultViewer::loadProperties(PropertyVectorSet& pvs) const
00399 {
00400 std::ifstream ifs(itsLoadPropertiesName.getVal().c_str());
00401 pvs.readFromStream(ifs);
00402 ifs.close();
00403 }
00404
00405
00406 bool MbariResultViewer::isSaveEventsNameSet() const
00407 {
00408 return (itsSaveEventsName.getVal().length() > 0);
00409 }
00410
00411
00412 void MbariResultViewer::saveVisualEventSet(const VisualEventSet& ves) const
00413 {
00414 std::ofstream ofs(itsSaveEventsName.getVal().c_str());
00415 ves.writeToStream(ofs);
00416 ofs.close();
00417 }
00418
00419
00420 bool MbariResultViewer::isSavePropertiesNameSet() const
00421 {
00422 return (itsSavePropertiesName.getVal().length() > 0);
00423 }
00424
00425
00426 void MbariResultViewer::saveProperties(const PropertyVectorSet& pvs) const
00427 {
00428 std::ofstream ofs(itsSavePropertiesName.getVal().c_str());
00429 pvs.writeToStream(ofs);
00430 ofs.close();
00431 }
00432
00433
00434 bool MbariResultViewer::isSavePositionsNameSet() const
00435 {
00436 return (itsSavePositionsName.getVal().length() > 0);
00437 }
00438
00439
00440 void MbariResultViewer::savePositions(const VisualEventSet& ves) const
00441 {
00442 std::ofstream ofs(itsSavePositionsName.getVal().c_str());
00443 ves.writePositions(ofs);
00444 ofs.close();
00445 }
00446
00447
00448 bool MbariResultViewer::needFrames() const
00449 {
00450 bool needOutput = itsSaveOutput.getVal() || itsDisplayOutput.getVal();
00451 bool needInput = !isLoadEventsNameSet() || isSaveEventClip();
00452 return (needInput || needOutput);
00453 }
00454
00455
00456 uint MbariResultViewer::getAvgCacheSize() const
00457 {
00458 return itsSizeAvgCache.getVal();
00459 }
00460
00461
00462 bool MbariResultViewer::isSaveEventClip() const
00463 {
00464 return (itsSaveEventNums.size() > 0);
00465 }
00466
00467
00468 uint MbariResultViewer::numSaveEventClips() const
00469 {
00470 return itsSaveEventNums.size();
00471 }
00472
00473
00474 uint MbariResultViewer::getSaveEventClipNum(uint idx) const
00475 {
00476 ASSERT(idx < itsSaveEventNums.size());
00477 return itsSaveEventNums[idx];
00478 }
00479
00480
00481 uint MbariResultViewer::getNumFromString(const std::string& resultName)
00482 {
00483
00484 for (uint i = 0; i < itsResultNames.size(); ++i)
00485 if (itsResultNames[i].compare(resultName) == 0)
00486 return i;
00487
00488
00489 itsResultNames.push_back(resultName);
00490 itsResultWindows.push_back(NULL);
00491
00492 return (itsResultNames.size() - 1);
00493 }
00494
00495
00496 std::string MbariResultViewer::getLabel(const uint num, const uint frameNum,
00497 const int resNum)
00498 {
00499 ASSERT(num < itsResultNames.size());
00500 char fnum[7];
00501 sprintf(fnum,"%06d",frameNum);
00502 return (getFileStem(itsResultNames[num], resNum) + std::string(fnum));
00503 }
00504
00505
00506 std::string MbariResultViewer::getFileStem(const std::string& resultName,
00507 const int resNum)
00508 {
00509 char rnum[4];
00510 if (resNum >= 0) sprintf(rnum,"%02d_",resNum);
00511 else sprintf(rnum,"_");
00512
00513 return(itsOfs->getFileStem() + std::string("_")
00514 + resultName + std::string(rnum));
00515 }
00516
00517
00518 template <class T>
00519 XWinManaged* MbariResultViewer::displayImage(const Image<T>& img,
00520 XWinManaged* win,
00521 const char* label)
00522 {
00523
00524 Dims dims = itsRescaleDisplay.getVal();
00525 if (dims.isEmpty()) dims = img.getDims();
00526 bool doRescale = (dims != img.getDims());
00527
00528
00529 if (win != NULL)
00530 {
00531 if (win->getDims() != dims) delete win;
00532 }
00533
00534 if (win == NULL)
00535 {
00536 if (doRescale)
00537 win = new XWinManaged(rescale(img, dims),label);
00538 else
00539 win = new XWinManaged(img,label);
00540 }
00541 else
00542 {
00543 if (doRescale)
00544 win->drawImage(rescale(img,dims));
00545 else
00546 win->drawImage(img);
00547
00548 win->setTitle(label);
00549 }
00550
00551 return win;
00552 }
00553
00554
00555 void MbariResultViewer::saveSingleEventFrame(const Image< PixRGB<byte> >& img,
00556 int frameNum,
00557 const VisualEvent& event)
00558 {
00559 ASSERT(event.isFrameOk(frameNum));
00560
00561
00562 char evnum[10];
00563 sprintf(evnum,"_evt%04d_",event.getEventNum());
00564 std::string filestem = itsOfs->getFileStem() + std::string(evnum);
00565
00566 const int pad = 10;
00567 Dims maxDims = event.getMaxObjectDims();
00568 Dims d(maxDims.w() + 2 * pad, maxDims.h() + 2 * pad);
00569
00570
00571 Rectangle bbox = event.getToken(frameNum).bitObject.getBoundingBox();
00572
00573
00574
00575 int wpad = (d.w() - bbox.width()) / 2;
00576 int ll = bbox.left() - wpad;
00577
00578 int rr = ll + d.w();
00579 if (ll < 0) { rr -= ll; ll = 0; }
00580 if (rr >= img.getWidth()) { rr = img.getWidth() - 1; ll = rr - d.w(); }
00581
00582
00583 int hpad = (d.h() - bbox.height()) / 2;
00584 int tt = bbox.top() - hpad;
00585
00586 int bb = tt + d.h();
00587 if (tt < 0) { bb -= tt; tt = 0; }
00588 if (bb >= img.getHeight()) { bb = img.getHeight() - 1; tt = bb - d.h(); }
00589
00590
00591 Image< PixRGB<byte> > cut = crop(img, Rectangle::tlbrI(tt,ll,bb,rr));
00592 itsOfs->writeMbariRGB(cut, filestem, frameNum);
00593 }
00594
00595
00596 void MbariResultViewer::parseSaveEventNums(const std::string& value)
00597 {
00598 itsSaveEventNums.clear();
00599
00600
00601 int curpos = 0, len = value.length();
00602 while (curpos < len)
00603 {
00604
00605 int nextpos = value.find_first_not_of("-.0123456789eE",curpos);
00606 if (nextpos == -1) nextpos = len;
00607
00608
00609 if (nextpos == curpos)
00610 LFATAL("Error parsing the SaveEventNum string '%s' - found '%c' "
00611 "instead of a number.",value.c_str(),value[curpos]);
00612
00613
00614 uint evNum;
00615 int rep = sscanf(value.substr(curpos,nextpos-curpos).c_str(),"%i",&evNum);
00616
00617
00618 if (rep != 1)
00619 LFATAL("Error parsing SaveEventNum string '%s' - found '%s' instead of "
00620 "a number.", value.c_str(),
00621 value.substr(curpos,nextpos-curpos).c_str());
00622
00623
00624 itsSaveEventNums.push_back(evNum);
00625
00626 LDEBUG("evNum = %i; value[nextpos] = '%c'",evNum,value[nextpos]);
00627
00628
00629 if ((nextpos < len) && (value[nextpos] != ','))
00630 LFATAL("Error parsing the SaveEventNum string '%s' - found '%c' "
00631 "instead of ','.",value.c_str(),value[nextpos]);
00632
00633
00634 curpos = nextpos + 1;
00635 }
00636
00637
00638 return;
00639 }
00640
00641
00642 #define INSTANTIATE(T) \
00643 template void MbariResultViewer::output(const Image< T >& img, \
00644 const uint frameNum, \
00645 const std::string& resultName, \
00646 const int resNum); \
00647 template void MbariResultViewer::display(const Image< T >& img, \
00648 const uint frameNum, \
00649 const std::string& resultName, \
00650 const int resNum); \
00651 template XWinManaged* MbariResultViewer::displayImage(const Image< T >& img, \
00652 XWinManaged* win, \
00653 const char* label);
00654
00655 INSTANTIATE(PixRGB<byte>);
00656 INSTANTIATE(byte);
00657 INSTANTIATE(float);
00658
00659
00660
00661
00662
00663
00664