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 "Channels/SingleChannel.H"
00039
00040 #include "Channels/ChannelOpts.H"
00041 #include "Channels/ChannelFacets.H"
00042 #include "Channels/ChannelVisitor.H"
00043 #include "Channels/SubmapAlgorithmStd.H"
00044 #include "Component/GlobalOpts.H"
00045 #include "Component/OptionManager.H"
00046 #include "Component/ParamMap.H"
00047 #include "Image/FFTWWrapper.H"
00048 #include "Image/FilterOps.H"
00049 #include "Image/Image.H"
00050 #include "Image/ImageSetOps.H"
00051 #include "Image/MathOps.H"
00052 #include "Image/PyrBuilder.H"
00053 #include "Image/PyramidOps.H"
00054 #include "Image/ShapeOps.H"
00055 #include "Image/Transforms.H"
00056 #include "Image/fancynorm.H"
00057 #include "Transport/FrameInfo.H"
00058 #include "Transport/FrameOstream.H"
00059 #include "Util/Assert.H"
00060 #include "Util/MathFunctions.H"
00061 #include "Util/log.H"
00062 #include "Util/sformat.H"
00063 #include "rutz/trace.h"
00064
00065 #include "Image/CutPaste.H"
00066 #include <cmath>
00067 #include <iostream>
00068 #include <fstream>
00069
00070
00071 SingleChannel::SingleChannel(OptionManager& mgr, const std::string& descrName,
00072 const std::string& tag,
00073 const VisualFeature vs,
00074 rutz::shared_ptr<PyrBuilder<float> > pbuild) :
00075 ChannelBase(mgr, descrName, tag, vs),
00076 itsTakeAbs("SingleChannelTakeAbs", this, false),
00077 itsNormalizeOutput("SingleChannelNormalizeOutput", this, false),
00078 itsScaleNoiseToMax("SingleChannelScaleNoiseToMax", this, false),
00079 itsLowThresh("SingleChannelLowThresh", this, 0.0F),
00080 itsRectifyPyramid("SingleChannelRectifyPyramid", this, false),
00081 itsComputeFullPyramid("SingleChannelComputeFullPyramid", this, false),
00082 itsUseRandom(&OPT_UseRandom, this),
00083 itsUseSplitCS(&OPT_SingleChannelUseSplitCS, this),
00084 itsLevelSpec(&OPT_LevelSpec, this),
00085 itsNormType(&OPT_MaxNormType, this),
00086 itsQlen(&OPT_SingleChannelQueueLen, this),
00087 itsUseOlderVersion(&OPT_UseOlderVersion, this),
00088 itsTimeDecay(&OPT_SingleChannelTimeDecay, this),
00089 itsSaveRawMaps(&OPT_SingleChannelSaveRawMaps, this),
00090 itsComputeFullPyramidForGist(&OPT_SingleChannelComputeFullPyramidForGist, this),
00091 itsSaveFeatureMaps(&OPT_SingleChannelSaveFeatureMaps, this),
00092 itsSaveOutputMap(&OPT_SingleChannelSaveOutputMap, this),
00093 itsSubmapAlgoType(&OPT_SubmapAlgoType, this),
00094 itsGetSingleChannelStats(&OPT_GetSingleChannelStats, this),
00095 itsSaveStatsPerChannel(&OPT_SaveStatsPerChannel, this),
00096 itsSaveStatsPerChannelFreq(&OPT_SaveStatsPerChannelFreq, this),
00097 itsGetSingleChannelStatsFile(&OPT_GetSingleChannelStatsFile, this),
00098 itsGetSingleChannelStatsTag(&OPT_GetSingleChannelStatsTag, this),
00099 itsOutputRangeMin(&OPT_ChannelOutputRangeMin, this),
00100 itsOutputRangeMax(&OPT_ChannelOutputRangeMax, this),
00101 itsPq(),
00102 itsOutputCache(),
00103 itsSubmapCache(NULL),
00104 itsTempl(),
00105 itsPyrBuilder(pbuild),
00106 itsClipPyr(),
00107 itsInputHandler(),
00108 itsSubmapAlgo(new SubmapAlgorithmStd(mgr))
00109 {
00110 GVX_TRACE(__PRETTY_FUNCTION__);
00111
00112 ComponentFactory<SubmapAlgorithm>& f = SubmapAlgorithm::getFactory();
00113 if (!f.is_valid_key("Std"))
00114 f.registerType<SubmapAlgorithmStd>("Std", mgr);
00115
00116 itsSubmapAlgo = SubmapAlgorithm::make(itsSubmapAlgoType.getVal());
00117
00118 this->addSubComponent(itsSubmapAlgo);
00119 }
00120
00121
00122 SingleChannel::~SingleChannel()
00123 {
00124 GVX_TRACE(__PRETTY_FUNCTION__);
00125 }
00126
00127
00128 void SingleChannel::start1()
00129 {
00130 GVX_TRACE(__PRETTY_FUNCTION__);
00131 const int maxind = maxIndex();
00132 itsSubmapCache = new Image<float>[maxind];
00133 itsTempl = ImageSet<float>(maxind);
00134 itsFrameIdx = 0;
00135
00136
00137
00138 if (itsUseOlderVersion.getVal() == false)
00139 {
00140 itsOutputRangeMin.setVal(0.0f);
00141 itsOutputRangeMax.setVal(0.0f);
00142 }
00143
00144
00145
00146
00147
00148 if (itsUseOlderVersion.getVal() && itsNormType.getVal() != VCXNORM_MAXNORM)
00149 {
00150 itsOutputRangeMin.setVal(0.0f);
00151 itsOutputRangeMax.setVal(0.0f);
00152 }
00153 }
00154
00155
00156 void SingleChannel::stop2()
00157 {
00158 GVX_TRACE(__PRETTY_FUNCTION__);
00159 delete [] itsSubmapCache; itsSubmapCache = 0;
00160 }
00161
00162
00163 void SingleChannel::reset1()
00164 {
00165 GVX_TRACE(__PRETTY_FUNCTION__);
00166
00167 itsPyrBuilder->reset();
00168 itsPq.clear();
00169 itsClipPyr.clear();
00170
00171
00172 ChannelBase::reset1();
00173 }
00174
00175
00176 void SingleChannel::accept(ChannelVisitor& v)
00177 {
00178 GVX_TRACE(__PRETTY_FUNCTION__);
00179 v.visitSingleChannel(*this);
00180 }
00181
00182
00183 void SingleChannel::paramChanged(ModelParamBase* const param,
00184 const bool valueChanged,
00185 ParamClient::ChangeStatus* status)
00186 {
00187 GVX_TRACE(__PRETTY_FUNCTION__);
00188 ChannelBase::paramChanged(param, valueChanged, status);
00189
00190 if (param == &itsSubmapAlgoType && valueChanged)
00191 {
00192 nub::ref<SubmapAlgorithm> algo =
00193 SubmapAlgorithm::make(itsSubmapAlgoType.getVal());
00194
00195 this->setSubmapAlgorithm(algo);
00196
00197 algo->exportOptions(MC_RECURSE);
00198 }
00199 }
00200
00201
00202 void SingleChannel::readFrom(const ParamMap& pmap)
00203 {
00204 GVX_TRACE(__PRETTY_FUNCTION__);
00205
00206 ChannelBase::readFrom(pmap);
00207 ChannelFacetMap::readFacetsFrom(pmap);
00208 }
00209
00210
00211 void SingleChannel::writeTo(ParamMap& pmap) const
00212 {
00213 GVX_TRACE(__PRETTY_FUNCTION__);
00214
00215 ChannelBase::writeTo(pmap);
00216 ChannelFacetMap::writeFacetsTo(pmap);
00217 }
00218
00219
00220 void SingleChannel::setTempl(const uint cntr, const uint surr,
00221 Image<float> &templ)
00222 {
00223 GVX_TRACE(__PRETTY_FUNCTION__);
00224 killCaches();
00225 itsTempl[csToIndex(cntr, surr)] = templ;
00226 }
00227
00228
00229 void SingleChannel::setBiasMask(Image<float> &biasMask)
00230 {
00231 GVX_TRACE(__PRETTY_FUNCTION__);
00232 killCaches();
00233 itsBiasMask = biasMask;
00234 }
00235
00236
00237 Image<float> SingleChannel::getBiasMask() const
00238 {
00239 GVX_TRACE(__PRETTY_FUNCTION__);
00240 return itsBiasMask;
00241 }
00242
00243
00244 Image<float> SingleChannel::getTempl(const uint cntr, const uint surr) const
00245 {
00246 GVX_TRACE(__PRETTY_FUNCTION__);
00247 return itsTempl[csToIndex(cntr, surr)];
00248
00249 }
00250
00251
00252 bool SingleChannel::outputAvailable() const
00253 {
00254 GVX_TRACE(__PRETTY_FUNCTION__);
00255
00256
00257 if (itsInputHandler.is_valid())
00258 itsInputHandler->waitForOutput(const_cast<SingleChannel&>(*this));
00259
00260 return (itsPq.empty() == false) || itsOutputCache.initialized();
00261 }
00262
00263
00264 bool SingleChannel::hasPyramid() const
00265 {
00266 GVX_TRACE(__PRETTY_FUNCTION__);
00267 return (itsPq.empty() == false);
00268 }
00269
00270
00271 bool SingleChannel::hasOutputCache() const
00272 {
00273 GVX_TRACE(__PRETTY_FUNCTION__);
00274 return itsOutputCache.initialized();
00275 }
00276
00277
00278 Dims SingleChannel::getMapDims() const
00279 {
00280 GVX_TRACE(__PRETTY_FUNCTION__);
00281 const int lev = itsLevelSpec.getVal().mapLevel();
00282
00283 return Dims(this->getInputDims().w() / (1 << lev),
00284 this->getInputDims().h() / (1 << lev));
00285 }
00286
00287
00288 const Image<float>& SingleChannel::getImage(const uint lev) const
00289 {
00290 GVX_TRACE(__PRETTY_FUNCTION__);
00291 if (itsPq.empty()) CLFATAL("I have no input pyramid yet!");
00292 return itsPq.front().pyr.getImage(lev);
00293 }
00294
00295
00296 Image<float> SingleChannel::centerSurround(const uint cntrlev,
00297 const uint surrlev) const
00298 {
00299 GVX_TRACE(__PRETTY_FUNCTION__);
00300 ASSERT(itsLevelSpec.getVal().csOK(cntrlev, surrlev));
00301 if (itsPq.empty()) CLFATAL("I have no input pyramid yet!");
00302
00303
00304 const ImageSet<float>& pyr = itsPq.front().pyr;
00305 double t = itsPq.front().t.secs();
00306
00307
00308 Image<float> cs = ::centerSurround(pyr, cntrlev, surrlev,
00309 itsTakeAbs.getVal(), &itsClipPyr);
00310
00311
00312 for (uint i = 1; i < itsPq.size(); ++i)
00313 {
00314 const ImageSet<float>& pyr2 = itsPq[i].pyr;
00315 double t2 = itsPq[i].t.secs();
00316
00317
00318
00319 float fac = exp( (t2 - t) * itsTimeDecay.getVal());
00320 cs += ::centerSurroundDiff(pyr, pyr2, cntrlev, surrlev,
00321 itsTakeAbs.getVal(), &itsClipPyr) * fac;
00322 }
00323
00324 return cs;
00325 }
00326
00327
00328 void SingleChannel::centerSurround(const uint cntrlev, const uint surrlev,
00329 Image<float>& pos, Image<float>& neg) const
00330 {
00331 GVX_TRACE(__PRETTY_FUNCTION__);
00332 ASSERT(itsLevelSpec.getVal().csOK(cntrlev, surrlev));
00333 if (itsPq.empty()) CLFATAL("I have no input pyramid yet!");
00334
00335
00336 const ImageSet<float>& pyr = itsPq.front().pyr;
00337 double t = itsPq.front().t.secs();
00338
00339
00340 ::centerSurround(pyr, cntrlev, surrlev, pos, neg, &itsClipPyr);
00341
00342
00343 for (uint i = 1; i < itsPq.size(); ++i)
00344 {
00345 const ImageSet<float>& pyr2 = itsPq[i].pyr;
00346 double t2 = itsPq[i].t.secs();
00347
00348
00349
00350 float fac = exp( (t2 - t) * itsTimeDecay.getVal());
00351 Image<float> pos2, neg2;
00352 ::centerSurroundDiff(pyr, pyr2, cntrlev, surrlev,
00353 pos2, neg2, &itsClipPyr);
00354 pos += pos2 * fac;
00355 neg += neg2 * fac;
00356 }
00357 }
00358
00359
00360 uint SingleChannel::numSubmaps() const
00361 {
00362 GVX_TRACE(__PRETTY_FUNCTION__);
00363 return maxIndex();
00364 }
00365
00366
00367 Image<float> SingleChannel::getSubmap(const uint idx) const
00368 {
00369 GVX_TRACE(__PRETTY_FUNCTION__);
00370
00371 if (itsSubmapCache[idx].initialized() == false)
00372 itsSubmapCache[idx] = itsSubmapAlgo->compute(*this, idx);
00373
00374 return itsSubmapCache[idx];
00375 }
00376
00377
00378 Image<float> SingleChannel::getRawCSmap(const uint idx) const
00379 {
00380 GVX_TRACE(__PRETTY_FUNCTION__);
00381 ASSERT(itsLevelSpec.getVal().indexOK(idx));
00382 if (itsPq.empty()) CLFATAL("I have no input pyramid yet!");
00383
00384
00385
00386
00387
00388
00389 float w = 1.0;
00390 if (hasFacet<ChannelFacetGainSingle>())
00391 w = getFacet<ChannelFacetGainSingle>()->getVal(idx);
00392
00393
00394 if (w == 0.0f) return Image<float>(getMapDims(), ZEROS);
00395
00396
00397 uint clev = 0, slev = 0;
00398 indexToCS(idx, clev, slev);
00399
00400 Image<float> submap;
00401 if (itsUseSplitCS.getVal())
00402 {
00403
00404
00405
00406 Image<float> subpos, subneg, subpos2, subneg2;
00407
00408
00409
00410 this->centerSurround(clev, slev, subpos, subneg);
00411
00412
00413 float pmin, pmax, nmin, nmax;
00414 getMinMax(subpos, pmin, pmax); subpos2 = binaryReverse(subpos, pmax);
00415 getMinMax(subneg, nmin, nmax); subneg2 = binaryReverse(subneg, nmax);
00416
00417
00418
00419
00420
00421
00422
00423 subpos = maxNormalize(subpos, 0.0f, 0.0f, itsNormType.getVal());
00424 subneg = maxNormalize(subneg, 0.0f, 0.0f, itsNormType.getVal());
00425 subpos2 = maxNormalize(subpos2, 0.0f, 0.0f, itsNormType.getVal());
00426 subneg2 = maxNormalize(subneg2, 0.0f, 0.0f, itsNormType.getVal());
00427
00428
00429
00430 submap = subpos + subneg + subpos2 + subneg2;
00431 }
00432 else
00433
00434 submap = this->centerSurround(clev, slev);
00435
00436
00437 if (MYLOGVERB >= LOG_DEBUG)
00438 {
00439 float mi, ma; getMinMax(submap, mi, ma);
00440 LDEBUG("%s(%d,%d): raw range [%f .. %f]", tagName().c_str(),
00441 clev, slev, mi, ma);
00442 }
00443
00444 return submap;
00445 }
00446
00447
00448 Image<float> SingleChannel::postProcessMap(const Image<float>& smap,
00449 const uint idx) const
00450 {
00451 GVX_TRACE(__PRETTY_FUNCTION__);
00452 Image<float> submap(smap);
00453 uint clev = 0, slev = 0;
00454 indexToCS(idx, clev, slev);
00455
00456
00457
00458 if (submap.getWidth() > getMapDims().w())
00459 submap = downSize(submap, getMapDims());
00460 else if (submap.getWidth() < getMapDims().w())
00461 submap = rescale(submap, getMapDims());
00462
00463
00464 if (itsUseRandom.getVal())
00465 {
00466
00467 if (itsScaleNoiseToMax.getVal())
00468 {
00469 float fMin, fMax; getMinMax(submap, fMin, fMax);
00470 inplaceAddBGnoise(submap, fMax);
00471 }
00472 else
00473 inplaceAddBGnoise(submap, 255.0);
00474 }
00475
00476
00477
00478
00479 if (itsUseOlderVersion.getVal())
00480 {
00481 LDEBUG("%s(%d,%d): applying %s(%f .. %f)", tagName().c_str(), clev, slev,
00482 maxNormTypeName(itsNormType.getVal()), MAXNORMMIN, MAXNORMMAX);
00483 submap = maxNormalize(submap, MAXNORMMIN, MAXNORMMAX,
00484 itsNormType.getVal());
00485 }
00486 else
00487 {
00488 LDEBUG("%s(%d,%d): applying %s(0.0 .. 0.0)", tagName().c_str(),
00489 clev, slev, maxNormTypeName(itsNormType.getVal()));
00490 submap = maxNormalize(submap, 0.0f, 0.0f, itsNormType.getVal());
00491 }
00492
00493
00494 if (MYLOGVERB >= LOG_DEBUG)
00495 {
00496 float mi, ma; getMinMax(submap, mi, ma);
00497 LDEBUG("%s(%d,%d): final range [%f .. %f]",
00498 tagName().c_str(), clev, slev, mi, ma);
00499 }
00500
00501 return submap;
00502 }
00503
00504
00505 std::string SingleChannel::getSubmapName(const uint idx) const
00506 {
00507 GVX_TRACE(__PRETTY_FUNCTION__);
00508 ASSERT( itsLevelSpec.getVal().indexOK(idx) );
00509
00510 uint clev = 0, slev = 0;
00511 indexToCS(idx, clev, slev);
00512
00513 return sformat("%s lev: %d delta: %d",
00514 descriptiveName().c_str(), clev, slev-clev);
00515 }
00516
00517
00518 std::string SingleChannel::getSubmapNameShort(const uint idx) const
00519 {
00520 GVX_TRACE(__PRETTY_FUNCTION__);
00521 ASSERT( itsLevelSpec.getVal().indexOK(idx) );
00522
00523 uint clev = 0, slev = 0;
00524 indexToCS(idx, clev, slev);
00525
00526 return sformat("%s(%d,%d)", tagName().c_str(), clev, slev);
00527 }
00528
00529
00530 void SingleChannel::getFeatures(const Point2D<int>& locn,
00531 std::vector<float>& mean) const
00532 {
00533 GVX_TRACE(__PRETTY_FUNCTION__);
00534 if (!this->outputAvailable())
00535 {
00536 CLDEBUG("I have no input pyramid yet -- RETURNING ZEROS");
00537 for (uint idx = 0; idx < numSubmaps(); idx ++) mean.push_back(0.0F);
00538 return;
00539 }
00540
00541
00542
00543
00544
00545 const ImageSet<float>& pyr = itsPq.front().pyr;
00546 const Dims indims = this->getInputDims();
00547
00548 for (uint idx = 0; idx < numSubmaps(); idx ++)
00549 {
00550
00551 uint clev = 0, slev = 0;
00552 indexToCS(idx, clev, slev);
00553
00554
00555 ASSERT(pyr[clev].initialized());
00556 const float cval = pyr[clev].getValInterpScaled(locn, indims);
00557
00558
00559 ASSERT(pyr[slev].initialized());
00560 const float sval = pyr[slev].getValInterpScaled(locn, indims);
00561
00562
00563
00564 float val = cval - sval; if (itsTakeAbs.getVal()) val = fabs(val);
00565
00566
00567 mean.push_back(val);
00568 }
00569 }
00570
00571
00572 void SingleChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn,
00573 std::vector<std::vector<float> > *mean,
00574 int *count) const
00575 {
00576 GVX_TRACE(__PRETTY_FUNCTION__);
00577 if (!this->outputAvailable())
00578 {
00579 CLDEBUG("I have no input pyramid yet -- RETURNING ZEROS");
00580 for (uint idx = 0; idx < numSubmaps(); idx ++)
00581 {
00582 std::vector<std::vector<float> >::iterator imean = mean->begin();
00583 for(int i = 0; i < *count; i++, ++imean)
00584 imean->push_back(0.0);
00585 }
00586 return;
00587 }
00588
00589
00590
00591
00592
00593 const ImageSet<float>& pyr = itsPq.front().pyr;
00594 const Dims indims = this->getInputDims();
00595 const uint sm = numSubmaps();
00596 for (uint idx = 0; idx < sm; ++idx)
00597 {
00598
00599 uint clev = 0, slev = 0;
00600 indexToCS(idx, clev, slev);
00601 std::vector<Point2D<int>*>::iterator ilocn = locn->begin();
00602 std::vector<std::vector<float> >::iterator imean = mean->begin();
00603
00604 for (int i = 0; i < *count; ++i, ++ilocn, ++imean)
00605 {
00606
00607 ASSERT(pyr[clev].initialized());
00608 const float cval = pyr[clev].getValInterpScaled(**ilocn, indims);
00609
00610
00611 ASSERT(pyr[slev].initialized());
00612 const float sval = pyr[slev].getValInterpScaled(**ilocn, indims);
00613
00614 const float val = cval - sval;
00615
00616
00617 imean->push_back(itsTakeAbs.getVal()
00618 ? fabs(val)
00619 : val);
00620 }
00621 }
00622 }
00623
00624
00625 void SingleChannel::killCaches()
00626 {
00627 GVX_TRACE(__PRETTY_FUNCTION__);
00628 ChannelBase::killCaches();
00629
00630 itsOutputCache.freeMem();
00631
00632
00633 if (started())
00634 for (uint i = 0; i < maxIndex(); ++i)
00635 itsSubmapCache[i] = Image<float>();
00636 }
00637
00638
00639 void SingleChannel::doInput(const InputFrame& inframe)
00640 {
00641 GVX_TRACE(__PRETTY_FUNCTION__);
00642
00643 if (!this->started())
00644 CLFATAL("must be start()-ed before using receiving any input");
00645
00646 ASSERT(inframe.grayFloat().initialized());
00647
00648
00649
00650 if (itsInputHandler.is_valid())
00651 {
00652 itsInputHandler->handleInput(*this, inframe.grayFloat(),
00653 inframe.time(), inframe.clipMask(),
00654 inframe.pyrCache());
00655 }
00656 else
00657 {
00658 setClipPyramid(inframe.clipMask());
00659 storePyramid(computePyramid(inframe.grayFloat(), inframe.pyrCache()),
00660 inframe.time());
00661 }
00662 }
00663
00664
00665 void SingleChannel::inputPyramid(const ImageSet<float>& pyr,
00666 const SimTime& t,
00667 const Image<byte>& clipMask)
00668 {
00669 GVX_TRACE(__PRETTY_FUNCTION__);
00670 killCaches();
00671 setClipPyramid(clipMask);
00672
00673 storePyramid(pyr, t);
00674 }
00675
00676
00677 ImageSet<float> SingleChannel::
00678 computePyramid(const Image<float>& bwimg,
00679 const rutz::shared_ptr<PyramidCache<float> >& cache)
00680 {
00681 GVX_TRACE(__PRETTY_FUNCTION__);
00682
00683
00684 ImageSet<float> py = itsPyrBuilder->
00685 build(bwimg, this->getMinPyrLevel(),
00686 this->getMaxPyrLevel(), cache.get());
00687
00688
00689 if (itsLowThresh.getVal() > 0.0f)
00690 {
00691 if (itsRectifyPyramid.getVal())
00692 doLowThresh(py, itsLowThresh.getVal());
00693 else
00694 doLowThreshAbs(py, itsLowThresh.getVal());
00695 }
00696 else if (itsRectifyPyramid.getVal())
00697 doRectify(py);
00698
00699
00700 return py;
00701 }
00702
00703
00704 void SingleChannel::storeOutputCache(const Image<float>& m)
00705 {
00706 GVX_TRACE(__PRETTY_FUNCTION__);
00707 itsOutputCache = m;
00708 }
00709
00710
00711 void SingleChannel::setClipPyramid(const Image<byte>& clipMask)
00712 {
00713 GVX_TRACE(__PRETTY_FUNCTION__);
00714
00715 if (clipMask.initialized())
00716 {
00717 itsClipPyr = buildPyrGaussian(Image<float>(clipMask)/255.0f,
00718 0, itsLevelSpec.getVal().maxDepth(), 9);
00719 doLowThresh(itsClipPyr, 1.0f, 0.0f);
00720 }
00721 else
00722 itsClipPyr.clear();
00723 }
00724
00725
00726 void SingleChannel::storeClipPyramid(const ImageSet<float>& p)
00727 {
00728 GVX_TRACE(__PRETTY_FUNCTION__);
00729 itsClipPyr = p;
00730 }
00731
00732
00733 void SingleChannel::storePyramid(const ImageSet<float>& p,
00734 const SimTime& t)
00735 {
00736 GVX_TRACE(__PRETTY_FUNCTION__);
00737
00738 itsPq.push_front(TPyr(p, t));
00739
00740
00741 while(int(itsPq.size()) > itsQlen.getVal()) itsPq.pop_back();
00742
00743
00744 ASSERT(isDyadic(itsPq.front().pyr.subSet
00745 (this->getMinPyrLevel(),
00746 this->getMaxPyrLevel())));
00747 }
00748
00749
00750 void SingleChannel::storeSubmapCache(const ImageSet<float>& p)
00751 {
00752 GVX_TRACE(__PRETTY_FUNCTION__);
00753 ASSERT(this->numSubmaps() == p.size());
00754 const uint maxind = this->numSubmaps();
00755 for (uint i = 0; i < maxind; ++i)
00756 this->itsSubmapCache[i] = p[i];
00757 }
00758
00759
00760 size_t SingleChannel::numPyramids() const
00761 {
00762 GVX_TRACE(__PRETTY_FUNCTION__);
00763 return itsPq.size();
00764 }
00765
00766
00767 const ImageSet<float>& SingleChannel::pyramid(const uint index) const
00768 {
00769 GVX_TRACE(__PRETTY_FUNCTION__);
00770 if (itsPq.empty()) CLFATAL("I have no input pyramid yet!");
00771 ASSERT(index < itsPq.size());
00772 return itsPq[index].pyr;
00773 }
00774
00775
00776 SimTime SingleChannel::pyramidTime(const uint index) const
00777 {
00778 GVX_TRACE(__PRETTY_FUNCTION__);
00779 if (itsPq.empty()) return SimTime::ZERO();
00780 ASSERT(index < itsPq.size());
00781 return itsPq[index].t;
00782 }
00783
00784
00785 const ImageSet<float>& SingleChannel::clipPyramid() const
00786 {
00787 GVX_TRACE(__PRETTY_FUNCTION__);
00788 return itsClipPyr;
00789 }
00790
00791
00792 LevelSpec SingleChannel::getLevelSpec() const
00793 {
00794 GVX_TRACE(__PRETTY_FUNCTION__);
00795 return itsLevelSpec.getVal();
00796 }
00797
00798
00799 int SingleChannel::getNormType() const
00800 {
00801 GVX_TRACE(__PRETTY_FUNCTION__);
00802 return itsNormType.getVal();
00803 }
00804
00805
00806 Image<float> SingleChannel::combineSubMaps()
00807 {
00808 GVX_TRACE(__PRETTY_FUNCTION__);
00809 Image<float> output(getMapDims(), ZEROS);
00810
00811
00812 for (uint idx = 0; idx < maxIndex(); ++idx)
00813 {
00814
00815 float w = 1.0;
00816 if (hasFacet<ChannelFacetGainSingle>())
00817 w = getFacet<ChannelFacetGainSingle>()->getVal(idx);
00818
00819 if (w != 0.0f)
00820 {
00821 Image<float> submap = getSubmap(idx);
00822
00823
00824 if (itsTempl[idx].initialized())
00825 {
00826 Image<float> img = templMatch(submap, itsTempl[idx]);
00827
00828
00829 Point2D<int> p; float maxval; findMax(img, p, maxval);
00830 img *= -1; img += maxval;
00831
00832
00833
00834 submap.clear(0.0F);
00835 inplacePaste(submap, img,
00836 Point2D<int>(itsTempl[idx].getWidth()/2,
00837 itsTempl[idx].getHeight()/2));
00838 }
00839
00840 if (w != 1.0f) submap *= w;
00841 output += submap;
00842
00843 if (MYLOGVERB >= LOG_DEBUG)
00844 {
00845 uint clev = 0, slev = 0;
00846 indexToCS(idx, clev, slev);
00847 LDEBUG("%s(%d,%d): weight %f", tagName().c_str(), clev, slev, w);
00848 }
00849
00850 if (itsGetSingleChannelStats.getVal()) saveStats(submap, idx);
00851 }
00852 }
00853
00854
00855 if(itsNormType.getVal() == VCXNORM_LANDMARK)
00856 {
00857 float goodness = pow(goodness_map(output), 0.1);
00858 LINFO("GOODNESS = %f", goodness);
00859 output *= goodness;
00860 }
00861 else if (itsNormalizeOutput.getVal())
00862 {
00863 LDEBUG("%s: Normalizing output: %s(%f .. %f)", tagName().c_str(),
00864 maxNormTypeName(itsNormType.getVal()), itsOutputRangeMin.getVal(),
00865 itsOutputRangeMax.getVal());
00866
00867 output = maxNormalize(output, itsOutputRangeMin.getVal(),
00868 itsOutputRangeMax.getVal(), itsNormType.getVal());
00869 }
00870
00871
00872 if (MYLOGVERB >= LOG_DEBUG)
00873 {
00874 float mi, ma; getMinMax(output, mi, ma);
00875 LDEBUG("%s: final range [%f .. %f]", tagName().c_str(), mi, ma);
00876 }
00877
00878 LINFO("Computed %s Conspicuity Map", descriptiveName().c_str());
00879
00880 if (itsGetSingleChannelStats.getVal()) saveStats(output, -1);
00881
00882 return output;
00883 }
00884
00885
00886 void SingleChannel::saveStats(const Image<float> img, const short idx)
00887 {
00888 std::string fileName;
00889
00890 if(itsSaveStatsPerChannel.getVal())
00891 {
00892 std::string dot = ".";
00893 std::string txt = ".txt";
00894 fileName = itsGetSingleChannelStatsFile.getVal()+ dot + tagName() + txt;
00895 }
00896 else
00897 fileName = itsGetSingleChannelStatsFile.getVal();
00898
00899 ushort minx = 0, miny = 0, maxx = 0, maxy = 0;
00900 float min, max, avg, std;
00901 uint N;
00902
00903 getMinMaxAvgEtc(img, min, max, avg, std, minx, miny, maxx, maxy, N);
00904
00905 std::ofstream statsFile(fileName.c_str(), std::ios::app);
00906
00907 statsFile << itsGetSingleChannelStatsTag.getVal() << "\t";
00908
00909 statsFile << itsFrameIdx << "\t";
00910
00911
00912
00913 if(idx == -1)
00914 {
00915 statsFile << "COMBINED\t-1\t";
00916 itsFrameIdx++;
00917 }
00918 else
00919 statsFile << "SCALE\t" << idx << "\t";
00920
00921 statsFile << tagName().c_str() << "\t" << descriptiveName().c_str() << "\t";
00922 statsFile << min << "\t" << max << "\t" << avg << "\t" << std << "\t"
00923 << minx << "\t" << miny << "\t" << maxx << "\t" << maxy << "\t"
00924 << N << "\n";
00925 statsFile.close();
00926
00927 if(itsSaveStatsPerChannelFreq.getVal())
00928 {
00929 std::string dot = ".";
00930 std::string txt = ".freq.txt";
00931 fileName = itsGetSingleChannelStatsFile.getVal()+ dot + tagName() + txt;
00932
00933 FFTWWrapper fft(img.getWidth(), img.getHeight());
00934 double dimg[img.getHeight() * img.getWidth()];
00935 Image<float>::const_iterator itr = img.begin();
00936 double *ditr = &dimg[0];
00937 while(itr != img.end()) *ditr++ = double(*itr++);
00938 fft.init(dimg);
00939 double mag[img.getHeight() * (img.getWidth()/2 + 1)];
00940 fft.compute(mag);
00941
00942 std::ofstream freqFile(fileName.c_str(), std::ios::app);
00943 freqFile << itsGetSingleChannelStatsTag.getVal() << "\t";
00944 freqFile << itsFrameIdx << "\t";
00945
00946
00947
00948 if(idx == -1) freqFile << "COMBINED\t-1\t";
00949 else freqFile << "SCALE\t" << idx << "\t";
00950
00951 freqFile << "SIZE\t" << img.getWidth() <<"\t"<< img.getHeight() << "\n";
00952
00953 for(int i = 0; i < img.getHeight(); i++)
00954 {
00955 for(int j = 0; j < (img.getWidth()/2 + 1); j++)
00956 freqFile << mag[i * (img.getWidth()/2 + 1) + j] << "\t";
00957 freqFile << "\n";
00958 }
00959 freqFile.close();
00960 }
00961 }
00962
00963
00964 Image<float> SingleChannel::getOutput()
00965 {
00966 GVX_TRACE(__PRETTY_FUNCTION__);
00967
00968 if (!this->hasInput())
00969
00970
00971 CLFATAL("Oops! can't get output -- I don't even have any input yet");
00972
00973 if (!this->outputAvailable())
00974 {
00975
00976
00977
00978
00979
00980 LERROR("No %s channel yet! -- IGNORING.", this->tagName().c_str());
00981 return Image<float>(this->getMapDims(), ZEROS);
00982 }
00983
00984 if (!itsOutputCache.initialized())
00985 itsOutputCache = combineSubMaps();
00986
00987 return itsOutputCache;
00988 }
00989
00990
00991 void SingleChannel::setPyramid(rutz::shared_ptr<PyrBuilder<float> > pbuild)
00992 {
00993 GVX_TRACE(__PRETTY_FUNCTION__);
00994 ASSERT(pbuild.get() != 0);
00995 itsPq.clear();
00996 itsPyrBuilder = pbuild;
00997 }
00998
00999
01000 ImageSet<float>& SingleChannel::pyrMut(const uint index)
01001 {
01002 GVX_TRACE(__PRETTY_FUNCTION__);
01003 ASSERT(index < itsPq.size());
01004 return itsPq[index].pyr;
01005 }
01006
01007
01008 uint SingleChannel::csToIndex(const uint centerlev,
01009 const uint surroundlev) const
01010 {
01011 GVX_TRACE(__PRETTY_FUNCTION__);
01012 return itsLevelSpec.getVal().csToIndex(centerlev, surroundlev);
01013 }
01014
01015
01016
01017 void SingleChannel::indexToCS(const uint index, uint& centerlev, uint& surroundlev) const
01018 {
01019 GVX_TRACE(__PRETTY_FUNCTION__);
01020 itsLevelSpec.getVal().indexToCS(index, centerlev, surroundlev);
01021 }
01022
01023
01024 uint SingleChannel::maxIndex() const
01025 {
01026 GVX_TRACE(__PRETTY_FUNCTION__);
01027 return itsLevelSpec.getVal().maxIndex();
01028 }
01029
01030
01031 void SingleChannel::saveResults(const nub::ref<FrameOstream>& ofs)
01032 {
01033 GVX_TRACE(__PRETTY_FUNCTION__);
01034 if (itsPq.empty() == false)
01035 {
01036
01037 if (itsSaveRawMaps.getVal()) {
01038 const ImageSet<float>& pyr = itsPq.front().pyr;
01039 for (uint i = 0; i < pyr.size(); i ++)
01040 {
01041
01042 ofs->writeFloat(pyr[i], FLOAT_NORM_0_255,
01043 sformat("SR%s-%d-", tagName().c_str(),i),
01044 FrameInfo(sformat("%s SingleChannel raw map (%u of %u)",
01045 this->descriptiveName().c_str(),
01046 i, pyr.size()),
01047 SRC_POS));
01048 }
01049 }
01050
01051
01052 if (itsSaveFeatureMaps.getVal())
01053 for (uint i = 0; i < numSubmaps(); i ++) {
01054 uint clev = 0, slev = 0;
01055 indexToCS(i, clev, slev);
01056 ofs->writeFloat(getSubmap(i),
01057 FLOAT_NORM_0_255,
01058 sformat("SF%s-%d-%d-", tagName().c_str(),clev, slev),
01059 FrameInfo(sformat("%s SingleChannel center-surround map (c=%u s=%u)",
01060 this->descriptiveName().c_str(),
01061 clev, slev),
01062 SRC_POS));
01063 }
01064 }
01065
01066
01067
01068 if (itsSaveOutputMap.getVal())
01069 ofs->writeFloat(getOutput(), FLOAT_NORM_0_255,
01070 sformat("SO%s-", tagName().c_str()),
01071 FrameInfo(sformat("%s SingleChannel output",
01072 this->descriptiveName().c_str()),
01073 SRC_POS));
01074 }
01075
01076
01077 void SingleChannel::setInputHandler(rutz::shared_ptr<InputHandler> h)
01078 {
01079 GVX_TRACE(__PRETTY_FUNCTION__);
01080 itsInputHandler = InputHandler::clone(h);
01081 }
01082
01083
01084 rutz::shared_ptr<InputHandler> SingleChannel::cloneInputHandler() const
01085 {
01086 GVX_TRACE(__PRETTY_FUNCTION__);
01087 return InputHandler::clone(itsInputHandler);
01088 }
01089
01090
01091 void SingleChannel::setSubmapAlgorithm(nub::ref<SubmapAlgorithm> algo)
01092 {
01093 GVX_TRACE(__PRETTY_FUNCTION__);
01094 this->removeSubComponent(*itsSubmapAlgo);
01095 itsSubmapAlgo = algo;
01096 this->addSubComponent(itsSubmapAlgo);
01097
01098 if (this->started() && !algo->started())
01099 itsSubmapAlgo->start();
01100 }
01101
01102
01103
01104
01105
01106