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: */