LoOccGrid.C

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/slam/LoOccGrid.C
00003    \brief This file defines the non-inline member functions of the
00004    lobot::OccGrid class.
00005 */
00006 
00007 // //////////////////////////////////////////////////////////////////// //
00008 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00009 // by the University of Southern California (USC) and the iLab at USC.  //
00010 // See http://iLab.usc.edu for information about this project.          //
00011 // //////////////////////////////////////////////////////////////////// //
00012 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00013 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00014 // in Visual Environments, and Applications'' by Christof Koch and      //
00015 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00016 // pending; application number 09/912,225 filed July 23, 2001; see      //
00017 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00018 // //////////////////////////////////////////////////////////////////// //
00019 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00022 // redistribute it and/or modify it under the terms of the GNU General  //
00023 // Public License as published by the Free Software Foundation; either  //
00024 // version 2 of the License, or (at your option) any later version.     //
00025 //                                                                      //
00026 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00027 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00028 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00029 // PURPOSE.  See the GNU General Public License for more details.       //
00030 //                                                                      //
00031 // You should have received a copy of the GNU General Public License    //
00032 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00033 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00034 // Boston, MA 02111-1307 USA.                                           //
00035 // //////////////////////////////////////////////////////////////////// //
00036 //
00037 // Primary maintainer for this file: mviswana usc edu
00038 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/slam/LoOccGrid.C $
00039 // $Id: LoOccGrid.C 13560 2010-06-11 12:58:57Z mviswana $
00040 //
00041 
00042 //------------------------------ HEADERS --------------------------------
00043 
00044 // lobot headers
00045 #include "Robots/LoBot/slam/LoOccGrid.H"
00046 #include "Robots/LoBot/slam/LoMap.H"
00047 #include "Robots/LoBot/slam/LoCoords.H"
00048 #include "Robots/LoBot/slam/LoSlamParams.H"
00049 
00050 #include "Robots/LoBot/config/LoConfigHelpers.H"
00051 #include "Robots/LoBot/util/LoMath.H"
00052 #include "Robots/LoBot/misc/singleton.hh"
00053 
00054 // INVT utilities
00055 #include "Util/log.H"
00056 
00057 // Standard C++ headers
00058 #include <fstream>
00059 #include <string>
00060 #include <algorithm>
00061 #include <functional>
00062 #include <iterator>
00063 
00064 //----------------------------- NAMESPACE -------------------------------
00065 
00066 namespace lobot {
00067 
00068 //-------------------------- INITIALIZATION -----------------------------
00069 
00070 // Init "empty" occupancy grid
00071 OccGrid::OccGrid()
00072 {
00073    const int N = SlamParams::map_width() * SlamParams::map_height() ;
00074    m_grid.reserve(N) ;
00075    std::fill_n(std::back_inserter(m_grid), N, 0.0f) ;
00076 
00077    /*
00078    LERROR("created empty OccGrid [%08lX]",
00079           reinterpret_cast<unsigned long>(this)) ;
00080    // */
00081 }
00082 
00083 // Init occupancy grid using known obstacle map
00084 OccGrid::OccGrid(const std::string& map_file_name)
00085 {
00086    const int N = SlamParams::map_width() * SlamParams::map_height() ;
00087    m_grid.reserve(N) ;
00088 
00089    // First, mark all cells vacant
00090    std::fill_n(std::back_inserter(m_grid), N, prob_to_log_odds(0.01f)) ;
00091 
00092    // Then, read map file and mark those cells as occupied
00093    std::ifstream map_file(map_file_name.c_str()) ;
00094    const float occupied = prob_to_log_odds(0.99f) ;
00095    for (;;)
00096    {
00097       float x0, y0, x1, y1 ;
00098       map_file >> x0 >> y0 >> x1 >> y1 ;
00099       if (! map_file)
00100          break ;
00101 
00102       int gx0, gy0, gx1, gy1 ;
00103       Coords::to_grid(x0, y0, &gx0, &gy0) ;
00104       Coords::to_grid(x1, y1, &gx1, &gy1) ;
00105 
00106       if (gx0 > gx1)
00107          std::swap(gx0, gx1) ;
00108       if (gy0 > gy1)
00109          std::swap(gy0, gy1) ;
00110 
00111       const int W = SlamParams::map_width() ;
00112       int k = gy0 * W + gx0 ;
00113       for (int y = gy0; y <= gy1; ++y, k += W - (gx1 - gx0 + 1))
00114       for (int x = gx0; x <= gx1; ++x, ++k)
00115          m_grid[k] = occupied ;
00116    }
00117    /*
00118    LERROR("created OccGrid [%08lX] from map file \"%s\"",
00119           reinterpret_cast<unsigned long>(this), map_file_name.c_str()) ;
00120    // */
00121 }
00122 
00123 // Copy
00124 OccGrid::OccGrid(const OccGrid& g)
00125    : m_grid(g.m_grid)
00126 {
00127    /*
00128    LERROR("copied OccGrid [%08lX] to [%08lX]",
00129           reinterpret_cast<unsigned long>(&g),
00130           reinterpret_cast<unsigned long>(this)) ;
00131    // */
00132 }
00133 
00134 // Assignment
00135 OccGrid& OccGrid::operator=(const OccGrid& g)
00136 {
00137    if (&g != this) {
00138       m_grid = g.m_grid ;
00139       /*
00140       LERROR("assigned OccGrid [%08lX] to [%08lX]",
00141              reinterpret_cast<unsigned long>(&g),
00142              reinterpret_cast<unsigned long>(this)) ;
00143       // */
00144    }
00145    return *this ;
00146 }
00147 
00148 //-------------------------- MAP OPERATIONS -----------------------------
00149 
00150 // Add two maps together and retain result in this map
00151 OccGrid& OccGrid::operator+=(const OccGrid& M)
00152 {
00153    std::transform(m_grid.begin(), m_grid.end(), M.m_grid.begin(),
00154                   m_grid.begin(), std::plus<float>()) ;
00155    return *this ;
00156 }
00157 
00158 // Add two maps together and return the result via a new map
00159 OccGrid OccGrid::operator+(const OccGrid& M) const
00160 {
00161    OccGrid result(*this) ;
00162    result += M ;
00163    return result ;
00164 }
00165 
00166 // Scale this map using the supplied weighting factor and return the
00167 // result via a new map.
00168 OccGrid OccGrid::operator*(float weight) const
00169 {
00170    OccGrid result(*this) ;
00171    std::transform(result.m_grid.begin(), result.m_grid.end(),
00172                   result.m_grid.begin(),
00173                   std::bind2nd(std::multiplies<float>(), weight)) ;
00174    return result ;
00175 }
00176 
00177 //---------------------------- MAP ACCESS -------------------------------
00178 
00179 void OccGrid::occupied(int x, int y)
00180 {
00181    update(x, y, exp(-0.5f * sqr(get(x, y)))) ;
00182 }
00183 
00184 void OccGrid::vacant(int x, int y)
00185 {
00186    update(x, y, -exp(-0.5f * sqr(get(x, y)))) ;
00187 }
00188 
00189 // This method increments/decrements the specified cell's log-odds value
00190 // by the specified delta. To prevent the occupancy probability for a
00191 // cell from becoming 0 or 1 (i.e., absolute certainty), we clamp the new
00192 // log-odds value to some reasonable boundary, viz., [-7, 7]. A log-odds
00193 // value of -7 corresponds to a probability of 0.00091105 and +7 to
00194 // 0.99908895.
00195 //
00196 // NOTE: When we update a cell, we also update its immediate neighbours.
00197 // A part of the delta value is added to the target cell's current
00198 // occupancy value and the remaining part is divided equally between and
00199 // added to the cell's immediate neighbours.
00200 void OccGrid::update(int x, int y, float delta)
00201 {
00202    const int W = SlamParams::map_width()  ;
00203    const int H = SlamParams::map_height() ;
00204    if (x < 0 || x >= W || y < 0 || y >= H)
00205       return ; // (x,y) out of bounds
00206 
00207    // Determine extents for immediate neigbours of (x,y)
00208    const int x_min = std::max(x - 1, 0) ;
00209    const int x_max = std::min(x + 1, W - 1) ;
00210    const int y_min = std::max(y - 1, 0) ;
00211    const int y_max = std::min(y + 1, H - 1) ;
00212 
00213    // Only a certain percentage of the delta value will be applied to
00214    // (x,y). The remaining percentage of the delta value will be
00215    // distributed equally to the immediate neigbours of (x,y).
00216    const float w = SlamParams::update_weight() ;
00217    const float delta_nbr = delta *
00218       (1 - w)/((x_max - x_min + 1) * (y_max - y_min + 1) - 1) ;
00219 
00220    // Apply delta * (1 - w)/num_nbrs to immediate neigbours of (x,y)
00221    for (int j = y_min; j <= y_max; ++j)
00222    {
00223       int k = j * W + x_min ;
00224       for (int i = x_min; i <= x_max; ++i, ++k)
00225          m_grid[k] = clamp(m_grid[k] + delta_nbr, -7.0f, +7.0f) ;
00226    }
00227 
00228    // The above loop would have applied delta * (1 - w)/num_nbrs to the
00229    // neigbours of (x,y) as well as to (x,y) itself. So, we subtract that
00230    // amount from the occupancy value in cell (x,y) and add the proper
00231    // delta value for the target cell, viz., w * delta.
00232    int k = y * W + x ;
00233    m_grid[k] = clamp(m_grid[k] - delta_nbr + w * delta, -7.0f, +7.0f) ;
00234 }
00235 
00236 // This function checks the occupancy value of the specified cell to see
00237 // if it is occupied or not.
00238 bool OccGrid::is_occupied(int x, int y) const
00239 {
00240    return get(x, y) >= SlamParams::occ_threshold() ;
00241 }
00242 
00243 // This function returns the occupancy value of the specified cell.
00244 //
00245 // NOTE: The occupancy value of a cell is determined as a weighted sum of
00246 // the values in the target cell and those of its immediate neigbours.
00247 // The maximum weight is given to the target cell (x,y) while the others
00248 // get lower weights. Specifically, the same weighting factor applied to
00249 // the delta value during cell updates is used here. Thus, if the update
00250 // weight is 0.75, then 75% of the occupancy value of cell (x,y) is used
00251 // and the remaining 25% is divided equally between the immediate
00252 // neighbours to yield the final occupancy value.
00253 float OccGrid::get(int x, int y) const
00254 {
00255    const int W = SlamParams::map_width()  ;
00256    const int H = SlamParams::map_height() ;
00257    if (x < 0 || x >= W || y < 0 || y >= H)
00258       return 0 ; // area not covered by map: 50-50 occupancy likelihood
00259 
00260    // Determine extents for immediate neigbours of (x,y)
00261    const int x_min = std::max(x - 1, 0) ;
00262    const int x_max = std::min(x + 1, W - 1) ;
00263    const int y_min = std::max(y - 1, 0) ;
00264    const int y_max = std::min(y + 1, H - 1) ;
00265 
00266    // Only a certain percentage of the occupancy value of cell (x,y) will
00267    // actually contribute towards its "true" occupancy value. The
00268    // remaining percentage of the final weighted value will come from the
00269    // immediate neigbours of (x,y).
00270    const float w = SlamParams::update_weight() ;
00271    const float w_nbr = (1 - w)/((x_max - x_min + 1) * (y_max - y_min + 1) - 1);
00272 
00273    // When determining the weighted sum for the final occupancy value
00274    // corresponding to cell (x,y), first apply (1 - w)/num_nbrs to the
00275    // immediate neigbours...
00276    float occ = 0 ;
00277    for (int j = y_min; j <= y_max; ++j)
00278    {
00279       int k = j * W + x_min ;
00280       for (int i = x_min; i <= x_max; ++i, ++k)
00281          occ += w_nbr * m_grid[k] ;
00282    }
00283 
00284    // The above loop would have applied (1 - w)/num_nbrs to the
00285    // neigbours of (x,y) as well as to (x,y) itself. So, we subtract that
00286    // amount from the occupancy value in cell (x,y) and add the proper
00287    // weighted value to get the final occupancy likelihood.
00288    int k = y * W + x ;
00289    occ += (w - w_nbr) * m_grid[k] ;
00290    return occ ;
00291 }
00292 
00293 //----------------------------- CLEAN-UP --------------------------------
00294 
00295 OccGrid::~OccGrid()
00296 {
00297    /*
00298    LERROR("cleaning up OccGrid [%08lX]",
00299           reinterpret_cast<unsigned long>(this)) ;
00300    // */
00301 }
00302 
00303 //-----------------------------------------------------------------------
00304 
00305 } // end of namespace encapsulating this file's definitions
00306 
00307 /* So things look consistent in everyone's emacs... */
00308 /* Local Variables: */
00309 /* indent-tabs-mode: nil */
00310 /* End: */
Generated on Sun May 8 08:41:31 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3