IntegerComplexChannel.C

Go to the documentation of this file.
00001 /*!@file Channels/IntegerComplexChannel.C */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Channels/IntegerComplexChannel.C $
00035 // $Id: IntegerComplexChannel.C 12820 2010-02-11 05:44:51Z itti $
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       // else ...
00098 
00099       if (dosubmaps && level1 == level2)
00100         return chan1->numSubmaps() > chan2->numSubmaps();
00101 
00102       // else ...
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; // apply to all newly-added subchannels
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         // ok, the index is valid, let's look up based on that:
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         // ok, the tagname is valid, let's look up based on that:
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         // ok, the address is valid, let's look up based on that:
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]; // keep compiler happy
00163   }
00164 };
00165 
00166 // ######################################################################
00167 // ######################################################################
00168 // IntegerComplexChannel member definitions:
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   // in the new version, leave our output range open rather than
00214   // forcing it to a given range of values:
00215   if (itsUseOlderVersion.getVal() == false)
00216     {
00217       itsOutputRangeMin.setVal(0);
00218       itsOutputRangeMax.setVal(0);
00219     }
00220 
00221   // in the older version, we used to set the map range as we would
00222   // also apply spatial competition for salience to the output map,
00223   // only if using the MAXNORM type of competition, and otherwise we
00224   // would not touch the range:
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   /* can't happen */ 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           // OK, we have found the right subchan+submap combination:
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   // if the user gave us a name for the channel, then let's rename it:
00444   if (tagname != 0 && *tagname != '\0')
00445     ch->setTagName(tagname);
00446 
00447   // take ownership of the subchannel:
00448   this->addSubComponent(ch);
00449 
00450   // add it to our list of subchannels:
00451   rep->subchans.push_back(SubchanInfo(this, ch));
00452 
00453   // apply our subchannel visitor to the new subchannel:
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   // now apply the visitor to any subchannels that we already have:
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(); // call our base class's implementation
00542 
00543   // free our own output cache:
00544   rep->output.freeMem();
00545 
00546   // propagate to our subchannels:
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   // apply max-normalization on the output as needed:
00580   // print some debug info if in debug mode:
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   // save our own map:
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   // now do it for our subchannels:
00605   for (uint i = 0; i < numChans(); ++i) subChan(i)->saveResults(ofs);
00606 }
00607 
00608 // ######################################################################
00609 /* So things look consistent in everyone's emacs... */
00610 /* Local Variables: */
00611 /* mode: c++ */
00612 /* indent-tabs-mode: nil */
00613 /* End: */
00614 
00615 #endif // CHANNELS_INTEGERCOMPLEXCHANNEL_C_DEFINED
Generated on Sun May 8 08:40:21 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3