OctoMap.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include <rtabmap/core/OctoMap.h>
30 #include <rtabmap/utilite/UStl.h>
31 #include <rtabmap/utilite/UTimer.h>
35 #include <pcl/common/transforms.h>
36 
37 namespace rtabmap {
38 
40 // RtabmapColorOcTree
42 
44 #ifdef OCTOMAP_PRE_18
45  return static_cast<RtabmapColorOcTreeNode*> (OcTreeNode::getChild(i));
46 #else
47  UFATAL("This function should not be used with octomap >= 1.8");
48  return 0;
49 #endif
50 }
52 #ifdef OCTOMAP_PRE_18
53  return static_cast<const RtabmapColorOcTreeNode*> (OcTreeNode::getChild(i));
54 #else
55  UFATAL("This function should not be used with octomap >= 1.8");
56  return 0;
57 #endif
58 }
59 
60 //octomap <1.8
62 #ifdef OCTOMAP_PRE_18
63  // checks for equal occupancy only, color ignored
64  if (!this->collapsible()) return false;
65  // set occupancy value
67  // set color to average color
69  // delete children
70  for (unsigned int i=0;i<8;i++) {
71  delete children[i];
72  }
73  delete[] children;
74  children = NULL;
75  return true;
76 #else
77  UFATAL("This function should not be used with octomap >= 1.8");
78  return false;
79 #endif
80 }
81 //octomap <1.8
83 #ifdef OCTOMAP_PRE_18
84  assert(!hasChildren());
85  for (unsigned int k=0; k<8; k++) {
86  createChild(k);
87  children[k]->setValue(value);
88  getChild(k)->setColor(color);
89  }
90 #else
91  UFATAL("This function should not be used with octomap >= 1.8");
92 #endif
93 }
94 
95 //octomap <1.8
97 #ifdef OCTOMAP_PRE_18
98  if (children == NULL) allocChildren();
100  return true;
101 #else
102  UFATAL("This function should not be used with octomap >= 1.8");
103  return false;
104 #endif
105 }
106 
108  : OccupancyOcTreeBase<RtabmapColorOcTreeNode>(resolution) {
110 };
111 
113  uint8_t r,
114  uint8_t g,
115  uint8_t b) {
116  RtabmapColorOcTreeNode* n = search (key);
117  if (n != 0) {
118  n->setColor(r, g, b);
119  }
120  return n;
121 }
122 
124 #ifndef OCTOMAP_PRE_18
125  if (!isNodeCollapsible(node))
126  return false;
127 
128  // set value to children's values (all assumed equal)
129  node->copyData(*(getNodeChild(node, 0)));
130 
131  if (node->isColorSet()) // TODO check
132  node->setColor(node->getAverageChildColor());
133 
134  // delete children
135  for (unsigned int i=0;i<8;i++) {
136  deleteNodeChild(node, i);
137  }
138  delete[] node->children;
139  node->children = NULL;
140 
141  return true;
142 #else
143  UFATAL("This function should not be used with octomap < 1.8");
144  return false;
145 #endif
146 }
147 
149 #ifndef OCTOMAP_PRE_18
150  // all children must exist, must not have children of
151  // their own and have the same occupancy probability
152  if (!nodeChildExists(node, 0))
153  return false;
154 
155  const RtabmapColorOcTreeNode* firstChild = getNodeChild(node, 0);
156  if (nodeHasChildren(firstChild))
157  return false;
158 
159  for (unsigned int i = 1; i<8; i++) {
160  // compare nodes only using their occupancy, ignoring color for pruning
161  if (!nodeChildExists(node, i) || nodeHasChildren(getNodeChild(node, i)) || !(getNodeChild(node, i)->getValue() == firstChild->getValue()))
162  return false;
163  }
164 
165  return true;
166 #else
167  UFATAL("This function should not be used with octomap < 1.8");
168  return false;
169 #endif
170 }
171 
173  uint8_t r,
174  uint8_t g,
175  uint8_t b) {
176  RtabmapColorOcTreeNode* n = search(key);
177  if (n != 0) {
178  if (n->isColorSet()) {
179  RtabmapColorOcTreeNode::Color prev_color = n->getColor();
180  n->setColor((prev_color.r + r)/2, (prev_color.g + g)/2, (prev_color.b + b)/2);
181  }
182  else {
183  n->setColor(r, g, b);
184  }
185  }
186  return n;
187 }
188 
190  uint8_t r,
191  uint8_t g,
192  uint8_t b) {
193  RtabmapColorOcTreeNode* n = search (key);
194  if (n != 0) {
195  if (n->isColorSet()) {
196  RtabmapColorOcTreeNode::Color prev_color = n->getColor();
197  double node_prob = n->getOccupancy();
198  uint8_t new_r = (uint8_t) ((double) prev_color.r * node_prob
199  + (double) r * (0.99-node_prob));
200  uint8_t new_g = (uint8_t) ((double) prev_color.g * node_prob
201  + (double) g * (0.99-node_prob));
202  uint8_t new_b = (uint8_t) ((double) prev_color.b * node_prob
203  + (double) b * (0.99-node_prob));
204  n->setColor(new_r, new_g, new_b);
205  }
206  else {
207  n->setColor(r, g, b);
208  }
209  }
210  return n;
211 }
212 
213 
215  this->updateInnerOccupancyRecurs(this->root, 0);
216 }
217 
219 #ifndef OCTOMAP_PRE_18
220  // only recurse and update for inner nodes:
221  if (nodeHasChildren(node)){
222  // return early for last level:
223  if (depth < this->tree_depth){
224  for (unsigned int i=0; i<8; i++) {
225  if (nodeChildExists(node, i)) {
226  updateInnerOccupancyRecurs(getNodeChild(node, i), depth+1);
227  }
228  }
229  }
230  node->updateOccupancyChildren();
231  node->updateColorChildren();
232  }
233 #else
234  // only recurse and update for inner nodes:
235  if (node->hasChildren()){
236  // return early for last level:
237  if (depth < this->tree_depth){
238  for (unsigned int i=0; i<8; i++) {
239  if (node->childExists(i)) {
240  updateInnerOccupancyRecurs(node->getChild(i), depth+1);
241  }
242  }
243  }
244  node->updateOccupancyChildren();
245  node->updateColorChildren();
246  }
247 #endif
248 }
249 
252 
253 #ifndef OCTOMAP_PRE_18
254  tree->clearKeyRays();
255 #endif
256 
257  AbstractOcTree::registerTreeType(tree);
258  }
259 
260 
262 // OctoMap
264 
265 OctoMap::OctoMap(const ParametersMap & parameters) :
266  hasColor_(false),
267  fullUpdate_(Parameters::defaultGridGlobalFullUpdate()),
268  updateError_(Parameters::defaultGridGlobalUpdateError()),
269  rangeMax_(Parameters::defaultGridRangeMax()),
270  rayTracing_(Parameters::defaultGridRayTracing())
271 {
272  float cellSize = Parameters::defaultGridCellSize();
273  Parameters::parse(parameters, Parameters::kGridCellSize(), cellSize);
274  UASSERT(cellSize>0.0f);
275 
276  minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
277  maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
278 
279  float occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
280  float probHit = Parameters::defaultGridGlobalProbHit();
281  float probMiss = Parameters::defaultGridGlobalProbMiss();
282  float clampingMin = Parameters::defaultGridGlobalProbClampingMin();
283  float clampingMax = Parameters::defaultGridGlobalProbClampingMax();
284  Parameters::parse(parameters, Parameters::kGridGlobalOccupancyThr(), occupancyThr);
285  Parameters::parse(parameters, Parameters::kGridGlobalProbHit(), probHit);
286  Parameters::parse(parameters, Parameters::kGridGlobalProbMiss(), probMiss);
287  Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMin(), clampingMin);
288  Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMax(), clampingMax);
289 
290  octree_ = new RtabmapColorOcTree(cellSize);
291  if(occupancyThr <= 0.0f)
292  {
293  UWARN("Cannot set %s to null for OctoMap, using default value %f instead.",
294  Parameters::kGridGlobalOccupancyThr().c_str(),
295  Parameters::defaultGridGlobalOccupancyThr());
296  occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
297  }
298  octree_->setOccupancyThres(occupancyThr);
299  octree_->setProbHit(probHit);
300  octree_->setProbMiss(probMiss);
301  octree_->setClampingThresMin(clampingMin);
302  octree_->setClampingThresMax(clampingMax);
303  Parameters::parse(parameters, Parameters::kGridGlobalFullUpdate(), fullUpdate_);
304  Parameters::parse(parameters, Parameters::kGridGlobalUpdateError(), updateError_);
305  Parameters::parse(parameters, Parameters::kGridRangeMax(), rangeMax_);
306  Parameters::parse(parameters, Parameters::kGridRayTracing(), rayTracing_);
307 }
308 
309 OctoMap::OctoMap(float cellSize, float occupancyThr, bool fullUpdate, float updateError) :
310  octree_(new RtabmapColorOcTree(cellSize)),
311  hasColor_(false),
312  fullUpdate_(fullUpdate),
313  updateError_(updateError),
314  rangeMax_(0.0f),
316 {
317  minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
318  maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
319 
320  octree_->setOccupancyThres(occupancyThr);
321  UASSERT(cellSize>0.0f);
322 }
323 
325 {
326  this->clear();
327  delete octree_;
328 }
329 
331 {
332  octree_->clear();
333  cache_.clear();
334  cacheClouds_.clear();
335  cacheViewPoints_.clear();
336  addedNodes_.clear();
338  hasColor_ = false;
339  minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
340  maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
341 }
342 
343 void OctoMap::addToCache(int nodeId,
344  const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & ground,
345  const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & obstacles,
346  const pcl::PointXYZ & viewPoint)
347 {
348  UDEBUG("nodeId=%d", nodeId);
349  cacheClouds_.erase(nodeId);
350  cacheClouds_.insert(std::make_pair(nodeId, std::make_pair(ground, obstacles)));
351  uInsert(cacheViewPoints_, std::make_pair(nodeId, cv::Point3f(viewPoint.x, viewPoint.y, viewPoint.z)));
352 }
353 void OctoMap::addToCache(int nodeId,
354  const cv::Mat & ground,
355  const cv::Mat & obstacles,
356  const cv::Mat & empty,
357  const cv::Point3f & viewPoint)
358 {
359  UASSERT_MSG(ground.empty() || ground.type() == CV_32FC3 || ground.type() == CV_32FC(4) || ground.type() == CV_32FC(6), uFormat("Are local occupancy grids not 3d? (opencv type=%d)", ground.type()).c_str());
360  UASSERT_MSG(obstacles.empty() || obstacles.type() == CV_32FC3 || obstacles.type() == CV_32FC(4) || obstacles.type() == CV_32FC(6), uFormat("Are local occupancy grids not 3d? (opencv type=%d)", obstacles.type()).c_str());
361  UASSERT_MSG(empty.empty() || empty.type() == CV_32FC3 || empty.type() == CV_32FC(4) || empty.type() == CV_32FC(6), uFormat("Are local occupancy grids not 3d? (opencv type=%d)", empty.type()).c_str());
362  UDEBUG("nodeId=%d", nodeId);
363  uInsert(cache_, std::make_pair(nodeId, std::make_pair(std::make_pair(ground, obstacles), empty)));
364  uInsert(cacheViewPoints_, std::make_pair(nodeId, viewPoint));
365 }
366 
367 void OctoMap::update(const std::map<int, Transform> & poses)
368 {
369  UDEBUG("Update (poses=%d addedNodes_=%d)", (int)poses.size(), (int)addedNodes_.size());
370 
371  // First, check of the graph has changed. If so, re-create the octree by moving all occupied nodes.
372  bool graphOptimized = false; // If a loop closure happened (e.g., poses are modified)
373  bool graphChanged = addedNodes_.size()>0; // If the new map doesn't have any node from the previous map
374  std::map<int, Transform> transforms;
375  std::map<int, Transform> updatedAddedNodes;
376  float updateErrorSqrd = updateError_*updateError_;
377  for(std::map<int, Transform>::iterator iter=addedNodes_.begin(); iter!=addedNodes_.end(); ++iter)
378  {
379  std::map<int, Transform>::const_iterator jter = poses.find(iter->first);
380  if(jter != poses.end())
381  {
382  graphChanged = false;
383  UASSERT(!iter->second.isNull() && !jter->second.isNull());
385  if(iter->second.getDistanceSquared(jter->second) > updateErrorSqrd)
386  {
387  t = jter->second * iter->second.inverse();
388  graphOptimized = true;
389  }
390  transforms.insert(std::make_pair(jter->first, t));
391  updatedAddedNodes.insert(std::make_pair(jter->first, jter->second));
392  }
393  else
394  {
395  UDEBUG("Updated pose for node %d is not found, some points may not be copied. Use negative ids to just update cell values without adding new ones.", jter->first);
396  }
397  }
398  if(graphOptimized || graphChanged)
399  {
400  if(graphChanged)
401  {
402  UWARN("Graph has changed! The whole map should be rebuilt.");
403  }
404  else
405  {
406  UINFO("Graph optimized!");
407  }
408 
409  minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
410  maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
411 
412  if(fullUpdate_ || graphChanged)
413  {
414  // clear all but keep cache
415  octree_->clear();
416  addedNodes_.clear();
418  hasColor_ = false;
419  }
420  else
421  {
423  int copied=0;
424  int count=0;
425  UTimer t;
426  for (RtabmapColorOcTree::iterator it = octree_->begin(); it != octree_->end(); ++it, ++count)
427  {
428  RtabmapColorOcTreeNode & nOld = *it;
429  if(nOld.getNodeRefId() > 0)
430  {
431  std::map<int, Transform>::iterator jter = transforms.find(nOld.getNodeRefId());
432  if(jter != transforms.end())
433  {
434  octomap::point3d pt;
435  std::map<int, Transform>::iterator pter = addedNodes_.find(nOld.getNodeRefId());
436  UASSERT(pter != addedNodes_.end());
437 
438  if(nOld.getOccupancyType() > 0)
439  {
440  pt = nOld.getPointRef();
441  }
442  else
443  {
444  pt = octree_->keyToCoord(it.getKey());
445  }
446 
447  cv::Point3f cvPt(pt.x(), pt.y(), pt.z());
448  cvPt = util3d::transformPoint(cvPt, jter->second);
449  octomap::point3d ptTransformed(cvPt.x, cvPt.y, cvPt.z);
450 
451  octomap::OcTreeKey key;
452  if(newOcTree->coordToKeyChecked(ptTransformed, key))
453  {
454  RtabmapColorOcTreeNode * n = newOcTree->search(key);
455  if(n)
456  {
457  if(n->getNodeRefId() > nOld.getNodeRefId())
458  {
459  // The cell has been updated from more recent node, don't update the cell
460  continue;
461  }
462  else if(nOld.getOccupancyType() <= 0 && n->getOccupancyType() > 0)
463  {
464  // empty cells cannot overwrite ground/obstacle cells
465  continue;
466  }
467  }
468 
469  RtabmapColorOcTreeNode * nNew = newOcTree->updateNode(key, nOld.getLogOdds());
470  if(nNew)
471  {
472  ++copied;
473  updateMinMax(ptTransformed);
474  nNew->setNodeRefId(nOld.getNodeRefId());
475  if(nOld.getOccupancyType() > 0)
476  {
477  nNew->setPointRef(pt);
478  }
479  nNew->setOccupancyType(nOld.getOccupancyType());
480  nNew->setColor(nOld.getColor());
481  }
482  else
483  {
484  UERROR("Could not update node at (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
485  }
486  }
487  else
488  {
489  UERROR("Could not find key for (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
490  }
491  }
492  else if(jter == transforms.end())
493  {
494  // Note: normal if old nodes were transfered to LTM
495  //UWARN("Could not find a transform for point linked to node %d (transforms=%d)", iter->second.nodeRefId_, (int)transforms.size());
496  }
497  }
498  }
499  UINFO("Graph optimization detected, moved %d/%d in %fs", copied, count, t.ticks());
500  delete octree_;
501  octree_ = newOcTree;
502 
503  //update added poses
504  addedNodes_ = updatedAddedNodes;
505  }
506  }
507 
508  // Original version from A. Hornung:
509  // https://github.com/OctoMap/octomap_mapping/blob/jade-devel/octomap_server/src/OctomapServer.cpp#L356
510  //
511  std::list<std::pair<int, Transform> > orderedPoses;
512 
513  int lastId = addedNodes_.size()?addedNodes_.rbegin()->first:0;
514  UDEBUG("Last id = %d", lastId);
515 
516  // add old poses that were not in the current map (they were just retrieved from LTM)
517  for(std::map<int, Transform>::const_iterator iter=poses.upper_bound(0); iter!=poses.end(); ++iter)
518  {
519  if(addedNodes_.find(iter->first) == addedNodes_.end())
520  {
521  orderedPoses.push_back(*iter);
522  }
523  }
524 
525  // insert negative after
526  for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
527  {
528  if(iter->first < 0)
529  {
530  orderedPoses.push_back(*iter);
531  }
532  else
533  {
534  break;
535  }
536  }
537 
538  UDEBUG("orderedPoses = %d", (int)orderedPoses.size());
539  float rangeMaxSqrd = rangeMax_*rangeMax_;
540  float cellSize = octree_->getResolution();
541  for(std::list<std::pair<int, Transform> >::const_iterator iter=orderedPoses.begin(); iter!=orderedPoses.end(); ++iter)
542  {
543  std::map<int, std::pair<const pcl::PointCloud<pcl::PointXYZRGB>::Ptr, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr> >::iterator cloudIter;
544  std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator occupancyIter;
545  std::map<int, cv::Point3f>::iterator viewPointIter;
546  cloudIter = cacheClouds_.find(iter->first);
547  occupancyIter = cache_.find(iter->first);
548  viewPointIter = cacheViewPoints_.find(iter->first);
549  if(occupancyIter != cache_.end() || cloudIter != cacheClouds_.end())
550  {
551  UDEBUG("Adding %d to octomap (resolution=%f)", iter->first, octree_->getResolution());
552 
553  UASSERT(viewPointIter != cacheViewPoints_.end());
554  octomap::point3d sensorOrigin(iter->second.x(), iter->second.y(), iter->second.z());
555  sensorOrigin += octomap::point3d(viewPointIter->second.x, viewPointIter->second.y, viewPointIter->second.z);
556 
557  updateMinMax(sensorOrigin);
558 
559  octomap::OcTreeKey tmpKey;
560  if (!octree_->coordToKeyChecked(sensorOrigin, tmpKey)
561  || !octree_->coordToKeyChecked(sensorOrigin, tmpKey))
562  {
563  UERROR("Could not generate Key for origin ", sensorOrigin.x(), sensorOrigin.y(), sensorOrigin.z());
564  }
565 
566  bool computeRays = rayTracing_ && (occupancyIter == cache_.end() || occupancyIter->second.second.empty());
567 
568  // instead of direct scan insertion, compute update to filter ground:
569  octomap::KeySet free_cells;
570  // insert ground points only as free:
571  unsigned int maxGroundPts = occupancyIter != cache_.end()?occupancyIter->second.first.first.cols:cloudIter->second.first->size();
572  UDEBUG("%d: compute free cells (from %d ground points)", iter->first, (int)maxGroundPts);
573  Eigen::Affine3f t = iter->second.toEigen3f();
574  LaserScan tmpGround;
575  if(occupancyIter != cache_.end())
576  {
577  tmpGround = LaserScan::backwardCompatibility(occupancyIter->second.first.first);
578  UASSERT(tmpGround.size() == (int)maxGroundPts);
579  }
580  for (unsigned int i=0; i<maxGroundPts; ++i)
581  {
582  pcl::PointXYZRGB pt;
583  if(occupancyIter != cache_.end())
584  {
585  pt = util3d::laserScanToPointRGB(tmpGround, i);
586  pt = pcl::transformPoint(pt, t);
587  }
588  else
589  {
590  pt = pcl::transformPoint(cloudIter->second.first->at(i), t);
591  }
592  octomap::point3d point(pt.x, pt.y, pt.z);
593  bool ignoreOccupiedCell = false;
594  if(rangeMaxSqrd > 0.0f)
595  {
596  octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
597  if(v.norm_sq() > rangeMaxSqrd)
598  {
599  // compute new point to max range
600  v.normalize();
601  v*=rangeMax_;
602  point = sensorOrigin + v;
603  ignoreOccupiedCell=true;
604  }
605  }
606 
607  if(!ignoreOccupiedCell)
608  {
609  // occupied endpoint
610  octomap::OcTreeKey key;
611  if (octree_->coordToKeyChecked(point, key))
612  {
613  if(iter->first >0 && iter->first<lastId)
614  {
616  if(n && n->getNodeRefId() > 0 && n->getNodeRefId() > iter->first)
617  {
618  // The cell has been updated from more recent node, don't update the cell
619  continue;
620  }
621  }
622 
623  updateMinMax(point);
624  RtabmapColorOcTreeNode * n = octree_->updateNode(key, true);
625 
626  if(n)
627  {
628  if(!hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
629  {
630  hasColor_ = true;
631  }
632  octree_->averageNodeColor(key, pt.r, pt.g, pt.b);
633  if(iter->first > 0)
634  {
635  n->setNodeRefId(iter->first);
636  n->setPointRef(point);
637  }
639  }
640  }
641  }
642 
643  // only clear space (ground points)
644  if (computeRays &&
645  (iter->first < 0 || iter->first>lastId) &&
646  octree_->computeRayKeys(sensorOrigin, point, keyRay_))
647  {
648  free_cells.insert(keyRay_.begin(), keyRay_.end());
649  }
650  }
651  UDEBUG("%d: ground cells=%d free cells=%d", iter->first, (int)maxGroundPts, (int)free_cells.size());
652 
653  // all other points: free on ray, occupied on endpoint:
654  unsigned int maxObstaclePts = occupancyIter != cache_.end()?occupancyIter->second.first.second.cols:cloudIter->second.second->size();
655  UDEBUG("%d: compute occupied cells (from %d obstacle points)", iter->first, (int)maxObstaclePts);
656  LaserScan tmpObstacle;
657  if(occupancyIter != cache_.end())
658  {
659  tmpObstacle = LaserScan::backwardCompatibility(occupancyIter->second.first.second);
660  UASSERT(tmpObstacle.size() == (int)maxObstaclePts);
661  }
662  for (unsigned int i=0; i<maxObstaclePts; ++i)
663  {
664  pcl::PointXYZRGB pt;
665  if(occupancyIter != cache_.end())
666  {
667  pt = util3d::laserScanToPointRGB(tmpObstacle, i);
668  pt = pcl::transformPoint(pt, t);
669  }
670  else
671  {
672  pt = pcl::transformPoint(cloudIter->second.second->at(i), t);
673  }
674 
675  octomap::point3d point(pt.x, pt.y, pt.z);
676 
677  bool ignoreOccupiedCell = false;
678  if(rangeMaxSqrd > 0.0f)
679  {
680  octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
681  if(v.norm_sq() > rangeMaxSqrd)
682  {
683  // compute new point to max range
684  v.normalize();
685  v*=rangeMax_;
686  point = sensorOrigin + v;
687  ignoreOccupiedCell=true;
688  }
689  }
690 
691  if(!ignoreOccupiedCell)
692  {
693  // occupied endpoint
694  octomap::OcTreeKey key;
695  if (octree_->coordToKeyChecked(point, key))
696  {
697  if(iter->first >0 && iter->first<lastId)
698  {
700  if(n && n->getNodeRefId() > 0 && n->getNodeRefId() > iter->first)
701  {
702  // The cell has been updated from more recent node, don't update the cell
703  continue;
704  }
705  }
706 
707  updateMinMax(point);
708 
709  RtabmapColorOcTreeNode * n = octree_->updateNode(key, true);
710  if(n)
711  {
712  if(!hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
713  {
714  hasColor_ = true;
715  }
716  octree_->averageNodeColor(key, pt.r, pt.g, pt.b);
717  if(iter->first > 0)
718  {
719  n->setNodeRefId(iter->first);
720  n->setPointRef(point);
721  }
723  }
724  }
725  }
726 
727  // free cells
728  if (computeRays &&
729  (iter->first < 0 || iter->first>lastId) &&
730  octree_->computeRayKeys(sensorOrigin, point, keyRay_))
731  {
732  free_cells.insert(keyRay_.begin(), keyRay_.end());
733  }
734  }
735  UDEBUG("%d: occupied cells=%d free cells=%d", iter->first, (int)maxObstaclePts, (int)free_cells.size());
736 
737 
738  // mark free cells only if not seen occupied in this cloud
739  for(octomap::KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ++it)
740  {
741  if(iter->first > 0)
742  {
744  if(n && n->getNodeRefId() > 0 && n->getNodeRefId() >= iter->first)
745  {
746  // The cell has been updated from current node or more recent node, don't update the cell
747  continue;
748  }
749  }
750 
751  RtabmapColorOcTreeNode * n = octree_->updateNode(*it, false);
753  {
755  if(iter->first > 0)
756  {
757  n->setNodeRefId(iter->first);
758  }
759  }
760  }
761 
762  // all empty cells
763  if(occupancyIter != cache_.end() && occupancyIter->second.second.cols)
764  {
765  unsigned int maxEmptyPts = occupancyIter->second.second.cols;
766  UDEBUG("%d: compute free cells (from %d empty points)", iter->first, (int)maxEmptyPts);
767  LaserScan tmpEmpty = LaserScan::backwardCompatibility(occupancyIter->second.second);
768  UASSERT(tmpEmpty.size() == (int)maxEmptyPts);
769  for (unsigned int i=0; i<maxEmptyPts; ++i)
770  {
771  pcl::PointXYZ pt;
772  pt = util3d::laserScanToPoint(tmpEmpty, i);
773  pt = pcl::transformPoint(pt, t);
774 
775  octomap::point3d point(pt.x, pt.y, pt.z);
776 
777  bool ignoreCell = false;
778  if(rangeMaxSqrd > 0.0f)
779  {
780  octomap::point3d v(pt.x - sensorOrigin.x(), pt.y - sensorOrigin.y(), pt.z - sensorOrigin.z());
781  if(v.norm_sq() > rangeMaxSqrd)
782  {
783  ignoreCell=true;
784  }
785  }
786 
787  if(!ignoreCell)
788  {
789  octomap::OcTreeKey key;
790  if (octree_->coordToKeyChecked(point, key))
791  {
792 
793  if(iter->first >0)
794  {
796  if(n && n->getNodeRefId() > 0 && n->getNodeRefId() >= iter->first)
797  {
798  // The cell has been updated from current node or more recent node, don't update the cell
799  continue;
800  }
801  }
802 
803  updateMinMax(point);
804 
805  RtabmapColorOcTreeNode * n = octree_->updateNode(key, false);
807  {
809  if(iter->first > 0)
810  {
811  n->setNodeRefId(iter->first);
812  }
813  }
814  }
815  }
816  }
817  }
818 
819  // compress map
820  //octree_->prune();
821 
822  // ignore negative ids as they are temporary clouds
823  if(iter->first > 0)
824  {
825  addedNodes_.insert(*iter);
826  }
827  UDEBUG("%d: end", iter->first);
828  }
829  else
830  {
831  UDEBUG("Did not find %d in cache", iter->first);
832  }
833  }
834 
835  if(!fullUpdate_)
836  {
837  cache_.clear();
838  cacheClouds_.clear();
839  cacheViewPoints_.clear();
840  }
841 }
842 
844 {
845  if(point.x() < minValues_[0])
846  {
847  minValues_[0] = point.x();
848  }
849  if(point.y() < minValues_[1])
850  {
851  minValues_[1] = point.y();
852  }
853  if(point.z() < minValues_[2])
854  {
855  minValues_[2] = point.z();
856  }
857  if(point.x() > maxValues_[0])
858  {
859  maxValues_[0] = point.x();
860  }
861  if(point.y() > maxValues_[1])
862  {
863  maxValues_[1] = point.y();
864  }
865  if(point.z() > maxValues_[2])
866  {
867  maxValues_[2] = point.z();
868  }
869 }
870 
871 void OctoMap::HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
872 {
873  int i;
874  float f, p, q, t;
875  if( s == 0 ) {
876  // achromatic (grey)
877  *r = *g = *b = v;
878  return;
879  }
880  h /= 60; // sector 0 to 5
881  i = floor( h );
882  f = h - i; // factorial part of h
883  p = v * ( 1 - s );
884  q = v * ( 1 - s * f );
885  t = v * ( 1 - s * ( 1 - f ) );
886  switch( i ) {
887  case 0:
888  *r = v;
889  *g = t;
890  *b = p;
891  break;
892  case 1:
893  *r = q;
894  *g = v;
895  *b = p;
896  break;
897  case 2:
898  *r = p;
899  *g = v;
900  *b = t;
901  break;
902  case 3:
903  *r = p;
904  *g = q;
905  *b = v;
906  break;
907  case 4:
908  *r = t;
909  *g = p;
910  *b = v;
911  break;
912  default: // case 5:
913  *r = v;
914  *g = p;
915  *b = q;
916  break;
917  }
918 }
919 
920 pcl::PointCloud<pcl::PointXYZRGB>::Ptr OctoMap::createCloud(
921  unsigned int treeDepth,
922  std::vector<int> * obstacleIndices,
923  std::vector<int> * emptyIndices,
924  std::vector<int> * groundIndices,
925  bool originalRefPoints) const
926 {
927  UASSERT(treeDepth <= octree_->getTreeDepth());
928  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
929  UDEBUG("depth=%d (maxDepth=%d) octree = %d",
930  (int)treeDepth, (int)octree_->getTreeDepth(), (int)octree_->size());
931  cloud->resize(octree_->size());
932  if(obstacleIndices)
933  {
934  obstacleIndices->resize(octree_->size());
935  }
936  if(emptyIndices)
937  {
938  emptyIndices->resize(octree_->size());
939  }
940  if(groundIndices)
941  {
942  groundIndices->resize(octree_->size());
943  }
944 
945  if(treeDepth == 0)
946  {
947  treeDepth = octree_->getTreeDepth();
948  }
949 
950  double minZ = minValues_[2];
951  double maxZ = maxValues_[2];
952 
953  bool addAllPoints = obstacleIndices == 0 && groundIndices == 0 && emptyIndices == 0;
954  int oi=0;
955  int si=0;
956  int ei=0;
957  int gi=0;
958  float halfCellSize = octree_->getNodeSize(treeDepth)/2.0f;
959  for (RtabmapColorOcTree::iterator it = octree_->begin(treeDepth); it != octree_->end(); ++it)
960  {
961  if(octree_->isNodeOccupied(*it) && (obstacleIndices != 0 || groundIndices != 0 || addAllPoints))
962  {
963  octomap::point3d pt = octree_->keyToCoord(it.getKey());
964  if(octree_->getTreeDepth() == it.getDepth() && hasColor_)
965  {
966  (*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
967  }
968  else
969  {
970  // Gradiant color on z axis
971  float H = (maxZ - pt.z())*299.0f/(maxZ-minZ);
972  float r,g,b;
973  HSVtoRGB(&r, &g, &b, H, 1, 1);
974  (*cloud)[oi].r = r*255.0f;
975  (*cloud)[oi].g = g*255.0f;
976  (*cloud)[oi].b = b*255.0f;
977  }
978 
979  if(originalRefPoints && it->getOccupancyType() > 0)
980  {
981  const octomap::point3d & p = it->getPointRef();
982  (*cloud)[oi].x = p.x();
983  (*cloud)[oi].y = p.y();
984  (*cloud)[oi].z = p.z();
985  }
986  else
987  {
988  (*cloud)[oi].x = pt.x()-halfCellSize;
989  (*cloud)[oi].y = pt.y()-halfCellSize;
990  (*cloud)[oi].z = pt.z();
991  }
992 
993  if(it->getOccupancyType() == RtabmapColorOcTreeNode::kTypeGround)
994  {
995  if(groundIndices)
996  {
997  groundIndices->at(gi++) = oi;
998  }
999  }
1000  else if(obstacleIndices)
1001  {
1002  obstacleIndices->at(si++) = oi;
1003  }
1004 
1005  ++oi;
1006  }
1007  else if(!octree_->isNodeOccupied(*it) && (emptyIndices != 0 || addAllPoints))
1008  {
1009  octomap::point3d pt = octree_->keyToCoord(it.getKey());
1010  (*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
1011  (*cloud)[oi].x = pt.x()-halfCellSize;
1012  (*cloud)[oi].y = pt.y()-halfCellSize;
1013  (*cloud)[oi].z = pt.z();
1014  if(emptyIndices)
1015  {
1016  emptyIndices->at(ei++) = oi;
1017  }
1018  ++oi;
1019  }
1020  }
1021 
1022  cloud->resize(oi);
1023  if(obstacleIndices)
1024  {
1025  obstacleIndices->resize(si);
1026  UDEBUG("obstacle=%d", si);
1027  }
1028  if(emptyIndices)
1029  {
1030  emptyIndices->resize(ei);
1031  UDEBUG("empty=%d", ei);
1032  }
1033  if(groundIndices)
1034  {
1035  groundIndices->resize(gi);
1036  UDEBUG("ground=%d", gi);
1037  }
1038 
1039  UDEBUG("");
1040  return cloud;
1041 }
1042 
1043 cv::Mat OctoMap::createProjectionMap(float & xMin, float & yMin, float & gridCellSize, float minGridSize, unsigned int treeDepth)
1044 {
1045  UDEBUG("minGridSize=%f, treeDepth=%d", minGridSize, (int)treeDepth);
1046  UASSERT(treeDepth <= octree_->getTreeDepth());
1047  if(treeDepth == 0)
1048  {
1049  treeDepth = octree_->getTreeDepth();
1050  }
1051 
1052  gridCellSize = octree_->getNodeSize(treeDepth);
1053  float halfCellSize = gridCellSize/2.0f;
1054 
1055  cv::Mat obstaclesMat = cv::Mat(1, (int)octree_->size(), CV_32FC2);
1056  cv::Mat groundMat = cv::Mat(1, (int)octree_->size(), CV_32FC2);
1057  int gi=0;
1058  int oi=0;
1059  cv::Vec2f * oPtr = obstaclesMat.ptr<cv::Vec2f>(0,0);
1060  cv::Vec2f * gPtr = groundMat.ptr<cv::Vec2f>(0,0);
1061  for (RtabmapColorOcTree::iterator it = octree_->begin(treeDepth); it != octree_->end(); ++it)
1062  {
1063  octomap::point3d pt = octree_->keyToCoord(it.getKey());
1064  if(octree_->isNodeOccupied(*it) && it->getOccupancyType() == RtabmapColorOcTreeNode::kTypeObstacle)
1065  {
1066  // projected on ground
1067  oPtr[oi][0] = pt.x()-halfCellSize;
1068  oPtr[oi][1] = pt.y()-halfCellSize;
1069  ++oi;
1070  }
1071  else
1072  {
1073  // projected on ground
1074  gPtr[gi][0] = pt.x()-halfCellSize;
1075  gPtr[gi][1] = pt.y()-halfCellSize;
1076  ++gi;
1077  }
1078  }
1079  obstaclesMat = obstaclesMat(cv::Range::all(), cv::Range(0, oi));
1080  groundMat = groundMat(cv::Range::all(), cv::Range(0, gi));
1081 
1082  std::map<int, Transform> poses;
1083  poses.insert(std::make_pair(1, Transform::getIdentity()));
1084  std::map<int, std::pair<cv::Mat, cv::Mat> > maps;
1085  maps.insert(std::make_pair(1, std::make_pair(groundMat, obstaclesMat)));
1086 
1088  poses,
1089  maps,
1090  gridCellSize,
1091  xMin, yMin,
1092  minGridSize,
1093  false);
1094  UDEBUG("");
1095  return map;
1096 }
1097 
1098 bool OctoMap::writeBinary(const std::string & path)
1099 {
1100  return octree_->writeBinary(path);
1101 }
1102 
1103 } /* namespace rtabmap */
#define NULL
static bool parse(const ParametersMap &parameters, const std::string &key, bool &value)
Definition: Parameters.cpp:446
iterator begin()
iterator begin(unsigned char maxDepth=0) const
Definition: UTimer.h:46
ColorOcTreeNode::Color getAverageChildColor() const
cv::Mat RTABMAP_EXP create2DMapFromOccupancyLocalMaps(const std::map< int, Transform > &poses, const std::map< int, std::pair< cv::Mat, cv::Mat > > &occupancy, float cellSize, float &xMin, float &yMin, float minMapSize=0.0f, bool erode=false, float footprintRadius=0.0f)
float getValue() const
bool isColorSet() const
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
RtabmapColorOcTreeNode * averageNodeColor(const octomap::OcTreeKey &key, uint8_t r, uint8_t g, uint8_t b)
Definition: OctoMap.cpp:172
static StaticMemberInitializer RtabmapColorOcTreeMemberInit
static member to ensure static initialization (only once)
Definition: OctoMap.h:165
static void HSVtoRGB(float *r, float *g, float *b, float h, float s, float v)
Definition: OctoMap.cpp:871
Vector3 & normalize()
f
void updateMinMax(const octomap::point3d &point)
Definition: OctoMap.cpp:843
void update(const std::map< int, Transform > &poses)
Definition: OctoMap.cpp:367
virtual NODE * updateNode(const OcTreeKey &key, float log_odds_update, bool lazy_eval=false)
static Transform getIdentity()
Definition: Transform.cpp:364
std::map< int, Transform > addedNodes_
Definition: OctoMap.h:225
const iterator end() const
void deleteNodeChild(RtabmapColorOcTreeNode *node, unsigned int childIdx)
bool createChild(unsigned int i)
Definition: OctoMap.cpp:96
bool fullUpdate_
Definition: OctoMap.h:228
std::map< int, cv::Point3f > cacheViewPoints_
Definition: OctoMap.h:223
RtabmapColorOcTreeNode * getChild(unsigned int i)
Definition: OctoMap.cpp:43
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
std::map< std::string, std::string > ParametersMap
Definition: Parameters.h:41
RtabmapColorOcTreeNode * search(double x, double y, double z, unsigned int depth=0) const
pcl::PointXYZ RTABMAP_EXP laserScanToPoint(const LaserScan &laserScan, int index)
Definition: util3d.cpp:2433
unsigned int getTreeDepth() const
void updateOccupancyChildren()
virtual bool isNodeCollapsible(const RtabmapColorOcTreeNode *node) const
Definition: OctoMap.cpp:148
int size() const
Definition: LaserScan.h:70
bool coordToKeyChecked(const point3d &coord, OcTreeKey &key) const
void setPointRef(const octomap::point3d &point)
Definition: OctoMap.h:63
#define UFATAL(...)
void setNodeRefId(int nodeRefId)
Definition: OctoMap.h:61
RtabmapColorOcTreeNode * getNodeChild(RtabmapColorOcTreeNode *node, unsigned int childIdx) const
detail::uint8 uint8_t
Definition: fwd.hpp:908
#define UASSERT(condition)
Wrappers of STL for convenient functions.
bool computeRayKeys(const point3d &origin, const point3d &end, KeyRay &ray) const
void setLogOdds(float l)
void addToCache(int nodeId, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &ground, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &obstacles, const pcl::PointXYZ &viewPoint)
Definition: OctoMap.cpp:343
std::map< int, std::pair< std::pair< cv::Mat, cv::Mat >, cv::Mat > > cache_
Definition: OctoMap.h:221
const octomap::point3d & getPointRef() const
Definition: OctoMap.h:66
#define true
Definition: ConvertUTF.c:57
RtabmapColorOcTreeNode * integrateNodeColor(const octomap::OcTreeKey &key, uint8_t r, uint8_t g, uint8_t b)
Definition: OctoMap.cpp:189
int getOccupancyType() const
Definition: OctoMap.h:65
std::map< int, std::pair< const pcl::PointCloud< pcl::PointXYZRGB >::Ptr, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr > > cacheClouds_
Definition: OctoMap.h:222
GLM_FUNC_DECL genType floor(genType const &x)
AbstractOcTreeNode ** children
#define UASSERT_MSG(condition, msg_str)
Definition: ULogger.h:67
octomap::KeyRay keyRay_
Definition: OctoMap.h:226
bool nodeHasChildren(const RtabmapColorOcTreeNode *node) const
RtabmapColorOcTree * octree_
Definition: OctoMap.h:224
pcl::PointXYZRGB RTABMAP_EXP laserScanToPointRGB(const LaserScan &laserScan, int index, unsigned char r=255, unsigned char g=255, unsigned char b=255)
Definition: util3d.cpp:2468
pcl::PointCloud< pcl::PointXYZRGB >::Ptr createCloud(unsigned int treeDepth=0, std::vector< int > *obstacleIndices=0, std::vector< int > *emptyIndices=0, std::vector< int > *groundIndices=0, bool originalRefPoints=true) const
Definition: OctoMap.cpp:920
float getLogOdds() const
unordered_ns::unordered_set< OcTreeKey, OcTreeKey::KeyHash > KeySet
tree
RtabmapColorOcTree(double resolution)
Default constructor, sets resolution of leafs.
Definition: OctoMap.cpp:107
double getOccupancy() const
void setOccupancyType(char type)
Definition: OctoMap.h:62
void updateInnerOccupancyRecurs(RtabmapColorOcTreeNode *node, unsigned int depth)
Definition: OctoMap.cpp:218
iterator end()
#define false
Definition: ConvertUTF.c:56
double minValues_[3]
Definition: OctoMap.h:232
virtual ~OctoMap()
Definition: OctoMap.cpp:324
float rangeMax_
Definition: OctoMap.h:230
#define UDEBUG(...)
double getResolution() const
bool writeBinary(const std::string &path)
Definition: OctoMap.cpp:1098
octomath::Vector3 point3d
#define UERROR(...)
ULogger class and convenient macros.
#define UWARN(...)
bool nodeChildExists(const RtabmapColorOcTreeNode *node, unsigned int childIdx) const
double ticks()
Definition: UTimer.cpp:110
OctoMap(const ParametersMap &parameters)
Definition: OctoMap.cpp:265
double getNodeSize(unsigned depth) const
RtabmapColorOcTreeNode * setNodeColor(const octomap::OcTreeKey &key, uint8_t r, uint8_t g, uint8_t b)
Definition: OctoMap.cpp:112
bool rayTracing_
Definition: OctoMap.h:231
cv::Mat createProjectionMap(float &xMin, float &yMin, float &gridCellSize, float minGridSize=0.0f, unsigned int treeDepth=0)
Definition: OctoMap.cpp:1043
double maxValues_[3]
Definition: OctoMap.h:233
std::string UTILITE_EXP uFormat(const char *fmt,...)
virtual bool pruneNode(RtabmapColorOcTreeNode *node)
Definition: OctoMap.cpp:123
static LaserScan backwardCompatibility(const cv::Mat &oldScanFormat, int maxPoints=0, int maxRange=0, const Transform &localTransform=Transform::getIdentity())
Definition: LaserScan.cpp:84
virtual size_t size() const
float updateError_
Definition: OctoMap.h:229
void copyData(const ColorOcTreeNode &from)
double keyToCoord(key_type key, unsigned depth) const
Color getColor() const
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
Definition: UStl.h:443
#define UINFO(...)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Wed Jun 5 2019 22:41:32