LoStafford.C

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/lgmd/rind/LoStafford.C
00003    \brief Stafford's LGMD model.
00004 */
00005 
00006 // //////////////////////////////////////////////////////////////////// //
00007 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00008 // by the University of Southern California (USC) and the iLab at USC.  //
00009 // See http://iLab.usc.edu for information about this project.          //
00010 // //////////////////////////////////////////////////////////////////// //
00011 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00012 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00013 // in Visual Environments, and Applications'' by Christof Koch and      //
00014 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00015 // pending; application number 09/912,225 filed July 23, 2001; see      //
00016 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00017 // //////////////////////////////////////////////////////////////////// //
00018 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00019 //                                                                      //
00020 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00021 // redistribute it and/or modify it under the terms of the GNU General  //
00022 // Public License as published by the Free Software Foundation; either  //
00023 // version 2 of the License, or (at your option) any later version.     //
00024 //                                                                      //
00025 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00026 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00027 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00028 // PURPOSE.  See the GNU General Public License for more details.       //
00029 //                                                                      //
00030 // You should have received a copy of the GNU General Public License    //
00031 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00032 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00033 // Boston, MA 02111-1307 USA.                                           //
00034 // //////////////////////////////////////////////////////////////////// //
00035 //
00036 // Primary maintainer for this file: mviswana usc edu
00037 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/lgmd/rind/LoStafford.C $
00038 // $Id: LoStafford.C 13037 2010-03-23 01:00:53Z mviswana $
00039 //
00040 
00041 //------------------------------ HEADERS --------------------------------
00042 
00043 // lobot headers
00044 #include "Robots/LoBot/lgmd/rind/LoStafford.H"
00045 #include "Robots/LoBot/config/LoConfig.H"
00046 #include "Robots/LoBot/misc/LoRegistry.H"
00047 #include "Robots/LoBot/util/LoMath.H"
00048 
00049 // INVT image support
00050 #include "Image/Convolver.H"
00051 #include "Image/CutPaste.H"
00052 #include "Image/MathOps.H"
00053 #include "Image/Rectangle.H"
00054 
00055 // Standard C++ headers
00056 #include <numeric>
00057 #include <algorithm>
00058 #include <functional>
00059 #include <utility>
00060 #include <cmath>
00061 
00062 //----------------------------- NAMESPACE -------------------------------
00063 
00064 namespace lobot {
00065 
00066 //------------------------ STATIC DATA MEMBERS --------------------------
00067 
00068 /*
00069    All instances of the Stafford model share the neural net layers used
00070    to compute LGMD spikes so as to save on the amount of overall
00071    computation required.
00072 
00073    Each instance represents a separate (virtual) locust looking in a
00074    different direction with a limited field of view. Thus, each instance
00075    is setup to read a subportion of the composited source image. These
00076    subportions are just the source image divided into consecutive
00077    vertical strips. For example, if we have a single camera grabbing
00078    320x240 images and use the default value of 32 pixels for each virtual
00079    locust's FOV, we will get 320/32 = 10 vertical strips and, therefore,
00080    10 virtual locusts.
00081 
00082    Each virtual locust "monitors" the strip right in front of it (foveal
00083    vision) as well as the strips to the left and right (peripheral
00084    vision). If we were to treat each locust separately, we would perform
00085    subtraction, convolution, etc. for its strips and then repeat the
00086    operations for the overlapping strips of the neighbouring locusts.
00087 
00088    This is extremely wasteful. So, to avoid repeating the same
00089    computations over and over again, we use the following static data
00090    members to store the layers of the neural net for the entire
00091    composited input image. When the update() method of the first instance
00092    of the Stafford model is invoked, we perform the necessary operations
00093    for the entire composited image. But then, each instance reads only
00094    its assigned subportion of the S-layer to compute its LGMD membrane
00095    potential.
00096 */
00097 StaffordModel::layer StaffordModel::l_layer ;
00098 StaffordModel::layer StaffordModel::p_layer ;
00099 StaffordModel::layer StaffordModel::i_layer ;
00100 StaffordModel::layer StaffordModel::s_layer ;
00101 
00102 // To enable the above-mentioned computational savings via neural net
00103 // layer sharing, we have to keep track of the total number of instances
00104 // of the Stafford model and the number for which the layer computations
00105 // have been performed during each instance's update cycle.
00106 int StaffordModel::m_instances ;
00107 int StaffordModel::m_layers_computed ;
00108 
00109 //-------------------------- INITIALIZATION -----------------------------
00110 
00111 // Whenever a virtual locust based on the Stafford model is created, we
00112 // need to bump up the number of instances to ensure that the sharing
00113 // described above works properly.
00114 StaffordModel::StaffordModel(const LocustModel::InitParams& p)
00115    : base(p)
00116 {
00117    ++m_instances ;
00118 }
00119 
00120 //------------------------ LAYER COMPUTATIONS ---------------------------
00121 
00122 // This method performs the necessary layer computations, taking care to
00123 // do them only once, i.e., for the first instance for which the LGMD
00124 // update cycle is invoked and then skipping them for the rest.
00125 void StaffordModel::compute_layers()
00126 {
00127    if (m_layers_computed == 0)
00128    {
00129       prime_previous_layers() ;
00130 
00131       l_layer.current = m_source->get_grayscale_image() ;
00132 
00133       p_layer.current = absDiff(l_layer.current, l_layer.previous) ;
00134 
00135       GrayImage kernel(3, 3, NO_INIT) ;
00136       std::fill(kernel.beginw(), kernel.endw(), 1/9.0f) ;
00137       Convolver C(kernel, i_layer.previous.getDims()) ;
00138       i_layer.current =
00139          C.spatialConvolve((p_layer.current + p_layer.previous) * .25) ;
00140 
00141       s_layer.current = p_layer.current - i_layer.previous * 2 ;
00142       std::transform(s_layer.current.begin(), s_layer.current.end(),
00143                      s_layer.current.beginw(),
00144                      std::bind2nd(max<float>(), 0)) ; // discard -ve values
00145    }
00146    ++m_layers_computed ;
00147 }
00148 
00149 // Once all instances have finished with their LGMD update, we need to
00150 // move the current layers into the previous time-step's slot. And, to
00151 // ensure smooth operation of the sharing described at the start of this
00152 // file, we need to reset the number of instances for which the LGMD
00153 // computations have been done. Without this, the next update cycle will
00154 // fail.
00155 void StaffordModel::reset_layers()
00156 {
00157    if (m_layers_computed == m_instances)
00158    {
00159       l_layer.previous = l_layer.current ;
00160       p_layer.previous = p_layer.current ;
00161       i_layer.previous = i_layer.current ;
00162       s_layer.previous = s_layer.current ;
00163 
00164       m_layers_computed = 0 ;
00165    }
00166 }
00167 
00168 // We need to prime the pump for the very first update cycle. At this
00169 // point, there are no previous time-steps for any of the layers. As a
00170 // starting point, we use the current image as the input for the
00171 // L-layer's previous time-step and just keep all the other layers empty.
00172 void StaffordModel::prime_previous_layers()
00173 {
00174    if (! l_layer.previous.initialized())
00175       l_layer.previous = m_source->get_grayscale_image() ;
00176 
00177    if (! p_layer.previous.initialized())
00178       p_layer.previous.resize(l_layer.previous.getDims(), true) ;
00179 
00180    if (! i_layer.previous.initialized())
00181       i_layer.previous.resize(l_layer.previous.getDims(), true) ;
00182 
00183    if (! s_layer.previous.initialized())
00184       s_layer.previous.resize(l_layer.previous.getDims(), true) ;
00185 }
00186 
00187 //------------------------- DSMD COMPUTATION ----------------------------
00188 
00189 // This helper routine returns the appropriate block size to use given
00190 // the total number of pixels along the desired dimension (i.e., x- or
00191 // y-direction).
00192 static int dsmd_block_size(int dim, int ideal, int alt)
00193 {
00194    int block_size = ideal ;
00195    int num_emds = dim/block_size ;
00196    if (num_emds < 2)
00197       block_size = alt ; // just hope this works!
00198    return block_size ;
00199 }
00200 
00201 // This method uses three functions or function objects to compute the
00202 // DSMD membrane potential for the desired direction.
00203 //
00204 // The first function/function object returns the appropriate dimension
00205 // of the locust's "viewing" rectangle/window to the world. For
00206 // horizontal DSMDs, this function would return the width of the
00207 // rectangle; for vertical DSMDs, the height.
00208 //
00209 // The second parameter is a function/function object that computes the
00210 // DSMD block along the appropriate dimension. For horizontal DSMDs, it
00211 // should compute the bounds of the ith DSMD block running horizontally
00212 // along the center of the image. For vertical DSMDs, it should compute
00213 // the bounds of the ith DSMD block running vertically along the center
00214 // of the image.
00215 //
00216 // The third parameter computes the membrane potential using the
00217 // rectangular DSMD blocks returned by the second parameter and the
00218 // current and previous S-layer contents of those blocks.
00219 template<typename rect_dim, typename rect_comp, typename pot_comp>
00220 float StaffordModel::compute_dsmd_potential(rect_dim  dimension,
00221                                              rect_comp compute_dsmd_rect,
00222                                              pot_comp  compute_potential)
00223 {
00224    int d = dimension(m_rect) ; // width or height of this locust's FOV
00225    int b = dsmd_block_size(d, Params::ideal_dsmd_block_size(),
00226                               Params::alt_dsmd_block_size()) ;
00227    int n = d/b ; // number of EMDs for the DSMD under consideration
00228 
00229    float P = 0 ; // DSMD membrane potential
00230    Rectangle R1 = compute_dsmd_rect(0, b, m_rect) ;
00231    for (int i = 1; i < n; ++i) {
00232       Rectangle R2 = compute_dsmd_rect(i, b, m_rect) ;
00233       P += compute_potential(s_layer.current, s_layer.previous, R1, R2) ;
00234       R1 = R2 ;
00235    }
00236    return P ;
00237 }
00238 
00239 // rect_dim functions for above template method
00240 static int rect_width (const Rectangle& R) {return R.width() ;}
00241 static int rect_height(const Rectangle& R) {return R.height() ;}
00242 
00243 // rect_comp functions for above template method
00244 static Rectangle
00245 compute_horz_dsmd_rect(int i, int block_size, const Rectangle& R)
00246 {
00247    int left   = std::max(i * block_size, 0) ;
00248    int right  = std::min(left + block_size, R.width()) ;
00249    int top    = std::max((R.height() - block_size)/2, 0) ;
00250    int bottom = std::min(top + block_size, R.height()) ;
00251    return Rectangle::tlbrI(top, left, bottom, right) ;
00252 }
00253 
00254 static Rectangle
00255 compute_vert_dsmd_rect(int i, int block_size, const Rectangle& R)
00256 {
00257    int left   = std::max((R.width() - block_size)/2, 0) ;
00258    int right  = std::min(left + block_size, R.width()) ;
00259    int top    = std::max(i * block_size, 0) ;
00260    int bottom = std::min(top + block_size, R.height()) ;
00261    return Rectangle::tlbrI(top, left, bottom, right) ;
00262 }
00263 
00264 // A quick helper to compute the membrane potential corresponding to the
00265 // specified rectangular portion of the supplied image (usually, the
00266 // S-layer).
00267 static float membrane_potential(const GrayImage& I, const Rectangle& R)
00268 {
00269    return sum(crop(I, R.topLeft(), R.dims() - 1)) ;
00270 }
00271 
00272 // The following two functions are for use as the third pot_comp
00273 // parameter of the compute_dsmd_potential() template method defined
00274 // above.
00275 static float
00276 compute_dsmd_potential_R1_current(const GrayImage& current,
00277                                   const GrayImage& previous,
00278                                   const Rectangle& R1, const Rectangle& R2)
00279 {
00280    return membrane_potential(current, R1) * membrane_potential(previous, R2) ;
00281 }
00282 
00283 static float
00284 compute_dsmd_potential_R2_current(const GrayImage& current,
00285                                   const GrayImage& previous,
00286                                   const Rectangle& R1, const Rectangle& R2)
00287 {
00288    return compute_dsmd_potential_R1_current(current, previous, R2, R1) ;
00289 }
00290 
00291 // Given the spike count of some DSMD (e.g., left or up) and its opposite
00292 // (i.e., right or down), this function determines whether there has been
00293 // only lateral motion rather than motion in both directions.
00294 //
00295 // Since the spike counts are either 0 or 1, checking for lateral motion
00296 // is a simple matter of an XOR operation. For example, motion in the
00297 // left DSMD will register as 1 and none in the right DSMD will be zero.
00298 // If XOR these two values, we will get 1, indicating that motion was
00299 // detected in only one direction. However, if there was motion in both
00300 // directions (or in neither), the XOR will return false.
00301 //
00302 // To make it easy to compute the final spike count from the individual
00303 // spike counts of the LGMD and DSMDs and their corresponding weights,
00304 // the counts are stored as floats rather than ints. So before we can
00305 // apply the XOR operator, we convert the supplied counts to ints.
00306 /*
00307 static bool lateral_motion(float d1, float d2)
00308 {
00309    int a = (d1 > .5) ;
00310    int b = (d2 > .5) ;
00311    return a ^ b ;
00312 }
00313 
00314 static inline bool uniform_expansion(float d1, float d2)
00315 {
00316    return ! lateral_motion(d1, d2) ;
00317 }
00318 //*/
00319 
00320 //*
00321 static bool lateral_motion(float p1, float p2, float threshold)
00322 {
00323    float p = p1/p2 ;
00324    return (p > threshold) || (p < 1/threshold) ;
00325 }
00326 //*/
00327 
00328 //---------------------------- LGMD UPDATE ------------------------------
00329 
00330 // The following function object uses the sigmoid formula described
00331 // earlier (see comment preceding definition of the AREA_MAGNIFIERS
00332 // array) to scale raw membrane potentials to the [.5,1] range.
00333 namespace {
00334 
00335 class sigmoid {
00336    float area ;
00337    const float* magnifiers ;
00338    mutable int i ;
00339 public:
00340    sigmoid(float, const float*) ;
00341    float operator()(float) const ;
00342 } ;
00343 
00344 sigmoid::sigmoid(float A, const float* M)
00345    : area(A), magnifiers(M), i(0)
00346 {}
00347 
00348 float sigmoid::operator()(float potential) const
00349 {
00350    return 1/(1 + exp(-potential/(area * magnifiers[i++]))) ;
00351 }
00352 
00353 }
00354 
00355 // Quick helper macro for debug support
00356 #define LOSTU_DUMP(array) \
00357            dump(array, array + NUM_NEURONS, "StaffordUpdate", #array)
00358 
00359 // This is the main interface routine for updating the LGMD "value" based
00360 // on the latest frame acquired from the input video sources. After doing
00361 // the layer computations as described in the Stafford paper, it computes
00362 // the raw membrane potential of the LGMD by summing all the pixel values
00363 // in the current S-layer. Then, it scales this potential down to [.5, 1]
00364 // by applying a sigmoid function. Whenever this scaled down potential
00365 // exceeds a predetermined (manual) threshold, it is counted as an LGMD
00366 // spike.
00367 //
00368 // In addition to the LGMD spike, we also compute the FFI and DSMD
00369 // potentials, scale them using the same sigmoid and the count them as
00370 // spikes if they exceed their respective spiking thresholds.
00371 //
00372 // The final instantaneous spike rate is computed as a running average of
00373 // a weighted sum of the LGMD and DSMD spike counts.
00374 //
00375 // The running average is computed using the usual formula, i.e.:
00376 //     running average = weight * current + (1 - weight) * previous
00377 //
00378 // But before we can apply the above formula, we need to first normalize
00379 // the previous spike rate value, i.e., scale it down to [0,1], because
00380 // the current spike, being a weighted sum of either zeros or ones, will
00381 // be a number in the range [0,1]. We can't blithely compute a running
00382 // average using one number in [min, max] and another in [0,1]; the
00383 // result will be horribly wrong.
00384 //
00385 // Once the previous spike rate value has been normalized, we compute the
00386 // running average using it and the current spike count. Then, we scale
00387 // the result back to its usual min/max range.
00388 //
00389 // NOTE: The sigmoid thingummy is not described in the Stafford paper.
00390 // Rather it is in the following paper:
00391 //
00392 //     Yue, S., Santer, R. D., Yamawaki, Y., Rind, F. C.
00393 //     Reactive direction control for a mobile robot: A locust-like
00394 //     control of escape direction emerges when a bilateral pair of model
00395 //     locust visual neurons are integrated.
00396 //     Submitted to Autonmous Robots in 2008.
00397 //
00398 // ALSO: This function implements feed-forward and lateral motion
00399 // inhibition as described in the Stafford paper as well as the one
00400 // mentioned above. However, this inhibition does not work very well. So
00401 // we setup the weights and other relevant parameters defined at the
00402 // beginning of this file to ignore the FFI and DSMD neurons. We could
00403 // just as well remove all this unused/dead code. But it's left alone
00404 // just in case a magic wand shows up and enables us to figure out how to
00405 // get this weird and bogus model to actually behave like the LGMD (i.e.,
00406 // ignore lateral motion and respond preferentially to collisions).
00407 void StaffordModel::update()
00408 {
00409    compute_layers() ;
00410 
00411    float potentials[NUM_NEURONS] = {0} ;
00412    potentials[LGMD] = membrane_potential(s_layer.current, m_rect) ;
00413    potentials[FFI] = membrane_potential(p_layer.previous, m_rect) ;
00414    potentials[DSMD_LEFT] =
00415       compute_dsmd_potential(rect_width, compute_horz_dsmd_rect,
00416                              compute_dsmd_potential_R1_current) ;
00417    potentials[DSMD_RIGHT] =
00418       compute_dsmd_potential(rect_width, compute_horz_dsmd_rect,
00419                              compute_dsmd_potential_R2_current) ;
00420    potentials[DSMD_UP] =
00421       compute_dsmd_potential(rect_height, compute_vert_dsmd_rect,
00422                              compute_dsmd_potential_R1_current) ;
00423    potentials[DSMD_DOWN] =
00424       compute_dsmd_potential(rect_height, compute_vert_dsmd_rect,
00425                              compute_dsmd_potential_R2_current) ;
00426    //LOSTU_DUMP(potentials) ;
00427 
00428    float scaled_potentials[NUM_NEURONS] = {0} ;
00429    std::transform(potentials, potentials + NUM_NEURONS, scaled_potentials,
00430                   sigmoid(m_rect.area(), Params::area_magnifiers())) ;
00431    //LOSTU_DUMP(scaled_potentials) ;
00432 
00433    float spikes[NUM_NEURONS] = {0} ;
00434    std::transform(scaled_potentials, scaled_potentials + NUM_NEURONS,
00435                   Params::spike_thresholds(), spikes, std::greater<float>()) ;
00436    //LOSTU_DUMP(spikes) ;
00437 
00438    if (suppress_lgmd(spikes, potentials)) {
00439       update_lgmd(0) ;
00440       std::fill(spikes, spikes + NUM_NEURONS, 0) ;
00441    }
00442 
00443    // Even if the LGMD has been suppressed, the FFI and DSMD neurons may
00444    // still be able to produce some spiking from the LGMD network. The
00445    // following dot product computes a weighted sum of each neuron's
00446    // spike to produce the final spiking decision.
00447    //
00448    // NOTE: This weighted sum procedure is not described in any of the
00449    // LGMD related papers by Stafford, Blanchard, Yue, Rind and gang.
00450    // It's just something the author of this class made up to try and get
00451    // this model to work properly (i.e., suppress lateral motions and
00452    // respond only to collisional motion). It can be turned off by
00453    // setting the LGMD spike weight to 1 and the FFI and DSMD spike
00454    // weights to zero. Then, only the LGMD spike will be considered in
00455    // the final decision regarding whether or not the LGMD network emits
00456    // a spike or not (subject, of course, to the suppression signal
00457    // emitted by the FFI or DSMD).
00458    float spike = std::inner_product(spikes, spikes + NUM_NEURONS,
00459                                     Params::spike_weights(), 0.0f) ;
00460 
00461    const float min = get_range().min() ;
00462    const float max = get_range().max() ;
00463 
00464    float normalized_lgmd = (get_lgmd() - min)/(max - min) ;
00465    float w = Params::running_average_weight() ;
00466    float lgmd_avg = w * spike + (1 - w) * normalized_lgmd ;
00467    update_lgmd(min + lgmd_avg * (max - min)) ;//rescale from [0,1] to [min,max]
00468    //LINFO("final spike = %g, old spike = %g, new spike = %g",
00469          //spike, normalized_lgmd, lgmd_avg) ;
00470    //LINFO("LGMD rate = %g", getLGMD()) ;
00471 
00472    reset_layers() ;
00473 }
00474 
00475 // Check if LGMD suppression is on via either the FFI or DSMDs and their
00476 // corresponding suppression tests.
00477 bool StaffordModel::suppress_lgmd(const float spikes[],
00478                                   const float potentials[])
00479 {
00480    if (Params::ffi_on()) // check for whole field motion
00481       return spikes[FFI] > 0.5 ;
00482 
00483    if (Params::dsmd_on()) //chk directionally sensitive neurons for lat. motion
00484       return lateral_motion(potentials[DSMD_LEFT], potentials[DSMD_RIGHT],
00485                             Params::horizontal_motion_threshold())
00486           || lateral_motion(potentials[DSMD_UP], potentials[DSMD_DOWN],
00487                             Params::vertical_motion_threshold()) ;
00488 
00489    return false ;
00490 }
00491 
00492 //----------------------------- CLEAN-UP --------------------------------
00493 
00494 StaffordModel::~StaffordModel()
00495 {
00496    --m_instances ;
00497    --m_layers_computed ;
00498    if (m_layers_computed < 0)
00499       m_layers_computed = 0 ;
00500 }
00501 
00502 //-------------------------- KNOB TWIDDLING -----------------------------
00503 
00504 // Quick helper to retrieve configuration settings from the stafford
00505 // section of the config file.
00506 template<typename T>
00507 static T conf(const std::string& key, const T& default_value)
00508 {
00509    return Configuration::get<T>(LOLM_STAFFORD, key, default_value) ;
00510 }
00511 
00512 // Quick helper macro to retrieve lists from the stafford section of the
00513 // config file.
00514 #define LOST_GETCONF_ARRAY(key) \
00515            Configuration::get(LOLM_STAFFORD, #key, m_##key, \
00516                               default_##key, NUM_NEURONS)
00517 
00518 // Parameters initialization
00519 StaffordModel::Params::Params()
00520    : m_running_average_weight(conf("running_average_weight", 0.25)),
00521      m_ffi_on(conf("ffi", false)),
00522      m_dsmd_on(conf("dsmd", false)),
00523      m_horizontal_motion_threshold(conf("horizontal_motion_threshold", 1.5)),
00524      m_vertical_motion_threshold(conf("vertical_motion_threshold", 2.5)),
00525      m_ideal_dsmd_block_size(conf("ideal_dsmd_block_size", 10)),
00526      m_alt_dsmd_block_size(conf("alt_dsmd_block_size", 4))
00527 {
00528    float default_spike_thresholds[] = {.99, 1.5, 1.5, 1.5, 1.5, 1.5} ;
00529    LOST_GETCONF_ARRAY(spike_thresholds) ;
00530 
00531    float default_spike_weights[] = {1, 0, 0, 0, 0, 0} ;
00532    LOST_GETCONF_ARRAY(spike_weights) ;
00533 
00534    float default_area_magnifiers[] = {2, 5, 500, 500, 500, 500} ;
00535    LOST_GETCONF_ARRAY(area_magnifiers) ;
00536 }
00537 
00538 // Parameters clean-up
00539 StaffordModel::Params::~Params(){}
00540 
00541 // Parameters access
00542 const float* StaffordModel::Params::spike_thresholds()
00543 {
00544    return instance().m_spike_thresholds ;
00545 }
00546 
00547 const float* StaffordModel::Params::spike_weights()
00548 {
00549    return instance().m_spike_weights ;
00550 }
00551 
00552 const float* StaffordModel::Params::area_magnifiers()
00553 {
00554    return instance().m_area_magnifiers ;
00555 }
00556 
00557 float StaffordModel::Params::running_average_weight()
00558 {
00559    return instance().m_running_average_weight ;
00560 }
00561 
00562 bool StaffordModel::Params::ffi_on()
00563 {
00564    return instance().m_ffi_on ;
00565 }
00566 
00567 bool StaffordModel::Params::dsmd_on()
00568 {
00569    return instance().m_dsmd_on ;
00570 }
00571 
00572 float StaffordModel::Params::horizontal_motion_threshold()
00573 {
00574    return instance().m_horizontal_motion_threshold ;
00575 }
00576 
00577 float StaffordModel::Params::vertical_motion_threshold()
00578 {
00579    return instance().m_vertical_motion_threshold ;
00580 }
00581 
00582 int StaffordModel::Params::ideal_dsmd_block_size()
00583 {
00584    return instance().m_ideal_dsmd_block_size ;
00585 }
00586 
00587 int StaffordModel::Params::alt_dsmd_block_size()
00588 {
00589    return instance().m_alt_dsmd_block_size ;
00590 }
00591 
00592 //-----------------------------------------------------------------------
00593 
00594 } // end of namespace encapsulating this file's definitions
00595 
00596 /* So things look consistent in everyone's emacs... */
00597 /* Local Variables: */
00598 /* indent-tabs-mode: nil */
00599 /* End: */
Generated on Sun May 8 08:05:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3