36 #include <pcl/common/transforms.h> 49 UFATAL(
"This function should not be used with octomap >= 1.8");
57 UFATAL(
"This function should not be used with octomap >= 1.8");
66 if (!this->collapsible())
return false;
72 for (
unsigned int i=0;i<8;i++) {
79 UFATAL(
"This function should not be used with octomap >= 1.8");
86 assert(!hasChildren());
87 for (
unsigned int k=0; k<8; k++) {
93 UFATAL(
"This function should not be used with octomap >= 1.8");
104 UFATAL(
"This function should not be used with octomap >= 1.8");
143 #ifndef OCTOMAP_PRE_18 154 for (
unsigned int i=0;i<8;i++) {
162 UFATAL(
"This function should not be used with octomap < 1.8");
168 #ifndef OCTOMAP_PRE_18 178 for (
unsigned int i = 1; i<8; i++) {
186 UFATAL(
"This function should not be used with octomap < 1.8");
198 RtabmapColorOcTreeNode::Color prev_color = n->
getColor();
199 n->
setColor((prev_color.r + r)/2, (prev_color.g + g)/2, (prev_color.b + b)/2);
215 RtabmapColorOcTreeNode::Color prev_color = n->
getColor();
218 + (double) r * (0.99-node_prob));
220 + (double) g * (0.99-node_prob));
222 + (double) b * (0.99-node_prob));
238 #ifndef OCTOMAP_PRE_18 243 for (
unsigned int i=0; i<8; i++) {
255 if (node->hasChildren()){
258 for (
unsigned int i=0; i<8; i++) {
259 if (node->childExists(i)) {
274 #ifndef OCTOMAP_PRE_18 278 AbstractOcTree::registerTreeType(tree);
293 fullUpdate_(
Parameters::defaultGridGlobalFullUpdate()),
294 updateError_(
Parameters::defaultGridGlobalUpdateError()),
296 rayTracing_(
Parameters::defaultGridRayTracing()),
297 emptyFloodFillDepth_(
Parameters::defaultGridGlobalFloodFillDepth())
299 float cellSize = Parameters::defaultGridCellSize();
306 float occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
307 float probHit = Parameters::defaultGridGlobalProbHit();
308 float probMiss = Parameters::defaultGridGlobalProbMiss();
309 float clampingMin = Parameters::defaultGridGlobalProbClampingMin();
310 float clampingMax = Parameters::defaultGridGlobalProbClampingMax();
311 Parameters::parse(parameters, Parameters::kGridGlobalOccupancyThr(), occupancyThr);
314 Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMin(), clampingMin);
315 Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMax(), clampingMax);
318 if(occupancyThr <= 0.0
f)
320 UWARN(
"Cannot set %s to null for OctoMap, using default value %f instead.",
321 Parameters::kGridGlobalOccupancyThr().c_str(),
322 Parameters::defaultGridGlobalOccupancyThr());
323 occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
325 octree_->setOccupancyThres(occupancyThr);
327 octree_->setProbMiss(probMiss);
328 octree_->setClampingThresMin(clampingMin);
329 octree_->setClampingThresMax(clampingMax);
364 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & ground,
365 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & obstacles,
366 const pcl::PointXYZ & viewPoint)
368 UDEBUG(
"nodeId=%d", nodeId);
371 UWARN(
"Cannot add nodes with negative id (nodeId=%d)", nodeId);
375 cacheClouds_.insert(std::make_pair(nodeId==0?-1:nodeId, std::make_pair(ground, obstacles)));
376 uInsert(
cacheViewPoints_, std::make_pair(nodeId==0?-1:nodeId, cv::Point3f(viewPoint.x, viewPoint.y, viewPoint.z)));
379 const cv::Mat & ground,
380 const cv::Mat & obstacles,
381 const cv::Mat & empty,
382 const cv::Point3f & viewPoint)
384 UDEBUG(
"nodeId=%d", nodeId);
387 UWARN(
"Cannot add nodes with negative id (nodeId=%d)", nodeId);
390 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());
391 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());
392 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());
393 uInsert(
cache_, std::make_pair(nodeId==0?-1:nodeId, std::make_pair(std::make_pair(ground, obstacles), empty)));
399 auto nodePtr = octree_->
search(startPosition.
x(), startPosition.
y(), startPosition.
z(), treeDepth);
402 if(!octree_->isNodeOccupied(*nodePtr))
417 return startPosition;
458 return startPosition;
463 for(
auto it = EmptyNodes.find(key);it != EmptyNodes.end();it++)
477 auto key = octree_->
coordToKey(startPosition,treeDepth);
482 EmptyNodes.insert(key);
496 std::unordered_set<octomap::OcTreeKey, octomap::OcTreeKey::KeyHash> exploreNode;
497 std::queue<octomap::point3d> positionToExplore;
501 floodFill(octree_, treeDepth, startPosition, exploreNode, positionToExplore);
502 while(!positionToExplore.empty())
504 floodFill(octree_, treeDepth, positionToExplore.front(), exploreNode, positionToExplore);
505 positionToExplore.pop();
514 UDEBUG(
"Update (poses=%d addedNodes_=%d)", (
int)poses.size(), (int)
addedNodes_.size());
517 bool graphOptimized =
false;
519 std::map<int, Transform> transforms;
520 std::map<int, Transform> updatedAddedNodes;
524 std::map<int, Transform>::const_iterator jter = poses.find(iter->first);
525 if(jter != poses.end())
527 graphChanged =
false;
528 UASSERT(!iter->second.isNull() && !jter->second.isNull());
530 if(iter->second.getDistanceSquared(jter->second) > updateErrorSqrd)
532 t = jter->second * iter->second.inverse();
533 graphOptimized =
true;
535 transforms.insert(std::make_pair(jter->first, t));
536 updatedAddedNodes.insert(std::make_pair(jter->first, jter->second));
540 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);
544 if(graphOptimized || graphChanged)
548 UWARN(
"Graph has changed! The whole map should be rebuilt.");
552 UINFO(
"Graph optimized!");
576 std::map<int, Transform>::iterator jter = transforms.find(nOld.
getNodeRefId());
577 if(jter != transforms.end())
592 cv::Point3f cvPt(pt.
x(), pt.
y(), pt.
z());
629 UERROR(
"Could not update node at (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
634 UERROR(
"Could not find key for (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
637 else if(jter == transforms.end())
644 UINFO(
"Graph optimization detected, moved %d/%d in %fs", copied, count, t.
ticks());
656 std::list<std::pair<int, Transform> > orderedPoses;
659 UDEBUG(
"Last id = %d", lastId);
662 for(std::map<int, Transform>::const_iterator iter=poses.lower_bound(1); iter!=poses.end(); ++iter)
666 orderedPoses.push_back(*iter);
671 if(poses.find(0) != poses.end())
673 orderedPoses.push_back(std::make_pair(-1, poses.at(0)));
676 UDEBUG(
"orderedPoses = %d", (
int)orderedPoses.size());
678 if(!orderedPoses.empty())
682 for(std::list<std::pair<int, Transform> >::const_iterator iter=orderedPoses.begin(); iter!=orderedPoses.end(); ++iter)
684 std::map<int, std::pair<const pcl::PointCloud<pcl::PointXYZRGB>::Ptr,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr> >::iterator cloudIter;
685 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator occupancyIter;
686 std::map<int, cv::Point3f>::iterator viewPointIter;
688 occupancyIter =
cache_.find(iter->first);
695 octomap::point3d sensorOrigin(iter->second.x(), iter->second.y(), iter->second.z());
696 sensorOrigin +=
octomap::point3d(viewPointIter->second.x, viewPointIter->second.y, viewPointIter->second.z);
704 UERROR(
"Could not generate Key for origin ", sensorOrigin.x(), sensorOrigin.y(), sensorOrigin.z());
707 bool computeRays =
rayTracing_ && (occupancyIter ==
cache_.end() || occupancyIter->second.second.empty());
712 unsigned int maxGroundPts = occupancyIter !=
cache_.end()?occupancyIter->second.first.first.cols:cloudIter->second.first->size();
713 UDEBUG(
"%d: compute free cells (from %d ground points)", iter->first, (
int)maxGroundPts);
714 Eigen::Affine3f t = iter->second.toEigen3f();
716 if(occupancyIter !=
cache_.end())
721 for (
unsigned int i=0; i<maxGroundPts; ++i)
724 if(occupancyIter !=
cache_.end())
734 bool ignoreOccupiedCell =
false;
735 if(rangeMaxSqrd > 0.0
f)
737 octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
738 if(v.norm_sq() > rangeMaxSqrd)
743 point = sensorOrigin + v;
744 ignoreOccupiedCell=
true;
748 if(!ignoreOccupiedCell)
754 if(iter->first >0 && iter->first<lastId)
769 if(!
hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
787 (iter->first < 0 || iter->first>lastId) &&
790 free_cells.insert(keyRay.
begin(), keyRay.
end());
793 UDEBUG(
"%d: ground cells=%d free cells=%d", iter->first, (
int)maxGroundPts, (
int)free_cells.size());
796 unsigned int maxObstaclePts = occupancyIter !=
cache_.end()?occupancyIter->second.first.second.cols:cloudIter->second.second->size();
797 UDEBUG(
"%d: compute occupied cells (from %d obstacle points)", iter->first, (
int)maxObstaclePts);
799 if(occupancyIter !=
cache_.end())
802 UASSERT(tmpObstacle.
size() == (int)maxObstaclePts);
804 for (
unsigned int i=0; i<maxObstaclePts; ++i)
807 if(occupancyIter !=
cache_.end())
819 bool ignoreOccupiedCell =
false;
820 if(rangeMaxSqrd > 0.0
f)
822 octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
823 if(v.norm_sq() > rangeMaxSqrd)
828 point = sensorOrigin + v;
829 ignoreOccupiedCell=
true;
833 if(!ignoreOccupiedCell)
839 if(iter->first >0 && iter->first<lastId)
854 if(!
hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
872 (iter->first < 0 || iter->first>lastId) &&
875 free_cells.insert(keyRay.
begin(), keyRay.
end());
878 UDEBUG(
"%d: occupied cells=%d free cells=%d", iter->first, (
int)maxObstaclePts, (
int)free_cells.size());
882 for(octomap::KeySet::iterator it = free_cells.begin(),
end=free_cells.end(); it!=
end; ++it)
906 if(occupancyIter !=
cache_.end() && occupancyIter->second.second.cols)
908 unsigned int maxEmptyPts = occupancyIter->second.second.cols;
909 UDEBUG(
"%d: compute free cells (from %d empty points)", iter->first, (
int)maxEmptyPts);
912 for (
unsigned int i=0; i<maxEmptyPts; ++i)
920 bool ignoreCell =
false;
921 if(rangeMaxSqrd > 0.0
f)
923 octomap::point3d v(pt.x - sensorOrigin.x(), pt.y - sensorOrigin.y(), pt.z - sensorOrigin.z());
924 if(v.norm_sq() > rangeMaxSqrd)
962 if((occupancyIter !=
cache_.end() && occupancyIter->second.second.cols) || !free_cells.empty())
978 UDEBUG(
"%d: end", iter->first);
982 UDEBUG(
"Did not find %d in cache", iter->first);
995 std::vector<octomap::OcTreeKey> nodeToDelete;
999 if(!
octree_->isNodeOccupied(*it))
1003 nodeToDelete.push_back(it.getKey());
1009 for(
unsigned int y=0; y < nodeToDelete.size(); y++)
1013 UDEBUG(
"Flood Fill: deleted %d empty cells (%fs)", (
int)nodeToDelete.size(), t.
ticks());
1055 unsigned int treeDepth,
1056 std::vector<int> * obstacleIndices,
1057 std::vector<int> * emptyIndices,
1058 std::vector<int> * groundIndices,
1059 bool originalRefPoints,
1060 std::vector<int> * frontierIndices,
1061 std::vector<double> * cloudProb)
const 1063 UASSERT(treeDepth <= octree_->getTreeDepth());
1064 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
1069 UDEBUG(
"depth=%d (maxDepth=%d) octree = %d",
1097 bool addAllPoints = obstacleIndices == 0 && groundIndices == 0 && emptyIndices == 0;
1107 if(
octree_->isNodeOccupied(*it) && (obstacleIndices != 0 || groundIndices != 0 || addAllPoints))
1112 (*cloudProb)[oi] = it->getOccupancy();
1116 (*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
1121 float H = (maxZ - pt.
z())*299.0
f/(maxZ-minZ);
1124 (*cloud)[oi].r = r*255.0f;
1125 (*cloud)[oi].g = g*255.0f;
1126 (*cloud)[oi].b = b*255.0f;
1129 if(originalRefPoints && it->getOccupancyType() > 0)
1132 (*cloud)[oi].
x = p.
x();
1133 (*cloud)[oi].y = p.
y();
1134 (*cloud)[oi].z = p.
z();
1138 (*cloud)[oi].x = pt.
x()-halfCellSize;
1139 (*cloud)[oi].y = pt.
y()-halfCellSize;
1140 (*cloud)[oi].z = pt.
z();
1147 groundIndices->at(gi++) = oi;
1150 else if(obstacleIndices)
1152 obstacleIndices->at(si++) = oi;
1157 else if(!
octree_->isNodeOccupied(*it) && (emptyIndices != 0 || addAllPoints || frontierIndices !=0))
1162 (*cloudProb)[oi] = it->getOccupancy();
1164 if(frontierIndices !=0 &&
1170 frontierIndices->at(fi++) = oi;
1174 (*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
1175 (*cloud)[oi].x = pt.
x()-halfCellSize;
1176 (*cloud)[oi].y = pt.
y()-halfCellSize;
1177 (*cloud)[oi].z = pt.
z();
1181 emptyIndices->at(ei++) = oi;
1191 cloudProb->resize(oi);
1195 obstacleIndices->resize(si);
1196 UDEBUG(
"obstacle=%d", si);
1200 emptyIndices->resize(ei);
1205 frontierIndices->resize(fi);
1206 UDEBUG(
"frontier=%d", fi);
1210 groundIndices->resize(gi);
1220 UDEBUG(
"minGridSize=%f, treeDepth=%d", minGridSize, (
int)treeDepth);
1221 UASSERT(treeDepth <= octree_->getTreeDepth());
1229 cv::Mat obstaclesMat = cv::Mat(1, (
int)
octree_->
size(), CV_32FC2);
1230 cv::Mat groundMat = cv::Mat(1, (
int)
octree_->
size(), CV_32FC2);
1233 cv::Vec2f * oPtr = obstaclesMat.ptr<cv::Vec2f>(0,0);
1234 cv::Vec2f * gPtr = groundMat.ptr<cv::Vec2f>(0,0);
1239 if(
octree_->isNodeOccupied(*it) &&
1243 oPtr[oi][0] = pt.
x()-halfCellSize;
1244 oPtr[oi][1] = pt.
y()-halfCellSize;
1250 gPtr[gi][0] = pt.
x()-halfCellSize;
1251 gPtr[gi][1] = pt.
y()-halfCellSize;
1258 std::map<int, Transform> poses;
1260 std::map<int, std::pair<cv::Mat, cv::Mat> > maps;
1261 maps.insert(std::make_pair(1, std::make_pair(groundMat, obstaclesMat)));
1276 return octree_->writeBinary(path);
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
const iterator end() 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)
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, std::vector< int > *frontierIndices=0, std::vector< double > *cloudProb=0) const
int getOccupancyType() 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)
static bool isNodeVisited(std::unordered_set< octomap::OcTreeKey, octomap::OcTreeKey::KeyHash > const &EmptyNodes, octomap::OcTreeKey const key)
void updateMinMax(const octomap::point3d &point)
const unsigned int tree_depth
double getOccupancy() const
virtual NODE * updateNode(const OcTreeKey &key, float log_odds_update, bool lazy_eval=false)
static StaticMemberInitializer RtabmapColorOcTreeMemberInit
static member to ensure static initialization (only once)
std::map< int, Transform > addedNodes_
double keyToCoord(key_type key, unsigned depth) const
void updateColorChildren()
void deleteNodeChild(RtabmapColorOcTreeNode *node, unsigned int childIdx)
bool createChild(unsigned int i)
bool deleteNode(double x, double y, double z, unsigned int depth=0)
std::map< int, cv::Point3f > cacheViewPoints_
RtabmapColorOcTreeNode * getChild(unsigned int i)
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
RtabmapColorOcTreeNode * getNodeChild(RtabmapColorOcTreeNode *node, unsigned int childIdx) const
std::map< std::string, std::string > ParametersMap
pcl::PointXYZ RTABMAP_EXP laserScanToPoint(const LaserScan &laserScan, int index)
static octomap::point3d findCloseEmpty(RtabmapColorOcTree *octree_, unsigned int treeDepth, octomap::point3d startPosition)
static bool isValidEmpty(RtabmapColorOcTree *octree_, unsigned int treeDepth, octomap::point3d startPosition)
void updateOccupancyChildren()
key_type coordToKey(double coordinate) const
void setPointRef(const octomap::point3d &point)
pcl::PointXYZRGB RTABMAP_EXP laserScanToPointRGB(const LaserScan &laserScan, int index, unsigned char r=100, unsigned char g=100, unsigned char b=100)
void setNodeRefId(int nodeRefId)
leaf_iterator begin_leafs(unsigned char maxDepth=0) const
#define UASSERT(condition)
bool update(const std::map< int, Transform > &poses)
Wrappers of STL for convenient functions.
void addToCache(int nodeId, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &ground, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &obstacles, const pcl::PointXYZ &viewPoint)
std::map< int, std::pair< std::pair< cv::Mat, cv::Mat >, cv::Mat > > cache_
RtabmapColorOcTreeNode * search(double x, double y, double z, unsigned int depth=0) const
RtabmapColorOcTreeNode * integrateNodeColor(const octomap::OcTreeKey &key, uint8_t r, uint8_t g, uint8_t b)
std::map< int, std::pair< const pcl::PointCloud< pcl::PointXYZRGB >::Ptr, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr > > cacheClouds_
AbstractOcTreeNode ** children
#define UASSERT_MSG(condition, msg_str)
iterator begin(unsigned char maxDepth=0) const
bool coordToKeyChecked(const point3d &coord, OcTreeKey &key) const
OctoMap(const ParametersMap ¶meters=ParametersMap())
void updateInnerOccupancy()
RtabmapColorOcTree * octree_
double getResolution() const
ColorOcTreeNode::Color getAverageChildColor() const
double getNodeSize(unsigned depth) const
unordered_ns::unordered_set< OcTreeKey, OcTreeKey::KeyHash > KeySet
virtual bool isNodeCollapsible(const RtabmapColorOcTreeNode *node) const
RtabmapColorOcTree(double resolution)
Default constructor, sets resolution of leafs.
unsigned int emptyFloodFillDepth_
const octomap::point3d & getPointRef() const
void setOccupancyType(char type)
void updateInnerOccupancyRecurs(RtabmapColorOcTreeNode *node, unsigned int depth)
const leaf_iterator end_leafs() const
bool writeBinary(const std::string &path)
octomath::Vector3 point3d
RtabmapColorOcTreeNode * root
StaticMemberInitializer()
ULogger class and convenient macros.
virtual size_t size() const
RtabmapColorOcTreeNode * setNodeColor(const octomap::OcTreeKey &key, uint8_t r, uint8_t g, uint8_t b)
cv::Mat createProjectionMap(float &xMin, float &yMin, float &gridCellSize, float minGridSize=0.0f, unsigned int treeDepth=0)
void updateOccupancyTypeChildren()
void RTABMAP_EXP HSVtoRGB(float *r, float *g, float *b, float h, float s, float v)
std::string UTILITE_EXP uFormat(const char *fmt,...)
virtual bool pruneNode(RtabmapColorOcTreeNode *node)
static LaserScan backwardCompatibility(const cv::Mat &oldScanFormat, int maxPoints=0, int maxRange=0, const Transform &localTransform=Transform::getIdentity())
bool nodeChildExists(const RtabmapColorOcTreeNode *node, unsigned int childIdx) const
bool nodeHasChildren(const RtabmapColorOcTreeNode *node) const
void copyData(const ColorOcTreeNode &from)
unsigned int getTreeDepth() const
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
static void floodFill(RtabmapColorOcTree *octree_, unsigned int treeDepth, octomap::point3d startPosition, std::unordered_set< octomap::OcTreeKey, octomap::OcTreeKey::KeyHash > &EmptyNodes, std::queue< octomap::point3d > &positionToExplore)
bool computeRayKeys(const point3d &origin, const point3d &end, KeyRay &ray) const
static std::unordered_set< octomap::OcTreeKey, octomap::OcTreeKey::KeyHash > findEmptyNode(RtabmapColorOcTree *octree_, unsigned int treeDepth, octomap::point3d startPosition)