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 #include "Channels/SingleSvChannel.H"
00038 #include "SpaceVariant/SpaceVariantOpts.H"
00039
00040
00041 SingleSvChannel::SingleSvChannel(OptionManager& mgr, const std::string& descrName,
00042 const std::string& tag,const VisualFeature vs,
00043 const SpaceVariantModule& spacevariantmodule) :
00044 SingleChannel(mgr, descrName, tag, vs, rutz::shared_ptr<PyrBuilder<float> >()),
00045 itsChanDims(&OPT_SpaceVariantDims, this),
00046 itsLevels(&OPT_SpaceVariantChanScales, this),
00047 itsTakeSquare("TakeSquareRoot", this, false),
00048 isPolarized("IsPolarized", this, false),
00049 itsUseSpaceVariantBoundary("UseSpaceVariantBoundary", this, true),
00050 itsTransform(new SpaceVariantModule(mgr))
00051 {
00052 GVX_TRACE(__PRETTY_FUNCTION__);
00053
00054
00055 hideOption(&OPT_LevelSpec);
00056 }
00057
00058
00059 SingleSvChannel::~SingleSvChannel()
00060 {
00061 GVX_TRACE(__PRETTY_FUNCTION__);
00062 }
00063
00064
00065 ImageSet<float> SingleSvChannel::
00066 computePyramid(const Image<float>& bwimg,
00067 const rutz::shared_ptr<PyramidCache<float> >& cache)
00068 {
00069 GVX_TRACE(__PRETTY_FUNCTION__);
00070
00071 if (!cache.is_valid())
00072 LFATAL("Space variant channels should always get a cache from the retina");
00073
00074 ImageSet<float> py;
00075 itsTransform->transformFloatPyramid(bwimg, py, itsLevels.getVal(), cache->get());
00076
00077
00078 if (itsLowThresh.getVal() > 0.0f)
00079 {
00080 if (itsRectifyPyramid.getVal())
00081 doLowThresh(py, itsLowThresh.getVal());
00082 else
00083 doLowThreshAbs(py, itsLowThresh.getVal());
00084 }
00085 else if (itsRectifyPyramid.getVal())
00086 doRectify(py);
00087
00088
00089 return py;
00090 }
00091
00092
00093 Dims SingleSvChannel::getMapDims() const
00094 {
00095 GVX_TRACE(__PRETTY_FUNCTION__);
00096 return itsChanDims.getVal();
00097 }
00098
00099
00100 Image<float> SingleSvChannel::centerSurround(const uint cntrlev,
00101 const uint surrlev) const
00102 {
00103 GVX_TRACE(__PRETTY_FUNCTION__);
00104 LFATAL("We don't do center surround operations for this channel");
00105 return Image<float>();
00106 }
00107
00108
00109 void SingleSvChannel::centerSurround(const uint cntrlev, const uint surrlev,
00110 Image<float>& pos, Image<float>& neg) const
00111 {
00112 GVX_TRACE(__PRETTY_FUNCTION__);
00113 LFATAL("We don't do center surround operations for this channel");
00114 }
00115
00116
00117 std::string SingleSvChannel::getSubmapName(const uint idx) const
00118 {
00119 GVX_TRACE(__PRETTY_FUNCTION__);
00120 ASSERT(idx < numSubmaps());
00121 return sformat("%s lev ", descriptiveName().c_str(), idx);
00122 }
00123
00124
00125 std::string SingleSvChannel::getSubmapNameShort(const uint idx) const
00126 {
00127 GVX_TRACE(__PRETTY_FUNCTION__);
00128 ASSERT(idx < numSubmaps());
00129 return sformat("%s(%d)", tagName().c_str(), idx);
00130 }
00131
00132
00133 void SingleSvChannel::getFeatures(const Point2D<int>& locn,
00134 std::vector<float>& mean) const
00135 {
00136 GVX_TRACE(__PRETTY_FUNCTION__);
00137
00138 if (!this->outputAvailable())
00139 {
00140 CLDEBUG("I have no input pyramid yet -- RETURNING ZEROS");
00141 for (uint idx = 0; idx < numSubmaps(); idx ++) mean.push_back(0.0F);
00142 return;
00143 }
00144
00145 const ImageSet<float>& pyr = itsPq.front().pyr;
00146 const Dims indims = this->getInputDims();
00147
00148 for (uint idx = 0; idx < numSubmaps(); idx ++)
00149 {
00150
00151 ASSERT(pyr[idx].initialized());
00152 const float val = pyr[idx].getValInterpScaled(locn, indims);
00153
00154
00155 mean.push_back(val);
00156 }
00157 }
00158
00159
00160 void SingleSvChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn,
00161 std::vector<std::vector<float> > *mean,
00162 int *count) const
00163 {
00164 GVX_TRACE(__PRETTY_FUNCTION__);
00165
00166 if (!this->outputAvailable())
00167 {
00168 CLDEBUG("I have no input pyramid yet -- RETURNING ZEROS");
00169 for (uint idx = 0; idx < numSubmaps(); idx ++)
00170 {
00171 std::vector<std::vector<float> >::iterator imean = mean->begin();
00172 for(int i = 0; i < *count; i++, ++imean)
00173 imean->push_back(0.0);
00174 }
00175 return;
00176 }
00177
00178
00179
00180
00181
00182 const ImageSet<float>& pyr = itsPq.front().pyr;
00183 const Dims indims = this->getInputDims();
00184 const uint sm = numSubmaps();
00185 for (uint idx = 0; idx < sm; ++idx)
00186 {
00187 std::vector<Point2D<int>*>::iterator ilocn = locn->begin();
00188 std::vector<std::vector<float> >::iterator imean = mean->begin();
00189
00190 for (int i = 0; i < *count; ++i, ++ilocn, ++imean)
00191 {
00192
00193 ASSERT(pyr[clev].initialized());
00194 const float val = pyr[clev].getValInterpScaled(**ilocn, indims);
00195 }
00196 }
00197 }
00198
00199
00200 LevelSpec SingleSvChannel::getLevelSpec() const
00201 {
00202 GVX_TRACE(__PRETTY_FUNCTION__);
00203 LFATAL("Space variant channels do not use a LevelSpec");
00204 return itsLevelSpec.getVal();
00205 }
00206
00207
00208 void SingleSvChannel::setClipPyramid(const Image<byte>& clipMask)
00209 {
00210 GVX_TRACE(__PRETTY_FUNCTION__);
00211
00212 if (clipMask.initialized())
00213 {
00214 Image<float> mask = rescale(Image<float>(clipMask)/255.0f, getMapDims());
00215 itsClipPyr = ImageSet<float>(maxIndex());
00216 for (uint ii = 0; ii < maxIndex(); ++ii)
00217 itsClipPyr[ii] = mask;
00218 }
00219 else
00220 itsClipPyr.clear();
00221 }
00222
00223
00224 void SingleSvChannel::storePyramid(const ImageSet<float>& p,const SimTime& t)
00225 {
00226 GVX_TRACE(__PRETTY_FUNCTION__);
00227
00228 itsPq.push_front(TPyr(p, t));
00229
00230
00231 while(int(itsPq.size()) > itsQlen.getVal()) itsPq.pop_back();
00232
00233 ASSERT(itsPq.front().pyr.size() < this->getMaxPyrLevel());
00234 }
00235
00236
00237 Image<float> SingleSvChannel::getRawCSmap(const uint idx) const
00238 {
00239 GVX_TRACE(__PRETTY_FUNCTION__);
00240 ASSERT(itsLevelSpec.getVal().indexOK(idx));
00241 if (itsPq.empty()) CLFATAL("I have no input pyramid yet!");
00242
00243
00244
00245
00246
00247
00248 float w = 1.0;
00249 if (hasFacet<ChannelFacetGainSingle>())
00250 w = getFacet<ChannelFacetGainSingle>()->getVal(idx);
00251
00252
00253 if (w == 0.0f) return Image<float>(getMapDims(), ZEROS);
00254
00255 Image<float> submap;
00256
00257
00258
00259
00260
00261 if (itsUseSplitCS.getVal() && isPolarized.getVal())
00262 {
00263 Image<float> subpos, subneg;
00264 computeSubChanSplit(idx, subpos, subneg);
00265
00266
00267
00268
00269
00270
00271
00272 subpos = maxNormalize(subpos, 0.0f, 0.0f, itsNormType.getVal());
00273 subneg = maxNormalize(subneg, 0.0f, 0.0f, itsNormType.getVal());
00274
00275
00276
00277 submap = subpos + subneg;
00278 }
00279 else
00280 submap = computeSubChan(idx);
00281
00282
00283 if (MYLOGVERB >= LOG_DEBUG)
00284 {
00285 float mi, ma; getMinMax(submap, mi, ma);
00286 LDEBUG("%s(%d,%d): raw range [%f .. %f]", tagName().c_str(),
00287 clev, slev, mi, ma);
00288 }
00289
00290 return submap;
00291 }
00292
00293
00294 void SingleSvChannel::computeSubChanSplit(const uint idx, Image<float>& pos, Image<float>& neg) const
00295 {
00296
00297 const Image<float>& img = itsPq.front().pyr[idx];
00298 double t = itsPq.front().t.secs();
00299
00300 splitPosNeg(img, pos, neg);
00301
00302 else if (itsTakeSquare.getVal())
00303 {
00304 pos = squared(pos);
00305 neg = squared(neg);
00306 }
00307
00308
00309 for (uint i = 1; i < itsPq.size(); ++i)
00310 {
00311 const Image<float>& img2 = itsPq[i].pyr[idx];
00312 double t2 = itsPq[i].t.secs();
00313
00314
00315
00316 float fac = exp( (t2 - t) * itsTimeDecay.getVal());
00317
00318 const Image<float> pos2, neg2;
00319 splitPosNeg(img2, pos2, neg2);
00320
00321 if (itsTakeSquare.getVal())
00322 {
00323 pos2 = squared(pos2);
00324 neg2 = squared(neg2);
00325 }
00326 pos += pos2 * fac;
00327 neg += neg2 * fac;
00328 }
00329 }
00330
00331
00332 Image<float> SingleSvChannel::computeSubChan(const uint idx) const
00333 {
00334
00335 Image<float> img = itsPq.front().pyr[idx];
00336 double t = itsPq.front().t.secs();
00337
00338 if (itsTakeAbs.getVal())
00339 img = abs(img);
00340 else if (itsTakeSquare.getVal())
00341 img = squared(img);
00342
00343
00344 for (uint i = 1; i < itsPq.size(); ++i)
00345 {
00346 double t2 = itsPq[i].t.secs();
00347
00348
00349
00350 float fac = exp( (t2 - t) * itsTimeDecay.getVal());
00351
00352 if (itsTakeAbs.getVal())
00353 img = abs(itsPq[i].pyr[idx]) * fac;
00354 else if (itsTakeSquare.getVal())
00355 img = squared(itsPq[i].pyr[idx]) * fac;
00356 }
00357 return img;
00358 }
00359
00360
00361 int SingleSvChannel::getMinPyrLevel() const
00362 {
00363 return 0;
00364 }
00365
00366
00367 int SingleSvChannel::getMaxPyrLevel() const
00368 {
00369 return maxIndex();
00370 }
00371
00372
00373 void SingleSvChannel::start1()
00374 {
00375 GVX_TRACE(__PRETTY_FUNCTION__);
00376 SingleSvChannel::start1();
00377 }
00378
00379
00380 uint SingleSvChannel::csToIndex(const uint centerlev, const uint surroundlev) const
00381 {
00382 GVX_TRACE(__PRETTY_FUNCTION__);
00383 return centerlev;
00384 }
00385
00386
00387 void SingleSvChannel::indexToCS(const uint index, uint& centerlev, uint& surroundlev) const
00388 {
00389 GVX_TRACE(__PRETTY_FUNCTION__);
00390 centerlev = idx; surroundlev = maxIndex() + 1;
00391 }
00392
00393
00394 uint SingleSvChannel::maxIndex() const
00395 {
00396 GVX_TRACE(__PRETTY_FUNCTION__);
00397 return itsLevels.getVal().numLevels();
00398 }
00399
00400
00401
00402
00403
00404