ComplexChannel.C

Go to the documentation of this file.
00001 /*!@file Channels/ComplexChannel.C Channel class that pools across multiple
00002   subchannels. */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Channels/ComplexChannel.C $
00036 // $Id: ComplexChannel.C 14487 2011-02-08 18:57:45Z dberg $
00037 //
00038 
00039 #include "Channels/ComplexChannel.H"
00040 
00041 #include "Channels/ChannelOpts.H"
00042 #include "Channels/ChannelVisitor.H"
00043 #include "Channels/ChannelFacets.H"
00044 #include "Component/OptionManager.H"
00045 #include "Component/ParamMap.H"
00046 #include "Image/MathOps.H"
00047 #include "Image/ShapeOps.H"
00048 #include "Image/fancynorm.H"
00049 #include "Transport/FrameInfo.H"
00050 #include "Transport/FrameOstream.H"
00051 #include "Util/Assert.H"
00052 #include "Util/MathFunctions.H"
00053 #include "Util/log.H"
00054 #include "Util/sformat.H"
00055 #include "rutz/shared_ptr.h"
00056 #include "rutz/trace.h"
00057 
00058 #include <algorithm>
00059 #include <vector>
00060 
00061 namespace dummy_namespace_to_avoid_gcc411_bug_ComplexChannel_C
00062 {
00063   struct SubchanInfo
00064   {
00065     SubchanInfo(ComplexChannel* owner, nub::ref<ChannelBase> c,
00066                 const double wt = 1.0)
00067       :
00068       chan(c),
00069       weight(NModelParam<double>::make
00070              (sformat("%s_weight", c->tagName().c_str()), owner, wt))
00071     {}
00072 
00073     nub::ref<ChannelBase> chan;
00074     rutz::shared_ptr<NModelParam<double> > weight;
00075   };
00076 
00077   struct ChannelHierarchySorter
00078   {
00079     ChannelHierarchySorter(bool dosubmaps_)
00080       :
00081       dosubmaps(dosubmaps_)
00082     {}
00083 
00084     bool operator()(const SubchanInfo& i1, const SubchanInfo& i2)
00085     {
00086       nub::ref<ChannelBase> chan1 = i1.chan;
00087       nub::ref<ChannelBase> chan2 = i2.chan;
00088 
00089       const int level1 = int(featureHierarchyLevel(chan1->visualFeature()));
00090       const int level2 = int(featureHierarchyLevel(chan2->visualFeature()));
00091 
00092       if (level1 < level2)
00093         return true;
00094 
00095       // else ...
00096 
00097       if (dosubmaps && level1 == level2)
00098         return chan1->numSubmaps() > chan2->numSubmaps();
00099 
00100       // else ...
00101 
00102       return false;
00103     }
00104 
00105     bool dosubmaps;
00106   };
00107 }
00108 
00109 using namespace dummy_namespace_to_avoid_gcc411_bug_ComplexChannel_C;
00110 
00111 struct ComplexChannel::Impl
00112 {
00113   Impl()
00114     :
00115     sortChannelsByNumSubmaps(false)
00116   {}
00117 
00118   Image<float> output;
00119   rutz::shared_ptr<ChannelVisitor>  subchanVisitor; // apply to all newly-added subchannels
00120 
00121   std::vector<SubchanInfo> subchans;
00122 
00123   bool sortChannelsByNumSubmaps;
00124 
00125   SubchanInfo& findSubchanInfo(ComplexChannel::SubchanKey key)
00126   {
00127     if (key.index != uint(-1))
00128       {
00129         // ok, the index is valid, let's look up based on that:
00130 
00131         if (key.index >= subchans.size())
00132           LFATAL("Ooops, no such sub-channel %u "
00133                  "(I have only %"ZU" sub-channels)",
00134                  key.index, subchans.size());
00135 
00136         return subchans[key.index];
00137       }
00138     else if (key.tag != 0)
00139       {
00140         // ok, the tagname is valid, let's look up based on that:
00141 
00142         for (uint i = 0; i < subchans.size(); ++i)
00143           if (subchans[i].chan->tagName().compare(key.tag) == 0)
00144             return subchans[i];
00145 
00146         LFATAL("Ooops, no such sub-channel '%s'", key.tag);
00147       }
00148     else if (key.addr != 0)
00149       {
00150         // ok, the address is valid, let's look up based on that:
00151         for (uint i = 0; i < subchans.size(); ++i)
00152           if (subchans[i].chan.get() == key.addr)
00153             return subchans[i];
00154 
00155         LFATAL("no such sub-channel '%s'", key.addr->tagName().c_str());
00156       }
00157 
00158     LFATAL("Ooops, invalid SubchanKey (one of index, tag, or address "
00159            "must be valid)");
00160     return subchans[0]; // keep compiler happy
00161   }
00162 };
00163 
00164 // ######################################################################
00165 // ######################################################################
00166 // ComplexChannel member definitions:
00167 // ######################################################################
00168 // ######################################################################
00169 
00170 
00171 // ######################################################################
00172 ComplexChannel::ComplexChannel(OptionManager& mgr,
00173                                const std::string& descrName,
00174                                const std::string& tag,
00175                                const VisualFeature vs) :
00176   ChannelBase(mgr, descrName, tag, vs),
00177   itsNormType(&OPT_MaxNormType, this),
00178   itsCombineType(&OPT_ComplexChannelMapCombineType, this),
00179   itsSaveOutputMap(&OPT_ComplexChannelSaveOutputMap, this),
00180   itsUseOlderVersion(&OPT_UseOlderVersion, this),
00181   itsUseSpaceVariantBoundary("UseSpaceVariantBoundary", this, false),
00182   itsOutputRangeMin(&OPT_ChannelOutputRangeMin, this),
00183   itsOutputRangeMax(&OPT_ChannelOutputRangeMax, this),
00184   rep(new Impl)
00185 {
00186 GVX_TRACE(__PRETTY_FUNCTION__);
00187 }
00188 
00189 // ######################################################################
00190 ComplexChannel::~ComplexChannel()
00191 {
00192 GVX_TRACE(__PRETTY_FUNCTION__);
00193   delete rep;
00194 }
00195 
00196 // ######################################################################
00197 void ComplexChannel::start1()
00198 {
00199 GVX_TRACE(__PRETTY_FUNCTION__);
00200 
00201   std::stable_sort(rep->subchans.begin(), rep->subchans.end(),
00202                    ChannelHierarchySorter(rep->sortChannelsByNumSubmaps));
00203 }
00204 
00205 // ######################################################################
00206 void ComplexChannel::start2()
00207 {
00208 GVX_TRACE(__PRETTY_FUNCTION__);
00209 
00210   // in the new version, leave our output range open rather than
00211   // forcing it to a given range of values:
00212   if (itsUseOlderVersion.getVal() == false)
00213     {
00214       itsOutputRangeMin.setVal(0.0f);
00215       itsOutputRangeMax.setVal(0.0f);
00216     }
00217 
00218   // in the older version, we used to set the map range as we would
00219   // also apply spatial competition for salience to the output map,
00220   // only if using the MAXNORM type of competition, and otherwise we
00221   // would not touch the range:
00222   if (itsUseOlderVersion.getVal() && itsNormType.getVal() != VCXNORM_MAXNORM)
00223     {
00224       itsOutputRangeMin.setVal(0.0f);
00225       itsOutputRangeMax.setVal(0.0f);
00226     }
00227 
00228   // if we are in space variant mode, make sure our subchannels
00229   // handle those types of images
00230   for (uint i = 0; i < this->numChans(); ++i)
00231     if (itsUseSpaceVariantBoundary.getVal())
00232       if (this->subChan(i)->hasModelParam("UseSpaceVariantBoundary", MC_IGNORE_MISSING) == false)
00233         LFATAL("All channels must support space variant image boundary "
00234                "conditions when using a retinal type 'RetinaCT'");
00235 }
00236 
00237 // ######################################################################
00238 void ComplexChannel::stop2()
00239 {
00240 GVX_TRACE(__PRETTY_FUNCTION__);
00241 }
00242 
00243 // ######################################################################
00244 void ComplexChannel::accept(ChannelVisitor& v)
00245 {
00246 GVX_TRACE(__PRETTY_FUNCTION__);
00247   v.visitComplexChannel(*this);
00248 }
00249 
00250 // ######################################################################
00251 bool ComplexChannel::isHomogeneous() const
00252 {
00253 GVX_TRACE("ComplexChannel::isHomogeneous");
00254 
00255   for (uint i = 0; i < this->numChans(); ++i)
00256     {
00257       if (subChan(i)->visualFeature() != this->visualFeature()
00258           || (subChan(i)->isHomogeneous() == false))
00259         return false;
00260     }
00261 
00262   return true;
00263 }
00264 
00265 // ######################################################################
00266 uint ComplexChannel::numChans() const
00267 {
00268 GVX_TRACE(__PRETTY_FUNCTION__);
00269   return rep->subchans.size();
00270 }
00271 
00272 // ######################################################################
00273 nub::ref<ChannelBase> ComplexChannel::subChan(const uint idx) const
00274 {
00275 GVX_TRACE(__PRETTY_FUNCTION__);
00276   if (idx >= rep->subchans.size())
00277     LFATAL("Ooops, no such sub-channel %u (I have only %"ZU" sub-channels)",
00278            idx, rep->subchans.size());
00279 
00280   return rep->subchans[idx].chan;
00281 }
00282 
00283 // ######################################################################
00284 nub::ref<ChannelBase> ComplexChannel::subChan(const std::string& tagname) const
00285 {
00286 GVX_TRACE(__PRETTY_FUNCTION__);
00287 
00288   for (uint i = 0; i < rep->subchans.size(); ++i)
00289     if (rep->subchans[i].chan->tagName() == tagname)
00290       return rep->subchans[i].chan;
00291 
00292   LFATAL("Ooops, no such sub-channel '%s'", tagname.c_str());
00293 
00294   /* can't happen */ return nub::ref<ChannelBase>((ChannelBase*)0);
00295 }
00296 
00297 // ######################################################################
00298 nub::ref<ChannelBase> ComplexChannel::
00299 subChanFromSubmapNum(const uint oldIdx,
00300                      uint& newIdx) const
00301 {
00302 GVX_TRACE(__PRETTY_FUNCTION__);
00303   ASSERT(oldIdx < numSubmaps());
00304   uint subchan = 0;
00305   lookupSubmap(oldIdx, subchan, newIdx);
00306 
00307   return subChan(subchan);
00308 }
00309 
00310 // ######################################################################
00311 void ComplexChannel::readFrom(const ParamMap& pmap)
00312 {
00313 GVX_TRACE(__PRETTY_FUNCTION__);
00314   ChannelBase::readFrom(pmap);
00315   ChannelFacetMap::readFacetsFrom(pmap);
00316 
00317   for (uint i = 0; i < numChans(); ++i)
00318     {
00319       const std::string tagname = subChan(i)->tagName();
00320       if (pmap.hasParam(tagname))
00321         {
00322           rutz::shared_ptr<ParamMap> submap = pmap.getSubpmap(tagname);
00323           subChan(i)->readFrom(*submap);
00324 
00325           double wt = rep->subchans[i].weight->getVal();
00326 
00327           if (submap->queryDoubleParam("weight", wt) == ParamMap::MISSING)
00328             rep->subchans[i].weight->setVal(1.0);
00329           else
00330             rep->subchans[i].weight->setVal(wt);
00331         }
00332     }
00333 }
00334 
00335 // ######################################################################
00336 void ComplexChannel::writeTo(ParamMap& pmap) const
00337 {
00338 GVX_TRACE(__PRETTY_FUNCTION__);
00339 
00340   ChannelBase::writeTo(pmap);
00341   ChannelFacetMap::writeFacetsTo(pmap);
00342 
00343   for (uint i = 0; i < numChans(); ++i)
00344     {
00345       rutz::shared_ptr<ParamMap> submap(new ParamMap);
00346       subChan(i)->writeTo(*submap);
00347       submap->putDoubleParam("weight", rep->subchans[i].weight->getVal());
00348       submap->putDoubleParam("subchanindex", i);
00349       pmap.putSubpmap(subChan(i)->tagName(), submap);
00350     }
00351 }
00352 
00353 // ######################################################################
00354 bool ComplexChannel::outputAvailable() const
00355 {
00356 GVX_TRACE(__PRETTY_FUNCTION__);
00357   for (uint i = 0; i < numChans(); ++i)
00358     if (subChan(i)->outputAvailable() == false) return false;
00359   return true;
00360 }
00361 
00362 // ######################################################################
00363 Dims ComplexChannel::getMapDims() const
00364 {
00365 GVX_TRACE(__PRETTY_FUNCTION__);
00366   return subChan(0)->getMapDims();
00367 }
00368 
00369 // ######################################################################
00370 uint ComplexChannel::numSubmaps() const
00371 {
00372 GVX_TRACE(__PRETTY_FUNCTION__);
00373   uint sum = 0;
00374   for (uint i = 0; i < numChans(); ++i) sum += subChan(i)->numSubmaps();
00375   return sum;
00376 }
00377 
00378 // ######################################################################
00379 void ComplexChannel::lookupSubmap(const uint idx, uint& subchan,
00380                                   uint& subidx) const
00381 {
00382 GVX_TRACE(__PRETTY_FUNCTION__);
00383   ASSERT(idx < numSubmaps());
00384   uint offset = 0;
00385   for (subchan = 0; subchan < numChans(); ++subchan)
00386     {
00387       subidx = idx - offset;
00388       const uint nsub = subChan(subchan)->numSubmaps();
00389       if (subidx < nsub)
00390         {
00391           // OK, we have found the right subchan+submap combination:
00392           return;
00393         }
00394       else
00395         offset += nsub;
00396     }
00397   LFATAL("invalid submap index: %d", idx);
00398 }
00399 
00400 // ######################################################################
00401 Image<float> ComplexChannel::getSubmap(const uint idx) const
00402 {
00403 GVX_TRACE(__PRETTY_FUNCTION__);
00404   uint subchan = 0, subidx = 0;
00405   lookupSubmap(idx, subchan, subidx);
00406   return subChan(subchan)->getSubmap(subidx);
00407 }
00408 
00409 // ######################################################################
00410 Image<float> ComplexChannel::getRawCSmap(const uint idx) const
00411 {
00412 GVX_TRACE(__PRETTY_FUNCTION__);
00413   uint subchan = 0, subidx = 0;
00414   lookupSubmap(idx, subchan, subidx);
00415   return subChan(subchan)->getRawCSmap(subidx);
00416 }
00417 
00418 // ######################################################################
00419 std::string ComplexChannel::getSubmapName(const uint idx) const
00420 {
00421 GVX_TRACE(__PRETTY_FUNCTION__);
00422   uint subchan = 0, subidx = 0;
00423   lookupSubmap(idx, subchan, subidx);
00424   return subChan(subchan)->getSubmapName(subidx);
00425 }
00426 
00427 // ######################################################################
00428 std::string ComplexChannel::getSubmapNameShort(const uint idx) const
00429 {
00430 GVX_TRACE(__PRETTY_FUNCTION__);
00431   uint subchan = 0, subidx = 0;
00432   lookupSubmap(idx, subchan, subidx);
00433   return subChan(subchan)->getSubmapNameShort(subidx);
00434 }
00435 
00436 // ######################################################################
00437 void ComplexChannel::getFeatures(const Point2D<int>& locn,
00438                                  std::vector<float>& mean) const
00439 {
00440 GVX_TRACE(__PRETTY_FUNCTION__);
00441   for(uint i = 0; i < numChans(); ++i)
00442     subChan(i)->getFeatures(locn, mean);
00443 }
00444 
00445 // ######################################################################
00446 void ComplexChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn,
00447                                       std::vector<std::vector<float> > *mean,
00448                                       int *count) const
00449 {
00450 GVX_TRACE(__PRETTY_FUNCTION__);
00451   for (uint i = 0; i < numChans(); ++i)
00452     subChan(i)->getFeaturesBatch(locn, mean, count);
00453 }
00454 
00455 // ######################################################################
00456 void ComplexChannel::addSubChan(nub::ref<ChannelBase> ch,
00457                                 const char* tagname,
00458                                 const double weight,
00459                                 bool exportOpts)
00460 {
00461 GVX_TRACE(__PRETTY_FUNCTION__);
00462 
00463   // if the user gave us a name for the channel, then let's rename it:
00464   if (tagname != 0 && *tagname != '\0')
00465     ch->setTagName(tagname);
00466 
00467   // take ownership of the subchannel:
00468   this->addSubComponent(ch);
00469 
00470   // add it to our list of subchannels:
00471   rep->subchans.push_back(SubchanInfo(this, ch, weight));
00472 
00473   // apply our subchannel visitor to the new subchannel:
00474   if (rep->subchanVisitor.is_valid())
00475     ch->accept(*rep->subchanVisitor);
00476 
00477   if (exportOpts)
00478     ch->exportOptions(MC_RECURSE);
00479 }
00480 
00481 // ######################################################################
00482 void ComplexChannel::removeSubChan(nub::ref<ChannelBase> ch)
00483 {
00484 GVX_TRACE(__PRETTY_FUNCTION__);
00485 
00486   std::vector<SubchanInfo>::iterator itr = rep->subchans.begin();
00487 
00488   while (itr != rep->subchans.end())
00489     {
00490       if ((*itr).chan == ch)
00491         {
00492           itr = rep->subchans.erase(itr);
00493           this->removeSubComponent(*ch);
00494         }
00495       else
00496         ++itr;
00497     }
00498 }
00499 
00500 // ######################################################################
00501 void ComplexChannel::removeAllSubChans()
00502 {
00503 GVX_TRACE(__PRETTY_FUNCTION__);
00504 
00505   while (rep->subchans.size() > 0)
00506     {
00507       this->removeSubComponent(*(rep->subchans.back().chan));
00508       rep->subchans.pop_back();
00509     }
00510 
00511   ASSERT(rep->subchans.size() == 0);
00512 }
00513 
00514 // ######################################################################
00515 bool ComplexChannel::hasSubChan(const char* tagname) const
00516 {
00517 GVX_TRACE(__PRETTY_FUNCTION__);
00518   for (uint i = 0; i < rep->subchans.size(); ++i)
00519     if (rep->subchans[i].chan->tagName().compare(tagname) == 0)
00520       return true;
00521 
00522   return false;
00523 }
00524 
00525 // ######################################################################
00526 void ComplexChannel::setSubchanVisitor(rutz::shared_ptr<ChannelVisitor> v)
00527 {
00528 GVX_TRACE(__PRETTY_FUNCTION__);
00529   rep->subchanVisitor = v;
00530 
00531   // now apply the visitor to any subchannels that we already have:
00532   if (rep->subchanVisitor.is_valid())
00533     for (uint i = 0; i < this->numChans(); ++i)
00534       subChan(i)->accept(*rep->subchanVisitor);
00535 }
00536 
00537 // ######################################################################
00538 void ComplexChannel::setSubchanTotalWeight(SubchanKey key, const double wt)
00539 {
00540   this->killCaches();
00541   rep->findSubchanInfo(key).weight->setVal(wt);
00542 }
00543 
00544 // ######################################################################
00545 double ComplexChannel::getSubchanTotalWeight(SubchanKey key) const
00546 {
00547   return rep->findSubchanInfo(key).weight->getVal();
00548 }
00549 
00550 // ######################################################################
00551 void ComplexChannel::sortChannelsByNumSubmaps(bool dosort)
00552 {
00553 GVX_TRACE(__PRETTY_FUNCTION__);
00554   if (this->started())
00555     LFATAL("This must be called before start()");
00556 
00557   rep->sortChannelsByNumSubmaps = dosort;
00558 }
00559 
00560 // ######################################################################
00561 void ComplexChannel::killCaches()
00562 {
00563 GVX_TRACE(__PRETTY_FUNCTION__);
00564   ChannelBase::killCaches(); // call our base class's implementation
00565 
00566   // free our own output cache:
00567   rep->output.freeMem();
00568 
00569   // propagate to our subchannels:
00570   for (uint i = 0; i < numChans(); ++i) subChan(i)->killCaches();
00571 }
00572 
00573 // ######################################################################
00574 Image<float> ComplexChannel::getOutput()
00575 {
00576 GVX_TRACE(__PRETTY_FUNCTION__);
00577   if (!rep->output.initialized()) rep->output = combineOutputs();
00578   return rep->output;
00579 }
00580 
00581 // ######################################################################
00582 Image<float> ComplexChannel::combineOutputs()
00583 {
00584 GVX_TRACE(__PRETTY_FUNCTION__);
00585   Image<float> output; // leave uninitialized so that mapCombine() can
00586                        // do the Right Thing on the first call
00587 
00588   uint num_nzw = 0; // number of subchans with non-zero weights
00589 
00590   for (uint i = 0; i < numChans(); ++i)
00591     {
00592       // Determine the weight for each subchan. This is the product of
00593       // the intrinsic weight of each subchan (which is set either
00594       // through the --vc-chans config string of VisualCortex for
00595       // top-level channels, or subject to static modifications by
00596       // using --load at the start of the entire model and setting the
00597       // NModelParam value associated with each channel), multiplied
00598       // by any possible extra top-down gain if we have a
00599       // ChannelFacetGainComplex:
00600       float w = float(rep->subchans[i].weight->getVal());
00601 
00602       if (w != 0.0F) ++num_nzw;
00603 
00604       if (hasFacet<ChannelFacetGainComplex>())
00605         w *= getFacet<ChannelFacetGainComplex>()->getVal(i);
00606 
00607       if (w != 0.0f)
00608         {
00609           Image<float> subChanOut = subChan(i)->getOutput();
00610 
00611           if (subChanOut.getDims() != this->getMapDims())
00612             LFATAL("Oops! In \"%s\", the output of "
00613                    "\"%s\" (sub-channel %u/%u) was expected to be "
00614                    "%dx%d, but was actually %dx%d",
00615                    this->tagName().c_str(),
00616                    subChan(i)->tagName().c_str(),
00617                    i+1, this->numChans(),
00618                    output.getWidth(), output.getHeight(),
00619                    subChanOut.getWidth(), subChanOut.getHeight());
00620 
00621           if (w != 1.0f) subChanOut *= w;
00622 
00623           output = mapCombine(itsCombineType.getVal(),
00624                               output, subChanOut);
00625 
00626           if (MYLOGVERB >= LOG_DEBUG)
00627             {
00628               float mi, ma, av; getMinMaxAvg(subChanOut, mi, ma, av);
00629               LDEBUG("%s: %s weight %f, range %g .. %g (mean %g)",
00630                      tagName().c_str(),
00631                      subChan(i)->tagName().c_str(), w, mi, ma, av);
00632             }
00633         }
00634     }
00635 
00636   // if we didn't have any subchannel outputs, then just fill our
00637   // output with zeros
00638   if (!output.initialized())
00639     output = Image<float>(getMapDims(), ZEROS);
00640 
00641   // apply max-normalization on the output as needed, but only if we
00642   // have more than one subchan with non-zero weight; otherwise, that
00643   // means that we are just a shell for a singlechannel and should not
00644   // add this extra maxnorm:
00645   if (num_nzw > 1)
00646     {
00647       if (itsNormType.getVal() == VCXNORM_LANDMARK)
00648         {
00649           float goodness = pow(goodness_map(output), 0.05);
00650           LINFO("GOODNESS = %f", goodness);
00651           output *= goodness;
00652         }
00653       else
00654         {
00655           LDEBUG("%s: Normalizing output: %s(%f .. %f)", tagName().c_str(),
00656                  maxNormTypeName(itsNormType.getVal()), itsOutputRangeMin.getVal(),
00657                  itsOutputRangeMax.getVal());
00658           output = maxNormalize(output, itsOutputRangeMin.getVal(),
00659                                 itsOutputRangeMax.getVal(), itsNormType.getVal());
00660         }
00661     }
00662 
00663   // print some debug info if in debug mode:
00664   if (MYLOGVERB >= LOG_DEBUG)
00665     {
00666       float mi, ma; getMinMax(output, mi, ma);
00667       LDEBUG("%s: final range [%f .. %f]", tagName().c_str(), mi, ma);
00668     }
00669 
00670   LINFO("Computed %s Conspicuity Map", descriptiveName().c_str());
00671 
00672   return output;
00673 }
00674 
00675 // ######################################################################
00676 void ComplexChannel::saveResults(const nub::ref<FrameOstream>& ofs)
00677 {
00678 GVX_TRACE(__PRETTY_FUNCTION__);
00679   // save our own map:
00680   if (itsSaveOutputMap.getVal())
00681     {
00682       std::string name = sformat("CO%s-", tagName().c_str());
00683 
00684       LINFO("SAVING RESULTS %s",name.c_str());
00685 
00686       ofs->writeFloat(getOutput(), FLOAT_NORM_0_255, name,
00687                       FrameInfo(sformat("%s ComplexChannel output",
00688                                         this->descriptiveName().c_str()),
00689                                 SRC_POS));
00690     }
00691 
00692   // now do it for our subchannels:
00693   for (uint i = 0; i < numChans(); ++i) subChan(i)->saveResults(ofs);
00694 }
00695 
00696 // ######################################################################
00697 /* So things look consistent in everyone's emacs... */
00698 /* Local Variables: */
00699 /* indent-tabs-mode: nil */
00700 /* End: */
Generated on Sun May 8 08:40:21 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3