目录

1 类简介

1.1 OccupancyGrid类

2 static OccupancyGrid* CreateFromScans()

2.1 static void ComputeDimensions()

2.2 OccupancyGrid()

3 void CreateFromScans()

3.1 kt_bool AddScan()

3.2 kt_bool RayTrace()

3.3  void Grid::TraceLine()

3.4 virtual void Update()

3.5 virtual void UpdateCell()


slam_karto中的updateMap()调用了karto::OccupancyGrid::CreateFromScans()生成了栅格地图,这篇文章就讲一下栅格地图如何生成的。

bool
SlamKarto::updateMap()
{boost::mutex::scoped_lock lock(map_mutex_);karto::OccupancyGrid* occ_grid = karto::OccupancyGrid::CreateFromScans(mapper_->GetAllProcessedScans(), resolution_);
// ...
}

1 类简介

1.1 OccupancyGrid类

首先看一下OccupancyGrid类的成员变量

  /*** Occupancy grid definition. See GridStates for possible grid values.*/class OccupancyGrid : public Grid<kt_int8u>{friend class CellUpdater;friend class IncrementalOccupancyGrid;protected:/*** Counters of number of times a beam passed through a cell*/Grid<kt_int32u>* m_pCellPassCnt;/*** Counters of number of times a beam ended at a cell*/Grid<kt_int32u>* m_pCellHitsCnt;private:/*** Restrict the copy constructor*/OccupancyGrid(const OccupancyGrid&);/*** Restrict the assignment operator*/const OccupancyGrid& operator=(const OccupancyGrid&);private:CellUpdater* m_pCellUpdater;// NOTE: These two values are dependent on the resolution.  If the resolution is too small,// then not many beams will hit the cell!// Number of beams that must pass through a cell before it will be considered to be occupied// or unoccupied.  This prevents stray beams from messing up the map.Parameter<kt_int32u>* m_pMinPassThrough;// Minimum ratio of beams hitting cell to beams passing through cell for cell to be marked as occupiedParameter<kt_double>* m_pOccupancyThreshold;};  // OccupancyGrid

1.2 CellUpdater类(未进行使用)

  class KARTO_EXPORT CellUpdater : public Functor{public:CellUpdater(OccupancyGrid* pGrid): m_pOccupancyGrid(pGrid){}/*** Updates the cell at the given index based on the grid's hits and pass counters* @param index*/void CellUpdater::operator() (kt_int32u index){kt_int8u* pDataPtr = m_pOccupancyGrid->GetDataPointer();kt_int32u* pCellPassCntPtr = m_pOccupancyGrid->m_pCellPassCnt->GetDataPointer();kt_int32u* pCellHitCntPtr = m_pOccupancyGrid->m_pCellHitsCnt->GetDataPointer();m_pOccupancyGrid->UpdateCell(&pDataPtr[index], pCellPassCntPtr[index], pCellHitCntPtr[index]);}private:OccupancyGrid* m_pOccupancyGrid;};  // CellUpdater

2 static OccupancyGrid* CreateFromScans()

    /*** Create an occupancy grid from the given scans using the given resolution* @param rScans* @param resolution*/static OccupancyGrid* CreateFromScans(const LocalizedRangeScanVector& rScans, kt_double resolution){if (rScans.empty()){return NULL;}kt_int32s width, height;Vector2<kt_double> offset;ComputeDimensions(rScans, resolution, width, height, offset);OccupancyGrid* pOccupancyGrid = new OccupancyGrid(width, height, offset, resolution);pOccupancyGrid->CreateFromScans(rScans);return pOccupancyGrid;}

2.1 static void ComputeDimensions()

    /*** Calculate grid dimensions from localized range scans* @param rScans* @param resolution* @param rWidth* @param rHeight* @param rOffset*/static void ComputeDimensions(const LocalizedRangeScanVector& rScans,kt_double resolution,kt_int32s& rWidth,kt_int32s& rHeight,Vector2<kt_double>& rOffset){BoundingBox2 boundingBox;// 得到所有scan的总体boundingBoxconst_forEach(LocalizedRangeScanVector, &rScans){boundingBox.Add((*iter)->GetBoundingBox());}kt_double scale = 1.0 / resolution;Size2<kt_double> size = boundingBox.GetSize();// 坐标值除以分辨率等于栅格的个数rWidth = static_cast<kt_int32s>(math::Round(size.GetWidth() * scale));rHeight = static_cast<kt_int32s>(math::Round(size.GetHeight() * scale));rOffset = boundingBox.GetMinimum(); // 左下角的坐标值}

2.1.1 BoundingBox2

BoundingBox2 只是储存了矩形左下角坐标与右上角坐标

  /*** Defines a bounding box in 2-dimensional real space.*/class BoundingBox2{public:/*** Get bounding box minimum*/inline const Vector2<kt_double>& GetMinimum() const{return m_Minimum;}/*** Get the size of the bounding box 获取2坐标的差值*/inline Size2<kt_double> GetSize() const{Vector2<kt_double> size = m_Maximum - m_Minimum;return Size2<kt_double>(size.GetX(), size.GetY());}/*** Add vector to bounding box*/inline void Add(const Vector2<kt_double>& rPoint){m_Minimum.MakeFloor(rPoint);// m_Minimum的x和y坐标 如果比 rPoint 大,则用 rPoint 的x或y赋值m_Maximum.MakeCeil(rPoint); // m_Maximum的x和y坐标 如果比 rPoint 小,则用 rPoint 的x或y赋值}/*** Add other bounding box to bounding box*/inline void Add(const BoundingBox2& rBoundingBox){Add(rBoundingBox.GetMinimum());Add(rBoundingBox.GetMaximum());}private:Vector2<kt_double> m_Minimum;Vector2<kt_double> m_Maximum;};  // BoundingBox2

2.2 OccupancyGrid()

    /*** Constructs an occupancy grid of given size* @param width* @param height* @param rOffset* @param resolution*/OccupancyGrid(kt_int32s width, kt_int32s height, const Vector2<kt_double>& rOffset, kt_double resolution): Grid<kt_int8u>(width, height), m_pCellPassCnt(Grid<kt_int32u>::CreateGrid(0, 0, resolution)), m_pCellHitsCnt(Grid<kt_int32u>::CreateGrid(0, 0, resolution)), m_pCellUpdater(NULL){m_pCellUpdater = new CellUpdater(this);if (karto::math::DoubleEqual(resolution, 0.0)){throw Exception("Resolution cannot be 0");}m_pMinPassThrough = new Parameter<kt_int32u>("MinPassThrough", 2);m_pOccupancyThreshold = new Parameter<kt_double>("OccupancyThreshold", 0.1);GetCoordinateConverter()->SetScale(1.0 / resolution);GetCoordinateConverter()->SetOffset(rOffset);  // 左下角坐标值}

3 void CreateFromScans()

    /*** Create grid using scans* @param rScans*/virtual void CreateFromScans(const LocalizedRangeScanVector& rScans){// 设置 pass 网格的size与左下角坐标m_pCellPassCnt->Resize(GetWidth(), GetHeight());m_pCellPassCnt->GetCoordinateConverter()->SetOffset(GetCoordinateConverter()->GetOffset());// 设置 Hit 网格的size与左下角坐标m_pCellHitsCnt->Resize(GetWidth(), GetHeight());m_pCellHitsCnt->GetCoordinateConverter()->SetOffset(GetCoordinateConverter()->GetOffset());const_forEach(LocalizedRangeScanVector, &rScans){LocalizedRangeScan* pScan = *iter;AddScan(pScan);}Update();}/*** Resizes the grid (deletes all old data)* @param width* @param height*/virtual void Resize(kt_int32s width, kt_int32s height){Grid<kt_int8u>::Resize(width, height);    // 同时也将基类中的 Grid resize 了m_pCellPassCnt->Resize(width, height);m_pCellHitsCnt->Resize(width, height);}

3.1 kt_bool AddScan()

    /*** Adds the scan's information to this grid's counters (optionally* update the grid's cells' occupancy status)* @param pScan* @param doUpdate whether to update the grid's cell's occupancy status* @return returns false if an endpoint fell off the grid, otherwise true*/virtual kt_bool AddScan(LocalizedRangeScan* pScan, kt_bool doUpdate = false){kt_double rangeThreshold = pScan->GetLaserRangeFinder()->GetRangeThreshold();kt_double maxRange = pScan->GetLaserRangeFinder()->GetMaximumRange(); // 0kt_double minRange = pScan->GetLaserRangeFinder()->GetMinimumRange(); // 80Vector2<kt_double> scanPosition = pScan->GetSensorPose().GetPosition();// get scan point readings,  false 代表未经过滤波的scanconst PointVectorDouble& rPointReadings = pScan->GetPointReadings(false);kt_bool isAllInMap = true;// draw lines from scan position to all point readings 从雷达坐标向着scan画线int pointIndex = 0;const_forEachAs(PointVectorDouble, &rPointReadings, pointsIter){Vector2<kt_double> point = *pointsIter; // 雷达数据点的坐标kt_double rangeReading = pScan->GetRangeReadings()[pointIndex];kt_bool isEndPointValid = rangeReading < (rangeThreshold - KT_TOLERANCE); // 是否小于12米if (rangeReading <= minRange || rangeReading >= maxRange || std::isnan(rangeReading)){// ignore these readingspointIndex++;continue;}else if (rangeReading >= rangeThreshold) // 大于12米的点进行裁剪,距离越远有效距离越近{// trace up to range readingkt_double ratio = rangeThreshold / rangeReading;kt_double dx = point.GetX() - scanPosition.GetX();kt_double dy = point.GetY() - scanPosition.GetY();point.SetX(scanPosition.GetX() + ratio * dx);point.SetY(scanPosition.GetY() + ratio * dy);}kt_bool isInMap = RayTrace(scanPosition, point, isEndPointValid, doUpdate);if (!isInMap){isAllInMap = false;}pointIndex++;}return isAllInMap;}

3.2 kt_bool RayTrace()

    /*** Traces a beam from the start position to the end position marking* the bookkeeping arrays accordingly.* @param rWorldFrom start position of beam* @param rWorldTo end position of beam* @param isEndPointValid is the reading within the range threshold?* @param doUpdate whether to update the cells' occupancy status immediately* @return returns false if an endpoint fell off the grid, otherwise true*/virtual kt_bool RayTrace(const Vector2<kt_double>& rWorldFrom,const Vector2<kt_double>& rWorldTo,kt_bool isEndPointValid,kt_bool doUpdate = false){assert(m_pCellPassCnt != NULL && m_pCellHitsCnt != NULL);Vector2<kt_int32s> gridFrom = m_pCellPassCnt->WorldToGrid(rWorldFrom);Vector2<kt_int32s> gridTo = m_pCellPassCnt->WorldToGrid(rWorldTo);CellUpdater* pCellUpdater = doUpdate ? m_pCellUpdater : NULL;m_pCellPassCnt->TraceLine(gridFrom.GetX(), gridFrom.GetY(), gridTo.GetX(), gridTo.GetY(), pCellUpdater);// for the end pointif (isEndPointValid){if (m_pCellPassCnt->IsValidGridIndex(gridTo)){kt_int32s index = m_pCellPassCnt->GridIndex(gridTo, false);kt_int32u* pCellPassCntPtr = m_pCellPassCnt->GetDataPointer();kt_int32u* pCellHitCntPtr = m_pCellHitsCnt->GetDataPointer();// increment cell pass through and hit countpCellPassCntPtr[index]++;pCellHitCntPtr[index]++;if (doUpdate){(*m_pCellUpdater)(index);}}}return m_pCellPassCnt->IsValidGridIndex(gridTo);}

3.3  void Grid::TraceLine()

    /*** Increments all the grid cells from (x0, y0) to (x1, y1);* if applicable, apply f to each cell traced* @param x0* @param y0* @param x1* @param y1* @param f*/void Grid::TraceLine(kt_int32s x0, kt_int32s y0, kt_int32s x1, kt_int32s y1, Functor* f = NULL){kt_bool steep = abs(y1 - y0) > abs(x1 - x0);if (steep)           // 如果steep为true,将坐标关于y=x做对称,保持斜率小于45度{std::swap(x0, y0);std::swap(x1, y1);}if (x0 > x1)         // 坐标调换位置,保持x0在左边{std::swap(x0, x1);std::swap(y0, y1);}kt_int32s deltaX = x1 - x0;kt_int32s deltaY = abs(y1 - y0);kt_int32s error = 0;kt_int32s ystep;     // 向上走还是向下走kt_int32s y = y0;if (y0 < y1){ystep = 1;}else{ystep = -1;}kt_int32s pointX;kt_int32s pointY;for (kt_int32s x = x0; x <= x1; x++){if (steep){pointX = y;pointY = x;}else{pointX = x;pointY = y;}error += deltaY;if (2 * error >= deltaX){y += ystep;error -= deltaX;}Vector2<kt_int32s> gridIndex(pointX, pointY);if (IsValidGridIndex(gridIndex)){kt_int32s index = GridIndex(gridIndex, false);  // 二维坐标变为1维索引T* pGridPointer = GetDataPointer();             pGridPointer[index]++;                          // index处的栅格储存的值+1if (f != NULL){(*f)(index);}}}}
    /*** Checks whether the given coordinates are valid grid indices* @param rGrid*/inline kt_bool Grid::IsValidGridIndex(const Vector2<kt_int32s>& rGrid) const{return (math::IsUpTo(rGrid.GetX(), m_Width) && math::IsUpTo(rGrid.GetY(), m_Height));}/*** Checks whether value is in the range [0;maximum)* @param value* @param maximum*/template<typename T>inline kt_bool math::IIsUpTo(const T& value, const T& maximum){return (value >= 0 && value < maximum);}/*** Gets the index into the data pointer of the given grid coordinate* @param rGrid* @param boundaryCheck default value is true* @return grid index*/virtual kt_int32s Grid::GridIndex(const Vector2<kt_int32s>& rGrid, kt_bool boundaryCheck = true) const{if (boundaryCheck == true){if (IsValidGridIndex(rGrid) == false){std::stringstream error;error << "Index " << rGrid << " out of range.  Index must be between [0; "<< m_Width << ") and [0; " << m_Height << ")";throw Exception(error.str());}}kt_int32s index = rGrid.GetX() + (rGrid.GetY() * m_WidthStep);if (boundaryCheck == true){assert(math::IsUpTo(index, GetDataSize()));}return index;}

3.4 virtual void Update()

调用这个函数将更新整个栅格地图,并设置栅格地图的占用状态。更新时是通过pass栅格地图与hit栅格地图中对应栅格的比值进行判断的,hit中的1个值需要pass中的10个值来进行取消(占用的比例为0.1),Grid中的地图,与pass地图,hit地图的大小都一样,Resize()中实现。

Update()在CreateFromScans()中只调用1次,同时维护3个等大小的地图,2个中间地图,一个最终地图。

    /*** Update the grid based on the values in m_pCellHitsCnt and m_pCellPassCnt*/virtual void Update(){assert(m_pCellPassCnt != NULL && m_pCellHitsCnt != NULL);// clear gridClear();// set occupancy status of cellskt_int8u* pDataPtr = GetDataPointer();kt_int32u* pCellPassCntPtr = m_pCellPassCnt->GetDataPointer();kt_int32u* pCellHitCntPtr = m_pCellHitsCnt->GetDataPointer();kt_int32u nBytes = GetDataSize();for (kt_int32u i = 0; i < nBytes; i++, pDataPtr++, pCellPassCntPtr++, pCellHitCntPtr++){UpdateCell(pDataPtr, *pCellPassCntPtr, *pCellHitCntPtr);}}/*** Clear out the grid data*/void Grid::Clear(){memset(m_pData, 0, GetDataSize() * sizeof(T));}

3.5 virtual void UpdateCell()

    /*** Updates a single cell's value based on the given counters* @param pCell* @param cellPassCnt* @param cellHitCnt*/virtual void UpdateCell(kt_int8u* pCell, kt_int32u cellPassCnt, kt_int32u cellHitCnt){if (cellPassCnt > m_pMinPassThrough->GetValue())    // pass栅格图中的值是否大于2{kt_double hitRatio = static_cast<kt_double>(cellHitCnt) / static_cast<kt_double>(cellPassCnt);if (hitRatio > m_pOccupancyThreshold->GetValue()) // hitRatio 是否大于 0.1{                                                 // hit中的1个值需要pass中的10个值来取消掉*pCell = GridStates_Occupied;     // 100 }else{*pCell = GridStates_Free;         // 255}}}

karto探秘之open_karto 第五章 --- 栅格地图的生成相关推荐

  1. Python实现占用栅格地图的生成(Occupancy Grid Generation)

    本文的算法细节及推导可以参考Sebastian Thrun的<概率机器人>中占用栅格地图构建部分. 1. 导入所需要的库 import numpy as np import math im ...

  2. 第十五章 栅格数据重分类、栅格计算器、插值分析

    文章目录 第十五章 栅格数据分析 第一章 栅格数据重分类 第一节 栅格数据重分类 第二节 栅格重分类的使用 第三节 重分类的使用中的空值使用 第四节 重分类的案例:分类统计面积 第五节 坡度矢量分级图 ...

  3. Motion planning for self-driving cars课程笔记1:应用雷达数据生成占用栅格地图(Occupancy Grid Map)

    此文章为Motion planning for self-driving cars上第二课的笔记,主要讲述占据栅格地图的生成.由于课程中算法也是参考<probability robot>这 ...

  4. ORB-SLAM2栅格地图构建

    ORB-SLAM2栅格地图构建 过程 栅格地图的构建是基于稠密点云地图的构建和保存实现的,需要了解可以看我们前面的博客 基于ORB-SLAM2实时构建稠密点云 在点云地图的基础上构建包含占据信息的八叉 ...

  5. matlab构建栅格地图绘图思路

    matlab构建栅格地图绘图思路 近来因研究需要,调研并思考了栅格地图的生成方法,暂时总结以备不时之需. 栅格的建立最需要注意栅格粒度的问题,即根据需要调整栅格的边长,目前有两种思路一种是固定栅格边长 ...

  6. 《NodeJS开发指南》第五章微博实例开发总结

    所有文章搬运自我的个人主页:sheilasun.me <NodeJS开发指南>这本书用来NodeJS入门真是太好了,而且书的附录部分还讲到了闭包.this等JavaScript常用特性.第 ...

  7. 【转载】【《Real-Time Rendering 3rd》 提炼总结】(四) 第五章 · 图形渲染与视觉外观 The Visual Appearance

    本文由@浅墨_毛星云 出品,转载请注明出处.   文章链接: http://blog.csdn.net/poem_qianmo/article/details/72857602 这篇文章将总结和提炼& ...

  8. 计算机辅助设计应用教程,计算机辅助设计基础教程第五章.ppt

    计算机辅助设计基础教程第五章 第5章 3ds max 5.1 3ds max基础知识 5.2 对象的创建与编辑 5.3 复合对象的创建 5.4 NURBS建模 5.5 材质和贴图 5.6 摄影机.灯光 ...

  9. 【《Real-Time Rendering 3rd》 提炼总结】(四) 第五章 · 图形渲染与视觉外观 The Visual Appearance

    本文由@浅墨_毛星云 出品,转载请注明出处.   文章链接: http://blog.csdn.net/poem_qianmo/article/details/72857602 这篇文章将总结和提炼& ...

  10. ArcGIS for Desktop入门教程_第五章_ArcCatalog使用 - ArcGIS知乎-新一代ArcGIS问答社区

    原文:ArcGIS for Desktop入门教程_第五章_ArcCatalog使用 - ArcGIS知乎-新一代ArcGIS问答社区 1 ArcCatalog使用 1.1 GIS数据 地理信息系统, ...

最新文章

  1. BS文件夹上传操作(二) ——基本功能实现
  2. python 结果写入excel_python中如何将测试结果写入到原有的excel表格(二)
  3. C/C++中的数据类型转换
  4. GDCM:转储GEMS Ultrasound MovieGroup的测试程序
  5. 手写的奇怪vector
  6. 漫画:如何实现大整数相加
  7. java 的类和接口的变量调用
  8. python进阶12 Redis
  9. 文件的创建、删除、移动和查找
  10. 《Java语言程序设计》(基础篇原书第10版)第四章复习题答案
  11. 传感器原理与应用复习—电阻式应变传感器部分
  12. 2020_TKDE_DiffNet++_A Neural Influence and Interest Diffusion Network for Social Recommendation
  13. 阿里云企业邮箱标准版多域名绑定
  14. 百度登录界面CSS+HTML
  15. ICE for Linux
  16. 最安全的邮箱大全排名,公司安全邮箱申请如何设置?
  17. tableau可视化图表及仪表板设计
  18. html轮播图点击图片放大,jq点击图片 放大轮播
  19. pfamscan 的使用_科学网—[转载]InterProScan的使用教程 - 黄顺谋的博文
  20. Numpy库的安装与初次使用

热门文章

  1. [The Diary] 11.9 The Final Day
  2. [leetcode]Longest Palindromic Substring
  3. 【转】android gravity属性 和 weight属性
  4. iOS 关于单例那点事
  5. NBOOT分析-NBOOT.c(2)
  6. node 版本管理器 之 nvm 安装与使用
  7. 浅谈 HTTPS 和 SSL -TLS 协议的背景与基础
  8. Winform中 System.Drawing.Color颜色对照表
  9. AngularJS的ng-click阻止冒泡
  10. SqlServer中截取(获取)字符串中特定字符分割的每个元素