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