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 #ifndef NEURO_ENVSALIENCYMAP_C_DEFINED
00039 #define NEURO_ENVSALIENCYMAP_C_DEFINED
00040
00041 #include "Neuro/EnvSaliencyMap.H"
00042
00043 #include "Component/GlobalOpts.H"
00044 #include "Component/ModelOptionDef.H"
00045 #include "Image/MathOps.H"
00046 #include "Image/DrawOps.H"
00047 #include "Image/ShapeOps.H"
00048 #include "Neuro/EnvOpts.H"
00049 #include "Util/MathFunctions.H"
00050 #include "Util/TextLog.H"
00051 #include "Util/log.H"
00052
00053 static const ModelOptionCateg MOC_ESM = {
00054 MOC_SORTPRI_3, "EnvSaliencyMap-related Options" };
00055
00056
00057 const ModelOptionDef OPT_EsmUseFixed =
00058 { MODOPT_FLAG, "EsmUseFixed", &MOC_ESM, OPTEXP_CORE,
00059 "Whether to use a fixed center-of-attention given by the user",
00060 "esm-use-fixed", '\0', "", "false" };
00061
00062
00063 const ModelOptionDef OPT_EsmFixedX =
00064 { MODOPT_ARG(int), "EsmFixedX", &MOC_ESM, OPTEXP_CORE,
00065 "X coordinate of fixed center-of-atteniton location",
00066 "esm-fixed-x", '\0', "int", "20" };
00067
00068
00069 const ModelOptionDef OPT_EsmFixedY =
00070 { MODOPT_ARG(int), "EsmFixedY", &MOC_ESM, OPTEXP_CORE,
00071 "Y coordinate of fixed center-of-atteniton location",
00072 "esm-fixed-y", '\0', "int", "15" };
00073
00074
00075 const ModelOptionDef OPT_GetNMostSalientLoc =
00076 { MODOPT_ARG(int), "GetNMostSalientLoc", &MOC_ESM, OPTEXP_CORE,
00077 "Return a vector with the stop n most salient locations",
00078 "get-nmost-salient-loc", '\0', "int", "1" };
00079
00080
00081 const ModelOptionDef OPT_InternalIORRadius =
00082 { MODOPT_ARG(int), "InternalIORRadius", &MOC_ESM, OPTEXP_CORE,
00083 "The size of the internal IOR in pixels used for retrieving the N Most salient locations. "
00084 " This options will not change the actual saliency map.",
00085 "internal-ior-radius", '\0', "int", "10" };
00086
00087
00088 const ModelOptionDef OPT_EsmIorHalfLife =
00089 { MODOPT_ARG(double), "EsmIorHalfLife", &MOC_ESM, OPTEXP_CORE,
00090 "Number of frames in which the IOR map decays by half",
00091 "esm-ior-halflife", '\0', "<double>", "6.5" };
00092
00093
00094 const ModelOptionDef OPT_EsmIorStrength =
00095 { MODOPT_ARG(double), "EsmIorStrength", &MOC_ESM, OPTEXP_CORE,
00096 "Magnitude of IOR (useful range 0..255)",
00097 "esm-ior-strength", '\0', "<double>", "16.0" };
00098
00099
00100 const ModelOptionDef OPT_EsmIorRadius =
00101 { MODOPT_ARG(double), "EsmIorRadius", &MOC_ESM, OPTEXP_CORE,
00102 "Radius of IOR",
00103 "esm-ior-radius", '\0', "<double>", "32.0" };
00104
00105
00106 const ModelOptionDef OPT_EsmInertiaRadius =
00107 { MODOPT_ARG(double), "EsmInertiaRadius", &MOC_ESM, OPTEXP_CORE,
00108 "Radius of inertia blob",
00109 "esm-inertia-radius", '\0', "<double>", "32.0" };
00110
00111
00112 const ModelOptionDef OPT_EsmInertiaStrength =
00113 { MODOPT_ARG(double), "EsmInertiaStrength", &MOC_ESM, OPTEXP_CORE,
00114 "Initial strength of inertia blob",
00115 "esm-inertia-strength", '\0', "<double>", "100.0" };
00116
00117
00118 const ModelOptionDef OPT_EsmInertiaHalfLife =
00119 { MODOPT_ARG(double), "EsmInertiaHalfLife", &MOC_ESM, OPTEXP_CORE,
00120 "Number of frames in which the inertia blob decays by half",
00121 "esm-inertia-halflife", '\0', "<double>", "6.5" };
00122
00123
00124 const ModelOptionDef OPT_EsmInertiaShiftThresh =
00125 { MODOPT_ARG(double), "EsmInertiaShiftThresh", &MOC_ESM, OPTEXP_CORE,
00126 "Distance threshold for inertia shift",
00127 "esm-inertia-thresh", '\0', "<double>", "5.0" };
00128
00129 static const ModelOptionDef OPT_DynamicFeedback =
00130 { MODOPT_ARG(double), "DynamicFeedback", &MOC_ESM, OPTEXP_CORE,
00131 "How strongly the amount of temporal change in the visual cortex "
00132 "output causes suppression of IOR and inertia. A large value means "
00133 "that IOR and inertia will be totally suppressed by a small amount "
00134 "of temporal change in the visual cortex output, while a value of "
00135 "0.0 means that IOR and inertia will not be suppressed at all, "
00136 "regardless of the amount of temporal change in the visual cortex "
00137 "output.",
00138 "dynamic-feedback", '\0', "<double>", "1.5" };
00139
00140
00141 static double meanAbsDiff(const Image<float>* x,
00142 const Image<byte>* y)
00143 {
00144 ASSERT(x->getDims() == y->getDims());
00145
00146 double sum = 0.0;
00147
00148 const size_t sz = x->getSize();
00149
00150 const Image<float>::const_iterator xptr = x->begin();
00151 const Image<byte>::const_iterator yptr = y->begin();
00152
00153 for (size_t i = 0; i < sz; ++i)
00154 sum += fabs(xptr[i] - yptr[i]);
00155
00156 return sz > 0 ? sum/sz : 0.0;
00157 }
00158
00159
00160 static double sigmoid(double v)
00161 {
00162 return 1.0 / (1.0 + exp(-v));
00163 }
00164
00165
00166 EnvSaliencyMap::EnvSaliencyMap(OptionManager& mgr)
00167 :
00168 ModelComponent(mgr, "Embeddable Saliency Map", "EnvSaliencyMap"),
00169 itsInertiaLoc(-1,-1),
00170 itsCurrentInertiaFactor(1.0),
00171 itsInertiaMap(),
00172 itsInhibMap(),
00173 itsUseFixed(&OPT_EsmUseFixed, this, ALLOW_ONLINE_CHANGES),
00174 itsFixedX(&OPT_EsmFixedX, this, ALLOW_ONLINE_CHANGES),
00175 itsFixedY(&OPT_EsmFixedY, this, ALLOW_ONLINE_CHANGES),
00176 itsGetNMostSalientLoc(&OPT_GetNMostSalientLoc, this, ALLOW_ONLINE_CHANGES),
00177 itsInternalIORRadius(&OPT_InternalIORRadius, this, ALLOW_ONLINE_CHANGES),
00178 itsDynamicFeedback(&OPT_DynamicFeedback, this, ALLOW_ONLINE_CHANGES),
00179 itsInertiaHalfLife(&OPT_EsmInertiaHalfLife, this, ALLOW_ONLINE_CHANGES),
00180 itsInertiaStrength(&OPT_EsmInertiaStrength, this, ALLOW_ONLINE_CHANGES),
00181 itsInertiaRadius(&OPT_EsmInertiaRadius, this, ALLOW_ONLINE_CHANGES),
00182 itsInertiaShiftThresh(&OPT_EsmInertiaShiftThresh, this, ALLOW_ONLINE_CHANGES),
00183 itsIorHalfLife(&OPT_EsmIorHalfLife, this, ALLOW_ONLINE_CHANGES),
00184 itsIorStrength(&OPT_EsmIorStrength, this, ALLOW_ONLINE_CHANGES),
00185 itsIorRadius(&OPT_EsmIorRadius, this, ALLOW_ONLINE_CHANGES),
00186 itsLevelSpec(&OPT_EnvLevelSpec, this),
00187 itsTextLogFile(&OPT_TextLogFile, this),
00188 itsDynamicFactor(1.0),
00189 itsVcxMovingAvg(),
00190 itsVcxFlicker(0.0),
00191 itsVcxMeanDiffCenter(4.0),
00192 itsVcxFlickerMin(sigmoid(0.5*(-itsVcxMeanDiffCenter)))
00193 {}
00194
00195
00196 EnvSaliencyMap::~EnvSaliencyMap()
00197 {}
00198
00199
00200 void EnvSaliencyMap::paramChanged(ModelParamBase* const param,
00201 const bool valueChanged,
00202 ParamClient::ChangeStatus* status)
00203 {
00204 if (param == &itsUseFixed)
00205 {
00206 itsFixedX.setInactive(!itsUseFixed.getVal());
00207 itsFixedY.setInactive(!itsUseFixed.getVal());
00208 }
00209 }
00210
00211
00212 EnvSaliencyMap::State
00213 EnvSaliencyMap::getSalmap(const Image<byte>& vcxmap,
00214 const Point2D<int>& forceWinnerFullres)
00215 {
00216 State result;
00217
00218 result.salmap = vcxmap;
00219
00220
00221
00222
00223
00224
00225
00226
00227 const int zoom = (1 << itsLevelSpec.getVal().mapLevel());
00228
00229
00230 if (itsBiasImg.initialized())
00231 {
00232 if (itsBiasImg.getDims() != result.salmap.getDims())
00233 itsBiasImg = rescale(itsBiasImg, result.salmap.getDims());
00234 result.salmap *= itsBiasImg;
00235 }
00236
00237 if (itsUseFixed.getVal())
00238 {
00239 const Point2D<int> forceWinner
00240 (clampValue(itsFixedX.getVal(), 0, result.salmap.getWidth()-1),
00241 clampValue(itsFixedY.getVal(), 0, result.salmap.getHeight()-1));
00242
00243 ASSERT(result.salmap.coordsOk(forceWinner));
00244 result.lowres_maxpos = forceWinner;
00245 result.maxval = result.salmap.getVal(result.lowres_maxpos);
00246 }
00247 else if (forceWinnerFullres.isValid())
00248 {
00249 const Point2D<int> forceWinner
00250 (clampValue(forceWinnerFullres.i / zoom, 0, result.salmap.getWidth()-1),
00251 clampValue(forceWinnerFullres.j / zoom, 0, result.salmap.getHeight()-1));
00252
00253 ASSERT(result.salmap.coordsOk(forceWinner));
00254 result.lowres_maxpos = forceWinner;
00255 result.maxval = result.salmap.getVal(result.lowres_maxpos);
00256 }
00257 else
00258 {
00259 findMax(result.salmap, result.lowres_maxpos, result.maxval);
00260 }
00261
00262
00263
00264
00265 Image<byte> tmpSmap = vcxmap;
00266
00267
00268 Point2D<int> currentMaxLoc = result.lowres_maxpos;
00269 LocInfo locInfo;
00270 locInfo.lowres_maxpos = result.lowres_maxpos;
00271 locInfo.fullres_maxpos = locInfo.lowres_maxpos * zoom + zoom/2;
00272 locInfo.maxval = result.maxval;
00273 result.nMostSalientLoc.push_back(locInfo);
00274
00275 for(int i=1; i<itsGetNMostSalientLoc.getVal(); i++)
00276 {
00277
00278 drawDisk(tmpSmap, currentMaxLoc, itsInternalIORRadius.getVal(), (byte)0);
00279
00280
00281 findMax(tmpSmap, locInfo.lowres_maxpos, locInfo.maxval);
00282 locInfo.fullres_maxpos = locInfo.lowres_maxpos * zoom + zoom/2;
00283 result.nMostSalientLoc.push_back(locInfo);
00284 currentMaxLoc = locInfo.lowres_maxpos;
00285 }
00286
00287 result.fullres_maxpos = result.lowres_maxpos * zoom + zoom/2;
00288
00289 if (!itsVcxMovingAvg.initialized())
00290 itsVcxMovingAvg = vcxmap;
00291
00292 const double vcxmeandiff = meanAbsDiff(&itsVcxMovingAvg, &vcxmap);
00293 itsVcxFlicker =
00294 (sigmoid(0.5*(vcxmeandiff-itsVcxMeanDiffCenter)) - itsVcxFlickerMin)
00295 /
00296 (1.0 - itsVcxFlickerMin);
00297
00298 itsDynamicFactor =
00299 pow(1.0 - itsVcxFlicker,
00300 std::max(0.0, itsDynamicFeedback.getVal()));
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 if (itsInertiaLoc.i < 0 || itsInertiaLoc.j < 0
00313 || (result.lowres_maxpos.squdist(itsInertiaLoc)
00314 > (itsInertiaShiftThresh.getVal()
00315 * itsInertiaShiftThresh.getVal())))
00316 {
00317 itsCurrentInertiaFactor = 1.0;
00318 LDEBUG("inertia shift to (%d,%d)",
00319 result.lowres_maxpos.i, result.lowres_maxpos.j);
00320 }
00321 else
00322 {
00323 const float factor =
00324 (itsDynamicFactor * itsInertiaHalfLife.getVal()) > 0
00325 ? pow(0.5, 1.0/(itsDynamicFactor * itsInertiaHalfLife.getVal()))
00326 : 0.0f;
00327 itsCurrentInertiaFactor *= factor;
00328 }
00329
00330 {
00331 if (itsInertiaMap.getDims() != result.salmap.getDims())
00332 itsInertiaMap = Image<byte>(result.salmap.getDims(), ZEROS);
00333
00334 itsInertiaLoc = result.lowres_maxpos;
00335
00336 Image<float>::iterator iptr = itsInertiaMap.beginw();
00337
00338 const double s =
00339 itsInertiaStrength.getVal()
00340 * itsDynamicFactor
00341 * itsCurrentInertiaFactor;
00342
00343 const double r_inv =
00344 itsInertiaRadius.getVal() > 0.0
00345 ? (1.0 / itsInertiaRadius.getVal())
00346 : 0.0;
00347
00348 Point2D<int> p;
00349 for (p.j = 0; p.j < itsInertiaMap.getHeight(); ++p.j)
00350 for (p.i = 0; p.i < itsInertiaMap.getWidth(); ++p.i)
00351 {
00352 const int dsq =
00353 (itsInertiaLoc.i - p.i) * (itsInertiaLoc.i - p.i)
00354 + (itsInertiaLoc.j - p.j) * (itsInertiaLoc.j - p.j);
00355
00356 *iptr++ = s * exp(-dsq * r_inv);
00357 }
00358 }
00359
00360 if (itsDynamicFactor * itsIorStrength.getVal() > 0.0)
00361 {
00362 if (itsInhibMap.getDims() != result.salmap.getDims())
00363 itsInhibMap = Image<byte>(result.salmap.getDims(), ZEROS);
00364
00365 const float factor =
00366 (itsDynamicFactor * itsIorHalfLife.getVal()) > 0
00367 ? pow(0.5, 1.0/(itsDynamicFactor * itsIorHalfLife.getVal()))
00368 : 0.0f;
00369
00370 Image<byte>::iterator iptr = itsInhibMap.beginw();
00371
00372 Point2D<int> p;
00373 for (p.j = 0; p.j < itsInhibMap.getHeight(); ++p.j)
00374 for (p.i = 0; p.i < itsInhibMap.getWidth(); ++p.i)
00375 {
00376 const int dsq =
00377 (result.lowres_maxpos.i - p.i) * (result.lowres_maxpos.i - p.i)
00378 + (result.lowres_maxpos.j - p.j) * (result.lowres_maxpos.j - p.j);
00379
00380 const int newval =
00381 int(*iptr * factor
00382 + (itsDynamicFactor * itsIorStrength.getVal()
00383 * exp(- dsq / itsIorRadius.getVal())));
00384
00385 *iptr++ =
00386 newval < 0
00387 ? 0
00388 : newval > 255
00389 ? 255
00390 : byte(newval);
00391 }
00392 }
00393 else
00394 itsInhibMap.clear(0);
00395
00396 itsVcxMovingAvg += vcxmap;
00397 itsVcxMovingAvg *= 0.5;
00398
00399 textLog(itsTextLogFile.getVal(), "FOAcenter",
00400 convertToString(result.fullres_maxpos));
00401
00402 return result;
00403 }
00404
00405
00406
00407
00408
00409
00410
00411
00412 #endif // NEURO_ENVSALIENCYMAP_C_DEFINED