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 #ifndef CHANNELS_INTEGERCOMPLEXCHANNEL_C_DEFINED
00039 #define CHANNELS_INTEGERCOMPLEXCHANNEL_C_DEFINED
00040
00041 #include "Channels/IntegerComplexChannel.H"
00042
00043 #include "Channels/ChannelOpts.H"
00044 #include "Channels/ChannelVisitor.H"
00045 #include "Component/OptionManager.H"
00046 #include "Component/ParamMap.H"
00047 #include "Image/IntegerMathOps.H"
00048 #include "Image/MathOps.H"
00049 #include "Image/ShapeOps.H"
00050 #include "Image/fancynorm.H"
00051 #include "Transport/FrameInfo.H"
00052 #include "Transport/FrameOstream.H"
00053 #include "Util/Assert.H"
00054 #include "Util/MathFunctions.H"
00055 #include "Util/log.H"
00056 #include "Util/sformat.H"
00057 #include "nub/ref.h"
00058 #include "rutz/shared_ptr.h"
00059 #include "rutz/trace.h"
00060
00061 #include <algorithm>
00062 #include <vector>
00063
00064 namespace dummy_namespace_to_avoid_gcc411_bug_IntegerComplexChannel_C
00065 {
00066 struct SubchanInfo
00067 {
00068 SubchanInfo(IntegerComplexChannel* owner, nub::ref<IntegerChannel> c)
00069 :
00070 chan(c),
00071 weight(NModelParam<double>::make
00072 (sformat("%s_weight", c->tagName().c_str()), owner, 1.0))
00073 {}
00074
00075 nub::ref<IntegerChannel> chan;
00076 rutz::shared_ptr<NModelParam<double> > weight;
00077 };
00078
00079 struct ChannelHierarchySorter
00080 {
00081 ChannelHierarchySorter(bool dosubmaps_)
00082 :
00083 dosubmaps(dosubmaps_)
00084 {}
00085
00086 bool operator()(const SubchanInfo& i1, const SubchanInfo& i2)
00087 {
00088 nub::ref<ChannelBase> chan1 = i1.chan;
00089 nub::ref<ChannelBase> chan2 = i2.chan;
00090
00091 const int level1 = int(featureHierarchyLevel(chan1->visualFeature()));
00092 const int level2 = int(featureHierarchyLevel(chan2->visualFeature()));
00093
00094 if (level1 < level2)
00095 return true;
00096
00097
00098
00099 if (dosubmaps && level1 == level2)
00100 return chan1->numSubmaps() > chan2->numSubmaps();
00101
00102
00103
00104 return false;
00105 }
00106
00107 bool dosubmaps;
00108 };
00109 }
00110
00111 using namespace dummy_namespace_to_avoid_gcc411_bug_IntegerComplexChannel_C;
00112
00113 struct IntegerComplexChannel::Impl
00114 {
00115 Impl()
00116 :
00117 sortChannelsByNumSubmaps(false)
00118 {}
00119
00120 Image<int> output;
00121 rutz::shared_ptr<ChannelVisitor> subchanVisitor;
00122
00123 std::vector<SubchanInfo> subchans;
00124
00125 bool sortChannelsByNumSubmaps;
00126
00127 SubchanInfo& findSubchanInfo(IntegerComplexChannel::SubchanKey key)
00128 {
00129 if (key.index != uint(-1))
00130 {
00131
00132
00133 if (key.index >= subchans.size())
00134 LFATAL("Ooops, no such sub-channel %u "
00135 "(I have only %"ZU" sub-channels)",
00136 key.index, subchans.size());
00137
00138 return subchans[key.index];
00139 }
00140 else if (key.tag != 0)
00141 {
00142
00143
00144 for (uint i = 0; i < subchans.size(); ++i)
00145 if (subchans[i].chan->tagName().compare(key.tag) == 0)
00146 return subchans[i];
00147
00148 LFATAL("Ooops, no such sub-channel '%s'", key.tag);
00149 }
00150 else if (key.addr != 0)
00151 {
00152
00153 for (uint i = 0; i < subchans.size(); ++i)
00154 if (subchans[i].chan.get() == key.addr)
00155 return subchans[i];
00156
00157 LFATAL("no such sub-channel '%s'", key.addr->tagName().c_str());
00158 }
00159
00160 LFATAL("Ooops, invalid SubchanKey (one of index, tag, or address "
00161 "must be valid)");
00162 return subchans[0];
00163 }
00164 };
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 IntegerComplexChannel::
00175 IntegerComplexChannel(OptionManager& mgr,
00176 const std::string& descrName,
00177 const std::string& tag,
00178 const VisualFeature vs,
00179 nub::ref<IntegerMathEngine> eng)
00180 :
00181 IntegerChannel(mgr, descrName, tag, vs, eng),
00182 itsNormType(&OPT_MaxNormType, this),
00183 itsSaveOutputMap(&OPT_ComplexChannelSaveOutputMap, this),
00184 itsUseOlderVersion(&OPT_UseOlderVersion, this),
00185 itsOutputRangeMin(&OPT_IntChannelOutputRangeMin, this),
00186 itsOutputRangeMax(&OPT_IntChannelOutputRangeMax, this),
00187 rep(new Impl)
00188 {
00189 GVX_TRACE(__PRETTY_FUNCTION__);
00190 }
00191
00192
00193 IntegerComplexChannel::~IntegerComplexChannel()
00194 {
00195 GVX_TRACE(__PRETTY_FUNCTION__);
00196 delete rep;
00197 }
00198
00199
00200 void IntegerComplexChannel::start1()
00201 {
00202 GVX_TRACE(__PRETTY_FUNCTION__);
00203
00204 std::stable_sort(rep->subchans.begin(), rep->subchans.end(),
00205 ChannelHierarchySorter(rep->sortChannelsByNumSubmaps));
00206 }
00207
00208
00209 void IntegerComplexChannel::start2()
00210 {
00211 GVX_TRACE(__PRETTY_FUNCTION__);
00212
00213
00214
00215 if (itsUseOlderVersion.getVal() == false)
00216 {
00217 itsOutputRangeMin.setVal(0);
00218 itsOutputRangeMax.setVal(0);
00219 }
00220
00221
00222
00223
00224
00225 if (itsUseOlderVersion.getVal() && itsNormType.getVal() != VCXNORM_MAXNORM)
00226 {
00227 itsOutputRangeMin.setVal(0);
00228 itsOutputRangeMax.setVal(0);
00229 }
00230 }
00231
00232
00233 void IntegerComplexChannel::stop2()
00234 {
00235 GVX_TRACE(__PRETTY_FUNCTION__);
00236 }
00237
00238
00239 bool IntegerComplexChannel::isHomogeneous() const
00240 {
00241 GVX_TRACE("IntegerComplexChannel::isHomogeneous");
00242
00243 for (uint i = 0; i < this->numChans(); ++i)
00244 {
00245 if (subChan(i)->visualFeature() != this->visualFeature()
00246 || (subChan(i)->isHomogeneous() == false))
00247 return false;
00248 }
00249
00250 return true;
00251 }
00252
00253
00254 uint IntegerComplexChannel::numChans() const
00255 {
00256 GVX_TRACE(__PRETTY_FUNCTION__);
00257 return rep->subchans.size();
00258 }
00259
00260
00261 nub::ref<IntegerChannel> IntegerComplexChannel::subChan(const uint idx) const
00262 {
00263 GVX_TRACE(__PRETTY_FUNCTION__);
00264 if (idx >= rep->subchans.size())
00265 LFATAL("Ooops, no such sub-channel %u (I have only %"ZU" sub-channels)",
00266 idx, rep->subchans.size());
00267
00268 return rep->subchans[idx].chan;
00269 }
00270
00271
00272 nub::ref<IntegerChannel> IntegerComplexChannel::subChan(const std::string& tagname) const
00273 {
00274 GVX_TRACE(__PRETTY_FUNCTION__);
00275
00276 for (uint i = 0; i < rep->subchans.size(); ++i)
00277 if (rep->subchans[i].chan->tagName() == tagname)
00278 return rep->subchans[i].chan;
00279
00280 LFATAL("Ooops, no such sub-channel '%s'", tagname.c_str());
00281
00282 return nub::ref<IntegerChannel>((IntegerChannel*)0);
00283 }
00284
00285
00286 nub::ref<IntegerChannel> IntegerComplexChannel::
00287 subChanFromSubmapNum(const uint oldIdx,
00288 uint& newIdx) const
00289 {
00290 GVX_TRACE(__PRETTY_FUNCTION__);
00291 ASSERT(oldIdx < numSubmaps());
00292 uint subchan = 0;
00293 lookupSubmap(oldIdx, subchan, newIdx);
00294
00295 return subChan(subchan);
00296 }
00297
00298
00299 void IntegerComplexChannel::readFrom(const ParamMap& pmap)
00300 {
00301 GVX_TRACE(__PRETTY_FUNCTION__);
00302 IntegerChannel::readFrom(pmap);
00303 ChannelFacetMap::readFacetsFrom(pmap);
00304
00305 for (uint i = 0; i < numChans(); ++i)
00306 {
00307 const std::string tagname = subChan(i)->tagName();
00308 if (pmap.hasParam(tagname))
00309 {
00310 rutz::shared_ptr<ParamMap> submap = pmap.getSubpmap(tagname);
00311 subChan(i)->readFrom(*submap);
00312
00313 double wt = rep->subchans[i].weight->getVal();
00314
00315 if (submap->queryDoubleParam("weight", wt) == ParamMap::MISSING)
00316 rep->subchans[i].weight->setVal(1.0);
00317 else
00318 rep->subchans[i].weight->setVal(wt);
00319 }
00320 }
00321 }
00322
00323
00324 void IntegerComplexChannel::writeTo(ParamMap& pmap) const
00325 {
00326 GVX_TRACE(__PRETTY_FUNCTION__);
00327 IntegerChannel::writeTo(pmap);
00328 ChannelFacetMap::writeFacetsTo(pmap);
00329
00330 for (uint i = 0; i < numChans(); ++i)
00331 {
00332 rutz::shared_ptr<ParamMap> submap(new ParamMap);
00333 subChan(i)->writeTo(*submap);
00334 submap->putDoubleParam("weight", rep->subchans[i].weight->getVal());
00335 pmap.putSubpmap(subChan(i)->tagName(), submap);
00336 }
00337 }
00338
00339
00340 bool IntegerComplexChannel::outputAvailable() const
00341 {
00342 GVX_TRACE(__PRETTY_FUNCTION__);
00343 for (uint i = 0; i < numChans(); ++i)
00344 if (subChan(i)->outputAvailable() == false) return false;
00345 return true;
00346 }
00347
00348
00349 Dims IntegerComplexChannel::getMapDims() const
00350 {
00351 GVX_TRACE(__PRETTY_FUNCTION__);
00352 return subChan(0)->getMapDims();
00353 }
00354
00355
00356 uint IntegerComplexChannel::numSubmaps() const
00357 {
00358 GVX_TRACE(__PRETTY_FUNCTION__);
00359 uint sum = 0;
00360 for (uint i = 0; i < numChans(); ++i) sum += subChan(i)->numSubmaps();
00361 return sum;
00362 }
00363
00364
00365 void IntegerComplexChannel::lookupSubmap(const uint idx, uint& subchan,
00366 uint& subidx) const
00367 {
00368 GVX_TRACE(__PRETTY_FUNCTION__);
00369 ASSERT(idx < numSubmaps());
00370 uint offset = 0;
00371 for (subchan = 0; subchan < numChans(); ++subchan)
00372 {
00373 subidx = idx - offset;
00374 const uint nsub = subChan(subchan)->numSubmaps();
00375 if (subidx < nsub)
00376 {
00377
00378 return;
00379 }
00380 else
00381 offset += nsub;
00382 }
00383 LFATAL("invalid submap index: %d", idx);
00384 }
00385
00386
00387 Image<int> IntegerComplexChannel::getSubmapInt(const uint idx) const
00388 {
00389 GVX_TRACE(__PRETTY_FUNCTION__);
00390 uint subchan = 0, subidx = 0;
00391 lookupSubmap(idx, subchan, subidx);
00392 return subChan(subchan)->getSubmapInt(subidx);
00393 }
00394
00395
00396 Image<int> IntegerComplexChannel::getRawCSmapInt(const uint idx) const
00397 {
00398 GVX_TRACE(__PRETTY_FUNCTION__);
00399 uint subchan = 0, subidx = 0;
00400 lookupSubmap(idx, subchan, subidx);
00401 return subChan(subchan)->getRawCSmapInt(subidx);
00402 }
00403
00404
00405 std::string IntegerComplexChannel::getSubmapName(const uint idx) const
00406 {
00407 GVX_TRACE(__PRETTY_FUNCTION__);
00408 uint subchan = 0, subidx = 0;
00409 lookupSubmap(idx, subchan, subidx);
00410 return subChan(subchan)->getSubmapName(subidx);
00411 }
00412
00413
00414 std::string IntegerComplexChannel::getSubmapNameShort(const uint idx) const
00415 {
00416 GVX_TRACE(__PRETTY_FUNCTION__);
00417 uint subchan = 0, subidx = 0;
00418 lookupSubmap(idx, subchan, subidx);
00419 return subChan(subchan)->getSubmapNameShort(subidx);
00420 }
00421
00422
00423 void IntegerComplexChannel::getFeatures(const Point2D<int>& locn,
00424 std::vector<float>& mean) const
00425 {
00426 LFATAL("not implemented");
00427 }
00428
00429
00430 void IntegerComplexChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn,
00431 std::vector<std::vector<float> > *mean,
00432 int *count) const
00433 {
00434 LFATAL("not implemented");
00435 }
00436
00437
00438 void IntegerComplexChannel::addSubChan(nub::ref<IntegerChannel> ch,
00439 const char* tagname)
00440 {
00441 GVX_TRACE(__PRETTY_FUNCTION__);
00442
00443
00444 if (tagname != 0 && *tagname != '\0')
00445 ch->setTagName(tagname);
00446
00447
00448 this->addSubComponent(ch);
00449
00450
00451 rep->subchans.push_back(SubchanInfo(this, ch));
00452
00453
00454 if (rep->subchanVisitor.is_valid())
00455 ch->accept(*rep->subchanVisitor);
00456 }
00457
00458
00459 void IntegerComplexChannel::removeSubChan(nub::ref<IntegerChannel> ch)
00460 {
00461 GVX_TRACE(__PRETTY_FUNCTION__);
00462
00463 std::vector<SubchanInfo>::iterator itr = rep->subchans.begin();
00464
00465 while (itr != rep->subchans.end())
00466 {
00467 if ((*itr).chan == ch)
00468 {
00469 itr = rep->subchans.erase(itr);
00470 this->removeSubComponent(*ch);
00471 }
00472 else
00473 ++itr;
00474 }
00475 }
00476
00477
00478 void IntegerComplexChannel::removeAllSubChans()
00479 {
00480 GVX_TRACE(__PRETTY_FUNCTION__);
00481
00482 while (rep->subchans.size() > 0)
00483 {
00484 this->removeSubComponent(*(rep->subchans.back().chan));
00485 rep->subchans.pop_back();
00486 }
00487
00488 ASSERT(rep->subchans.size() == 0);
00489 }
00490
00491
00492 bool IntegerComplexChannel::hasSubChan(const char* tagname) const
00493 {
00494 GVX_TRACE(__PRETTY_FUNCTION__);
00495 for (uint i = 0; i < rep->subchans.size(); ++i)
00496 if (rep->subchans[i].chan->tagName().compare(tagname) == 0)
00497 return true;
00498
00499 return false;
00500 }
00501
00502
00503 void IntegerComplexChannel::setSubchanVisitor(rutz::shared_ptr<ChannelVisitor> v)
00504 {
00505 GVX_TRACE(__PRETTY_FUNCTION__);
00506 rep->subchanVisitor = v;
00507
00508
00509 if (rep->subchanVisitor.is_valid())
00510 for (uint i = 0; i < this->numChans(); ++i)
00511 subChan(i)->accept(*rep->subchanVisitor);
00512 }
00513
00514
00515 void IntegerComplexChannel::setSubchanTotalWeight(SubchanKey key, const double wt)
00516 {
00517 this->killCaches();
00518 rep->findSubchanInfo(key).weight->setVal(wt);
00519 }
00520
00521
00522 double IntegerComplexChannel::getSubchanTotalWeight(SubchanKey key) const
00523 {
00524 return rep->findSubchanInfo(key).weight->getVal();
00525 }
00526
00527
00528 void IntegerComplexChannel::sortChannelsByNumSubmaps(bool dosort)
00529 {
00530 GVX_TRACE(__PRETTY_FUNCTION__);
00531 if (this->started())
00532 LFATAL("This must be called before start()");
00533
00534 rep->sortChannelsByNumSubmaps = dosort;
00535 }
00536
00537
00538 void IntegerComplexChannel::killCaches()
00539 {
00540 GVX_TRACE(__PRETTY_FUNCTION__);
00541 IntegerChannel::killCaches();
00542
00543
00544 rep->output.freeMem();
00545
00546
00547 for (uint i = 0; i < numChans(); ++i) subChan(i)->killCaches();
00548 }
00549
00550
00551 Image<int> IntegerComplexChannel::getOutputInt()
00552 {
00553 GVX_TRACE(__PRETTY_FUNCTION__);
00554 if (!rep->output.initialized()) rep->output = combineOutputsInt();
00555 return rep->output;
00556 }
00557
00558
00559 Image<int> IntegerComplexChannel::combineOutputsInt()
00560 {
00561 GVX_TRACE(__PRETTY_FUNCTION__);
00562 Image<int> output(getMapDims(), ZEROS);
00563 for (uint i = 0; i < numChans(); ++i)
00564 {
00565 const Image<int> subChanOut = subChan(i)->getOutputInt();
00566
00567 ASSERT(subChanOut.initialized());
00568
00569 output += (subChanOut / int(numChans()));
00570 }
00571
00572 LDEBUG("%s: Normalizing output: %s(%d .. %d)", tagName().c_str(),
00573 maxNormTypeName(itsNormType.getVal()),
00574 itsOutputRangeMin.getVal(),
00575 itsOutputRangeMax.getVal());
00576 output = intgMaxNormalize(output, itsOutputRangeMin.getVal(),
00577 itsOutputRangeMax.getVal(), itsNormType.getVal());
00578
00579
00580
00581 if (MYLOGVERB >= LOG_DEBUG)
00582 {
00583 int mi, ma; getMinMax(output, mi, ma);
00584 LDEBUG("%s: final range [%d .. %d]", tagName().c_str(), mi, ma);
00585 }
00586
00587 LINFO("Computed %s Conspicuity Map", descriptiveName().c_str());
00588
00589 return output;
00590 }
00591
00592
00593 void IntegerComplexChannel::saveResults(const nub::ref<FrameOstream>& ofs)
00594 {
00595 GVX_TRACE(__PRETTY_FUNCTION__);
00596
00597 if (itsSaveOutputMap.getVal())
00598 ofs->writeFloat(Image<float>(getOutputInt()), FLOAT_NORM_0_255,
00599 sformat("ICO%s-", tagName().c_str()),
00600 FrameInfo(sformat("%s IntegerComplexChannel output",
00601 this->descriptiveName().c_str()),
00602 SRC_POS));
00603
00604
00605 for (uint i = 0; i < numChans(); ++i) subChan(i)->saveResults(ofs);
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615 #endif // CHANNELS_INTEGERCOMPLEXCHANNEL_C_DEFINED