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/IntegerRawVisualCortex.H"
00039 
00040 #include "Channels/ChannelOpts.H"
00041 #include "Channels/IntegerColorChannel.H"
00042 #include "Channels/IntegerFlickerChannel.H"
00043 #include "Channels/IntegerIntensityChannel.H"
00044 #include "Channels/IntegerMotionChannel.H"
00045 #include "Channels/IntegerOrientationChannel.H"
00046 #include "Component/GlobalOpts.H"
00047 #include "Component/OptionManager.H"
00048 #include "Component/ParamMap.H"
00049 #include "Image/ColorOps.H"   
00050 #include "Image/IntegerMathOps.H"
00051 #include "Image/MathOps.H"    
00052 #include "Image/Pixels.H"
00053 #include "Image/PyramidCache.H"
00054 #include "Image/ShapeOps.H"
00055 #include "Image/Transforms.H" 
00056 #include "Channels/ChannelOpts.H"
00057 #include "Transport/FrameInfo.H"
00058 #include "Transport/FrameOstream.H"
00059 #include "Util/TextLog.H"
00060 #include "Util/sformat.H"
00061 #include "rutz/mutex.h"
00062 #include "rutz/trace.h"
00063 
00064 #include <algorithm>
00065 #include <cctype>
00066 #include <cstdio>
00067 #include <vector>
00068 #include <sstream>
00069 
00070 
00071 IntegerRawVisualCortex::
00072 IntegerRawVisualCortex(OptionManager& mgr,
00073                     nub::ref<IntegerMathEngine> eng,
00074                     const std::string& descrName,
00075                     const std::string& tag) :
00076   IntegerComplexChannel(mgr, descrName, tag, UNKNOWN, eng),
00077   itsType(&OPT_IntegerRawVisualCortexChans, this),
00078   itsLogFile(&OPT_TextLogFile, this),
00079   itsNormType(&OPT_MaxNormType, this), 
00080   itsUseRandom(&OPT_UseRandom, this),  
00081   itsOutputFactor(&OPT_RawVisualCortexOutputFactor, this), 
00082   itsUseOlderVersion(&OPT_UseOlderVersion, this), 
00083   itsLevelSpec(&OPT_LevelSpec, this),
00084   itsSaveOutput(&OPT_RawVisualCortexSaveOutput, this),
00085   itsUseMax(&OPT_VCXuseMax, this)
00086 {
00087 GVX_TRACE(__PRETTY_FUNCTION__);
00088 }
00089 
00090 
00091 IntegerRawVisualCortex::~IntegerRawVisualCortex()
00092 {
00093 GVX_TRACE(__PRETTY_FUNCTION__);
00094 }
00095 
00096 
00097 void IntegerRawVisualCortex::start1()
00098 {
00099 GVX_TRACE(__PRETTY_FUNCTION__);
00100 
00101   IntegerComplexChannel::start1();
00102 
00103   for (uint i = 0; i < this->numChans(); ++i)
00104     LINFO("Top-level channel (%u/%u): level=%s feature=%s submaps=%u name=%s",
00105           i+1, uint(this->numChans()),
00106           featureHierarchyName(featureHierarchyLevel(this->subChan(i)->visualFeature())),
00107           featureName(this->subChan(i)->visualFeature()),
00108           this->subChan(i)->numSubmaps(), this->subChan(i)->descriptiveName().c_str());
00109 }
00110 
00111 
00112 void IntegerRawVisualCortex::stop2()
00113 {
00114 GVX_TRACE(__PRETTY_FUNCTION__);
00115 
00116   IntegerComplexChannel::stop2();
00117 }
00118 
00119 
00120 Image<int> IntegerRawVisualCortex::getChannelOutputMap(IntegerChannel& chan) const
00121 {
00122   float total_weight = 0.0;
00123 
00124   for (uint i = 0; i < this->numChans(); ++i)
00125     {
00126       nub::ref<IntegerChannel> c = this->subChan(i);
00127 
00128       if (itsUseOlderVersion.getVal())
00129         {
00130           const float w = float(this->getSubchanTotalWeight(*c) / c->numSubmaps());
00131           total_weight += w;
00132         }
00133       else
00134         {
00135           const float w = float(this->getSubchanTotalWeight(*c));
00136           total_weight += w;
00137         }
00138     }
00139 
00140   
00141 
00142 
00143 
00144 
00145 
00146 
00147 
00148 
00149 
00150 
00151 
00152 
00153 
00154 
00155 
00156 
00157 
00158 
00159   const int scalebits = 8;
00160 
00161   Image<int> chanOut = chan.getOutputInt();
00162   chanOut >>= scalebits;
00163 
00164   if (itsUseOlderVersion.getVal())
00165     {
00166       const float w = float(this->getSubchanTotalWeight(chan) / chan.numSubmaps());
00167 
00168       const int iw = int( 0.5 + (w*(1<<scalebits)) / total_weight );
00169 
00170       chanOut *= iw;
00171       LINFO("%s weight %d/%d",
00172             chan.tagName().c_str(), iw, (1<<scalebits));
00173     }
00174   else
00175     {
00176       const float w = float(this->getSubchanTotalWeight(chan));
00177 
00178       const int iw = int( 0.5 + (w*(1<<scalebits)) / total_weight );
00179 
00180       chanOut *= iw;
00181       LINFO("%s weight %d/%d", chan.tagName().c_str(), iw, (1<<scalebits));
00182     }
00183 
00184   return chanOut;
00185 }
00186 
00187 
00188 Image<int> IntegerRawVisualCortex::postProcessOutputMap(const Image<int>& outmap)
00189 {
00190   Image<int> result = outmap;
00191 
00192   
00193   switch(itsNormType.getVal())
00194     {
00195     case VCXNORM_LANDMARK:
00196     case VCXNORM_SURPRISE:
00197       LFATAL("Unsupported VCXNORM type");
00198       break;
00199     default:
00200       result = intgMaxNormalize(result, 0, 32768, itsNormType.getVal());
00201       LDEBUG("%s(%d .. %d)", maxNormTypeName(itsNormType.getVal()), 0, 32768);
00202       break;
00203     }
00204 
00205   return result;
00206 }
00207 
00208 
00209 void IntegerRawVisualCortex::doInputInt(const IntegerInput& inp,
00210                                      const SimTime& t,
00211                                      PyramidCache<int>* cache,
00212                                      const Image<byte>& clipMask)
00213 {
00214   ASSERT(inp.grayInt().initialized());
00215 
00216   
00217   if (this->numChans() == 0) return;
00218 
00219   rutz::mutex_lock_class lock;
00220   if (cache && cache->gaussian5.beginSet(inp.grayInt(), &lock))
00221     {
00222       cache->gaussian5.endSet
00223         (inp.grayInt(),
00224          intgBuildPyrGaussian
00225          (inp.grayInt(), itsLevelSpec.getVal().maxDepth(),
00226           5, this->getImath()),
00227          &lock);
00228     }
00229 
00230   
00231   for (uint i = 0; i < this->numChans(); ++i)
00232     {
00233       
00234       nub::ref<IntegerChannel> chan = this->subChan(i);
00235 
00236       
00237       chan->inputInt(inp, t, cache, clipMask);
00238       LINFO("Input to %s channel %s ok.", featureHierarchyName(featureHierarchyLevel(chan->visualFeature())),
00239             chan->tagName().c_str());
00240     }
00241 }
00242 
00243 
00244 Image<int> IntegerRawVisualCortex::combineOutputsInt()
00245 {
00246 GVX_TRACE(__PRETTY_FUNCTION__);
00247 
00248   Image<int> output;
00249 
00250   
00251   for (uint i = 0; i < this->numChans(); ++i)
00252     {
00253       nub::ref<IntegerChannel> ch = subChan(i);
00254 
00255       
00256       
00257       if (this->getSubchanTotalWeight(*ch) == 0.0) continue;
00258       if (ch->outputAvailable() == false) continue;
00259 
00260       const Image<int> chanOut = getChannelOutputMap(*ch);
00261 
00262       
00263       
00264       
00265       
00266       
00267       if (output.initialized() == false)
00268         output = chanOut;
00269       else
00270         {
00271           
00272           Image<int> o = intgDownSize(chanOut, output.getDims(), 9, this->getImath());
00273           if (itsUseMax.getVal()) output = takeMax(output, o); else output += o;
00274         }
00275     }
00276 
00277   
00278   
00279   if (output.initialized() == false)
00280     {
00281       int sml = itsLevelSpec.getVal().mapLevel();
00282       output = Image<int>(this->getInputDims().w() >> sml, this->getInputDims().h() >> sml, ZEROS);
00283       return output;
00284     }
00285 
00286   if (MYLOGVERB >= LOG_DEBUG)
00287     {
00288       int mi, ma; getMinMax(output, mi, ma);
00289       LDEBUG("Raw output range is [%d .. %d]", mi, ma);
00290     }
00291 
00292   
00293   
00294   output = postProcessOutputMap(output);
00295 
00296   LINFO("Computed IntegerRawVisualCortex output.");
00297   return output;
00298 }
00299 
00300 
00301 Image<float> IntegerRawVisualCortex::getOutput()
00302 {
00303   
00304   
00305   const float fac = itsOutputFactor.getVal() / (1 << this->getMathEngine()->getNbits());
00306   Image<float> output = getOutputInt() * fac;
00307 
00308   float mi, ma; getMinMax(output, mi, ma);
00309   LINFO("Salmap input range is [%f .. %f] nA", mi * 1.0e9F, ma * 1.0e9F);
00310 
00311   return output;
00312 }
00313 
00314 
00315 void IntegerRawVisualCortex::paramChanged(ModelParamBase* const param,
00316                                           const bool valueChanged,
00317                                           ParamClient::ChangeStatus* status)
00318 {
00319   ModelComponent::paramChanged(param, valueChanged, status);
00320   OptionManager& mgr = this->getManager();
00321   nub::ref<IntegerMathEngine> eng = this->getMathEngine();
00322 
00323   if (param == &itsType) {
00324     
00325     this->removeAllSubChans();
00326     ASSERT(this->numChans() == 0);
00327 
00328     
00329     
00330     
00331     
00332     
00333     uint i = 0; const std::string& str = itsType.getVal(); const uint len = str.length();
00334     double wc = 0.0, wi = 0.0, wo = 0.0, wf = 0.0, wm = 0.0;
00335 
00336     while (i < len) {
00337       char c = str[i];  
00338       double weight = 1.0;  
00339 
00340       
00341       if (i < len - 1 && str[i+1] == ':') {
00342         if (i >= len - 2) LFATAL("Missing channel weight value");
00343         uint end = str.find_first_not_of(".0123456789", i+2);
00344         std::stringstream s; s << str.substr(i+2, end); s >> weight;
00345         i = end;  
00346       } else ++i;
00347 
00348       switch(c) {
00349       case 'C': wc = weight; break;
00350       case 'I': wi = weight; break;
00351       case 'O': wo = weight; break;
00352       case 'F': wf = weight; break;
00353       case 'M': wm = weight; break;
00354       default: LFATAL("Unsupported channel type '%c' with weight %f", c, weight);
00355       }
00356     }
00357 
00358       
00359     if (wc) {
00360       LINFO("Using a Double Opponent ColorChannel with weight %f", wc);
00361       addSubChan(makeSharedComp(new IntegerColorChannel(mgr, eng)), "int-color");
00362       setSubchanTotalWeight("int-color", wc);
00363     }
00364     if (wf) {
00365       LINFO("Using a FlickerChannel with weight %f", wf);
00366       addSubChan(makeSharedComp(new IntegerFlickerChannel(mgr, eng)), "int-flicker");
00367       setSubchanTotalWeight("int-flicker", wf);
00368     }
00369     if (wi) {
00370       LINFO("Using an IntensityChannel with weight %f", wi);
00371       addSubChan(makeSharedComp(new IntegerIntensityChannel(mgr, eng)), "int-intensity");
00372       setSubchanTotalWeight("int-intensity", wi);
00373     }
00374     if (wo) {
00375       LINFO("Using an OrientationChannel with weight %f", wo);
00376       addSubChan(makeSharedComp(new IntegerOrientationChannel(mgr, eng)), "int-orientation");
00377       setSubchanTotalWeight("int-orientation", wo);
00378     }
00379     if (wm) {
00380       LINFO("Using a MotionChannel with weight %f", wm);
00381       addSubChan(makeSharedComp(new IntegerMotionChannel(mgr, eng)), "int-motion");
00382       setSubchanTotalWeight("int-motion", wm);
00383     }
00384 
00385     
00386     for (uint i = 0; i < this->numChans(); ++i) this->subChan(i)->exportOptions(MC_RECURSE);
00387   }
00388 }
00389 
00390 
00391 void IntegerRawVisualCortex::saveResults(const nub::ref<FrameOstream>& ofs)
00392 {
00393 GVX_TRACE(__PRETTY_FUNCTION__);
00394   
00395   if (itsSaveOutput.getVal())
00396     ofs->writeFloat(Image<float>(getOutputInt()), FLOAT_NORM_0_255, "IVCO",
00397                     FrameInfo("integer visual cortex output (input to saliency map)", SRC_POS));
00398 
00399   
00400   for (uint i = 0; i < numChans(); ++i) subChan(i)->saveResults(ofs);
00401 }
00402 
00403 
00404 
00405 
00406 
00407 
00408