36 #include <pcl/common/transforms.h> 48 UFATAL(
"This function should not be used with octomap >= 1.8");
56 UFATAL(
"This function should not be used with octomap >= 1.8");
71 for (
unsigned int i=0;i<8;i++) {
78 UFATAL(
"This function should not be used with octomap >= 1.8");
86 for (
unsigned int k=0; k<8; k++) {
92 UFATAL(
"This function should not be used with octomap >= 1.8");
103 UFATAL(
"This function should not be used with octomap >= 1.8");
125 #ifndef OCTOMAP_PRE_18 130 node->copyData(*(getNodeChild(node, 0)));
136 for (
unsigned int i=0;i<8;i++) {
137 deleteNodeChild(node, i);
144 UFATAL(
"This function should not be used with octomap < 1.8");
150 #ifndef OCTOMAP_PRE_18 153 if (!nodeChildExists(node, 0))
157 if (nodeHasChildren(firstChild))
160 for (
unsigned int i = 1; i<8; i++) {
162 if (!nodeChildExists(node, i) || nodeHasChildren(getNodeChild(node, i)) || !(getNodeChild(node, i)->getValue() == firstChild->
getValue()))
168 UFATAL(
"This function should not be used with octomap < 1.8");
180 RtabmapColorOcTreeNode::Color prev_color = n->
getColor();
181 n->
setColor((prev_color.r + r)/2, (prev_color.g + g)/2, (prev_color.b + b)/2);
197 RtabmapColorOcTreeNode::Color prev_color = n->
getColor();
200 + (double) r * (0.99-node_prob));
202 + (double) g * (0.99-node_prob));
204 + (double) b * (0.99-node_prob));
220 #ifndef OCTOMAP_PRE_18 222 if (nodeHasChildren(node)){
225 for (
unsigned int i=0; i<8; i++) {
226 if (nodeChildExists(node, i)) {
239 for (
unsigned int i=0; i<8; i++) {
254 #ifndef OCTOMAP_PRE_18 255 tree->clearKeyRays();
258 AbstractOcTree::registerTreeType(tree);
273 fullUpdate_(
Parameters::defaultGridGlobalFullUpdate()),
274 updateError_(
Parameters::defaultGridGlobalUpdateError()),
276 rayTracing_(
Parameters::defaultGridRayTracing())
278 float cellSize = Parameters::defaultGridCellSize();
285 float occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
286 float probHit = Parameters::defaultGridGlobalProbHit();
287 float probMiss = Parameters::defaultGridGlobalProbMiss();
288 float clampingMin = Parameters::defaultGridGlobalProbClampingMin();
289 float clampingMax = Parameters::defaultGridGlobalProbClampingMax();
290 Parameters::parse(parameters, Parameters::kGridGlobalOccupancyThr(), occupancyThr);
293 Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMin(), clampingMin);
294 Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMax(), clampingMax);
297 if(occupancyThr <= 0.0
f)
299 UWARN(
"Cannot set %s to null for OctoMap, using default value %f instead.",
300 Parameters::kGridGlobalOccupancyThr().c_str(),
301 Parameters::defaultGridGlobalOccupancyThr());
302 occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
304 octree_->setOccupancyThres(occupancyThr);
306 octree_->setProbMiss(probMiss);
307 octree_->setClampingThresMin(clampingMin);
308 octree_->setClampingThresMax(clampingMax);
326 octree_->setOccupancyThres(occupancyThr);
349 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & ground,
350 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & obstacles,
351 const pcl::PointXYZ & viewPoint)
353 UDEBUG(
"nodeId=%d", nodeId);
356 UWARN(
"Cannot add nodes with negative id (nodeId=%d)", nodeId);
360 cacheClouds_.insert(std::make_pair(nodeId==0?-1:nodeId, std::make_pair(ground, obstacles)));
361 uInsert(
cacheViewPoints_, std::make_pair(nodeId==0?-1:nodeId, cv::Point3f(viewPoint.x, viewPoint.y, viewPoint.z)));
364 const cv::Mat & ground,
365 const cv::Mat & obstacles,
366 const cv::Mat & empty,
367 const cv::Point3f & viewPoint)
369 UDEBUG(
"nodeId=%d", nodeId);
372 UWARN(
"Cannot add nodes with negative id (nodeId=%d)", nodeId);
375 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());
376 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());
377 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());
378 uInsert(
cache_, std::make_pair(nodeId==0?-1:nodeId, std::make_pair(std::make_pair(ground, obstacles), empty)));
384 UDEBUG(
"Update (poses=%d addedNodes_=%d)", (
int)poses.size(), (int)
addedNodes_.size());
387 bool graphOptimized =
false;
389 std::map<int, Transform> transforms;
390 std::map<int, Transform> updatedAddedNodes;
394 std::map<int, Transform>::const_iterator jter = poses.find(iter->first);
395 if(jter != poses.end())
397 graphChanged =
false;
398 UASSERT(!iter->second.isNull() && !jter->second.isNull());
400 if(iter->second.getDistanceSquared(jter->second) > updateErrorSqrd)
402 t = jter->second * iter->second.inverse();
403 graphOptimized =
true;
405 transforms.insert(std::make_pair(jter->first, t));
406 updatedAddedNodes.insert(std::make_pair(jter->first, jter->second));
410 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);
414 if(graphOptimized || graphChanged)
418 UWARN(
"Graph has changed! The whole map should be rebuilt.");
422 UINFO(
"Graph optimized!");
446 std::map<int, Transform>::iterator jter = transforms.find(nOld.
getNodeRefId());
447 if(jter != transforms.end())
462 cv::Point3f cvPt(pt.
x(), pt.
y(), pt.
z());
499 UERROR(
"Could not update node at (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
504 UERROR(
"Could not find key for (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
507 else if(jter == transforms.end())
514 UINFO(
"Graph optimization detected, moved %d/%d in %fs", copied, count, t.
ticks());
526 std::list<std::pair<int, Transform> > orderedPoses;
529 UDEBUG(
"Last id = %d", lastId);
532 for(std::map<int, Transform>::const_iterator iter=poses.lower_bound(1); iter!=poses.end(); ++iter)
536 orderedPoses.push_back(*iter);
541 if(poses.find(0) != poses.end())
543 orderedPoses.push_back(std::make_pair(-1, poses.at(0)));
546 UDEBUG(
"orderedPoses = %d", (
int)orderedPoses.size());
548 if(!orderedPoses.empty())
552 for(std::list<std::pair<int, Transform> >::const_iterator iter=orderedPoses.begin(); iter!=orderedPoses.end(); ++iter)
554 std::map<int, std::pair<const pcl::PointCloud<pcl::PointXYZRGB>::Ptr,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr> >::iterator cloudIter;
555 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator occupancyIter;
556 std::map<int, cv::Point3f>::iterator viewPointIter;
558 occupancyIter =
cache_.find(iter->first);
565 octomap::point3d sensorOrigin(iter->second.x(), iter->second.y(), iter->second.z());
566 sensorOrigin +=
octomap::point3d(viewPointIter->second.x, viewPointIter->second.y, viewPointIter->second.z);
574 UERROR(
"Could not generate Key for origin ", sensorOrigin.x(), sensorOrigin.y(), sensorOrigin.z());
577 bool computeRays =
rayTracing_ && (occupancyIter ==
cache_.end() || occupancyIter->second.second.empty());
582 unsigned int maxGroundPts = occupancyIter !=
cache_.end()?occupancyIter->second.first.first.cols:cloudIter->second.first->size();
583 UDEBUG(
"%d: compute free cells (from %d ground points)", iter->first, (
int)maxGroundPts);
584 Eigen::Affine3f t = iter->second.toEigen3f();
586 if(occupancyIter !=
cache_.end())
591 for (
unsigned int i=0; i<maxGroundPts; ++i)
594 if(occupancyIter !=
cache_.end())
604 bool ignoreOccupiedCell =
false;
605 if(rangeMaxSqrd > 0.0
f)
607 octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
608 if(v.norm_sq() > rangeMaxSqrd)
613 point = sensorOrigin + v;
614 ignoreOccupiedCell=
true;
618 if(!ignoreOccupiedCell)
624 if(iter->first >0 && iter->first<lastId)
639 if(!
hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
657 (iter->first < 0 || iter->first>lastId) &&
660 free_cells.insert(keyRay.
begin(), keyRay.
end());
663 UDEBUG(
"%d: ground cells=%d free cells=%d", iter->first, (
int)maxGroundPts, (
int)free_cells.size());
666 unsigned int maxObstaclePts = occupancyIter !=
cache_.end()?occupancyIter->second.first.second.cols:cloudIter->second.second->size();
667 UDEBUG(
"%d: compute occupied cells (from %d obstacle points)", iter->first, (
int)maxObstaclePts);
669 if(occupancyIter !=
cache_.end())
672 UASSERT(tmpObstacle.
size() == (int)maxObstaclePts);
674 for (
unsigned int i=0; i<maxObstaclePts; ++i)
677 if(occupancyIter !=
cache_.end())
689 bool ignoreOccupiedCell =
false;
690 if(rangeMaxSqrd > 0.0
f)
692 octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
693 if(v.norm_sq() > rangeMaxSqrd)
698 point = sensorOrigin + v;
699 ignoreOccupiedCell=
true;
703 if(!ignoreOccupiedCell)
709 if(iter->first >0 && iter->first<lastId)
724 if(!
hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
742 (iter->first < 0 || iter->first>lastId) &&
745 free_cells.insert(keyRay.
begin(), keyRay.
end());
748 UDEBUG(
"%d: occupied cells=%d free cells=%d", iter->first, (
int)maxObstaclePts, (
int)free_cells.size());
752 for(octomap::KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ++it)
776 if(occupancyIter !=
cache_.end() && occupancyIter->second.second.cols)
778 unsigned int maxEmptyPts = occupancyIter->second.second.cols;
779 UDEBUG(
"%d: compute free cells (from %d empty points)", iter->first, (
int)maxEmptyPts);
782 for (
unsigned int i=0; i<maxEmptyPts; ++i)
790 bool ignoreCell =
false;
791 if(rangeMaxSqrd > 0.0
f)
793 octomap::point3d v(pt.x - sensorOrigin.x(), pt.y - sensorOrigin.y(), pt.z - sensorOrigin.z());
794 if(v.norm_sq() > rangeMaxSqrd)
844 UDEBUG(
"%d: end", iter->first);
848 UDEBUG(
"Did not find %d in cache", iter->first);
859 return !orderedPoses.empty() || graphOptimized || graphChanged;
891 unsigned int treeDepth,
892 std::vector<int> * obstacleIndices,
893 std::vector<int> * emptyIndices,
894 std::vector<int> * groundIndices,
895 bool originalRefPoints,
896 std::vector<int> * frontierIndices,
897 std::vector<double> * cloudProb)
const 899 UASSERT(treeDepth <= octree_->getTreeDepth());
900 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
905 UDEBUG(
"depth=%d (maxDepth=%d) octree = %d",
933 bool addAllPoints = obstacleIndices == 0 && groundIndices == 0 && emptyIndices == 0;
942 if(
octree_->isNodeOccupied(*it) && (obstacleIndices != 0 || groundIndices != 0 || addAllPoints))
947 (*cloudProb)[oi] = it->getOccupancy();
951 (*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
956 float H = (maxZ - pt.
z())*299.0
f/(maxZ-minZ);
959 (*cloud)[oi].r = r*255.0f;
960 (*cloud)[oi].g = g*255.0f;
961 (*cloud)[oi].b = b*255.0f;
964 if(originalRefPoints && it->getOccupancyType() > 0)
967 (*cloud)[oi].
x = p.
x();
968 (*cloud)[oi].y = p.
y();
969 (*cloud)[oi].z = p.
z();
973 (*cloud)[oi].x = pt.
x()-halfCellSize;
974 (*cloud)[oi].y = pt.
y()-halfCellSize;
975 (*cloud)[oi].z = pt.
z();
982 groundIndices->at(gi++) = oi;
985 else if(obstacleIndices)
987 obstacleIndices->at(si++) = oi;
992 else if(!
octree_->isNodeOccupied(*it) && (emptyIndices != 0 || addAllPoints || frontierIndices !=0))
997 (*cloudProb)[oi] = it->getOccupancy();
1000 if(frontierIndices !=0 &&
1006 frontierIndices->at(fi++) = oi;
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();
1016 emptyIndices->at(ei++) = oi;
1026 cloudProb->resize(oi);
1030 obstacleIndices->resize(si);
1031 UDEBUG(
"obstacle=%d", si);
1035 emptyIndices->resize(ei);
1040 frontierIndices->resize(fi);
1041 UDEBUG(
"frontier=%d", fi);
1045 groundIndices->resize(gi);
1055 UDEBUG(
"minGridSize=%f, treeDepth=%d", minGridSize, (
int)treeDepth);
1056 UASSERT(treeDepth <= octree_->getTreeDepth());
1064 cv::Mat obstaclesMat = cv::Mat(1, (
int)
octree_->
size(), CV_32FC2);
1065 cv::Mat groundMat = cv::Mat(1, (
int)
octree_->
size(), CV_32FC2);
1068 cv::Vec2f * oPtr = obstaclesMat.ptr<cv::Vec2f>(0,0);
1069 cv::Vec2f * gPtr = groundMat.ptr<cv::Vec2f>(0,0);
1076 oPtr[oi][0] = pt.
x();
1077 oPtr[oi][1] = pt.
y();
1083 gPtr[gi][0] = pt.
x();
1084 gPtr[gi][1] = pt.
y();
1091 std::map<int, Transform> poses;
1093 std::map<int, std::pair<cv::Mat, cv::Mat> > maps;
1094 maps.insert(std::make_pair(1, std::make_pair(groundMat, obstaclesMat)));
1109 return octree_->writeBinary(path);
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
iterator begin(unsigned char maxDepth=0) const
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)
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)
void updateMinMax(const octomap::point3d &point)
const unsigned int tree_depth
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_
void updateColorChildren()
const iterator end() const
bool createChild(unsigned int i)
std::map< int, cv::Point3f > cacheViewPoints_
RtabmapColorOcTreeNode * getChild(unsigned int i)
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
std::map< std::string, std::string > ParametersMap
RtabmapColorOcTreeNode * search(double x, double y, double z, unsigned int depth=0) const
pcl::PointXYZ RTABMAP_EXP laserScanToPoint(const LaserScan &laserScan, int index)
unsigned int getTreeDepth() const
void updateOccupancyChildren()
virtual bool isNodeCollapsible(const RtabmapColorOcTreeNode *node) const
bool childExists(unsigned int i) const
bool coordToKeyChecked(const point3d &coord, OcTreeKey &key) 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)
double keyToCoord(unsigned short int key, unsigned depth) const
#define UASSERT(condition)
bool update(const std::map< int, Transform > &poses)
Wrappers of STL for convenient functions.
bool computeRayKeys(const point3d &origin, const point3d &end, KeyRay &ray) const
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_
const octomap::point3d & getPointRef() const
RtabmapColorOcTreeNode * integrateNodeColor(const octomap::OcTreeKey &key, uint8_t r, uint8_t g, uint8_t b)
int getOccupancyType() const
OcTreeDataNode< float > ** children
std::map< int, std::pair< const pcl::PointCloud< pcl::PointXYZRGB >::Ptr, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr > > cacheClouds_
#define UASSERT_MSG(condition, msg_str)
void updateInnerOccupancy()
RtabmapColorOcTree * octree_
unordered_ns::unordered_set< OcTreeKey, OcTreeKey::KeyHash > KeySet
RtabmapColorOcTree(double resolution)
Default constructor, sets resolution of leafs.
double getOccupancy() const
void setOccupancyType(char type)
void updateInnerOccupancyRecurs(RtabmapColorOcTreeNode *node, unsigned int depth)
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
double getResolution() const
bool writeBinary(const std::string &path)
octomath::Vector3 point3d
RtabmapColorOcTreeNode * root
StaticMemberInitializer()
ULogger class and convenient macros.
OctoMap(const ParametersMap ¶meters)
double getNodeSize(unsigned depth) 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 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())
virtual size_t size() const
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)