OctoMap.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 */
00027 
00028 #include <rtabmap/core/OctoMap.h>
00029 #include <rtabmap/utilite/ULogger.h>
00030 #include <rtabmap/utilite/UStl.h>
00031 #include <rtabmap/utilite/UTimer.h>
00032 #include <rtabmap/core/util3d_transforms.h>
00033 #include <rtabmap/core/util3d_filtering.h>
00034 #include <rtabmap/core/util3d_mapping.h>
00035 #include <pcl/common/transforms.h>
00036 
00037 namespace rtabmap {
00038 
00040 // RtabmapColorOcTree
00042 
00043 RtabmapColorOcTreeNode* RtabmapColorOcTreeNode::getChild(unsigned int i) {
00044 #ifdef OCTOMAP_PRE_18
00045   return static_cast<RtabmapColorOcTreeNode*> (OcTreeNode::getChild(i));
00046 #else
00047         UFATAL("This function should not be used with octomap >= 1.8");
00048         return 0;
00049 #endif
00050 }
00051 const RtabmapColorOcTreeNode* RtabmapColorOcTreeNode::getChild(unsigned int i) const {
00052 #ifdef OCTOMAP_PRE_18
00053   return static_cast<const RtabmapColorOcTreeNode*> (OcTreeNode::getChild(i));
00054 #else
00055         UFATAL("This function should not be used with octomap >= 1.8");
00056         return 0;
00057 #endif
00058 }
00059 
00060 //octomap <1.8
00061 bool RtabmapColorOcTreeNode::pruneNode() {
00062 #ifdef OCTOMAP_PRE_18
00063         // checks for equal occupancy only, color ignored
00064         if (!this->collapsible()) return false;
00065         // set occupancy value
00066         setLogOdds(getChild(0)->getLogOdds());
00067         // set color to average color
00068         if (isColorSet()) color = getAverageChildColor();
00069         // delete children
00070         for (unsigned int i=0;i<8;i++) {
00071                 delete children[i];
00072         }
00073         delete[] children;
00074         children = NULL;
00075         return true;
00076 #else
00077         UFATAL("This function should not be used with octomap >= 1.8");
00078         return false;
00079 #endif
00080 }
00081 //octomap <1.8
00082 void RtabmapColorOcTreeNode::expandNode() {
00083 #ifdef OCTOMAP_PRE_18
00084         assert(!hasChildren());
00085         for (unsigned int k=0; k<8; k++) {
00086                 createChild(k);
00087                 children[k]->setValue(value);
00088                 getChild(k)->setColor(color);
00089         }
00090 #else
00091         UFATAL("This function should not be used with octomap >= 1.8");
00092 #endif
00093 }
00094 
00095 //octomap <1.8
00096 bool RtabmapColorOcTreeNode::createChild(unsigned int i) {
00097 #ifdef OCTOMAP_PRE_18
00098   if (children == NULL) allocChildren();
00099   children[i] = new RtabmapColorOcTreeNode();
00100   return true;
00101 #else
00102         UFATAL("This function should not be used with octomap >= 1.8");
00103         return false;
00104 #endif
00105 }
00106 
00107 RtabmapColorOcTree::RtabmapColorOcTree(double resolution)
00108         : OccupancyOcTreeBase<RtabmapColorOcTreeNode>(resolution) {
00109         RtabmapColorOcTreeMemberInit.ensureLinking();
00110 };
00111 
00112 RtabmapColorOcTreeNode* RtabmapColorOcTree::setNodeColor(const octomap::OcTreeKey& key,
00113                 uint8_t r,
00114                 uint8_t g,
00115                 uint8_t b) {
00116         RtabmapColorOcTreeNode* n = search (key);
00117         if (n != 0) {
00118                 n->setColor(r, g, b);
00119         }
00120         return n;
00121 }
00122 
00123 bool RtabmapColorOcTree::pruneNode(RtabmapColorOcTreeNode* node) {
00124 #ifndef OCTOMAP_PRE_18
00125         if (!isNodeCollapsible(node))
00126                 return false;
00127 
00128         // set value to children's values (all assumed equal)
00129         node->copyData(*(getNodeChild(node, 0)));
00130 
00131         if (node->isColorSet()) // TODO check
00132                 node->setColor(node->getAverageChildColor());
00133 
00134         // delete children
00135         for (unsigned int i=0;i<8;i++) {
00136                 deleteNodeChild(node, i);
00137         }
00138         delete[] node->children;
00139         node->children = NULL;
00140 
00141         return true;
00142 #else
00143         UFATAL("This function should not be used with octomap < 1.8");
00144         return false;
00145 #endif
00146 }
00147 
00148 bool RtabmapColorOcTree::isNodeCollapsible(const RtabmapColorOcTreeNode* node) const{
00149 #ifndef OCTOMAP_PRE_18
00150         // all children must exist, must not have children of
00151         // their own and have the same occupancy probability
00152         if (!nodeChildExists(node, 0))
00153                 return false;
00154 
00155         const RtabmapColorOcTreeNode* firstChild = getNodeChild(node, 0);
00156         if (nodeHasChildren(firstChild))
00157                 return false;
00158 
00159         for (unsigned int i = 1; i<8; i++) {
00160                 // compare nodes only using their occupancy, ignoring color for pruning
00161                 if (!nodeChildExists(node, i) || nodeHasChildren(getNodeChild(node, i)) || !(getNodeChild(node, i)->getValue() == firstChild->getValue()))
00162                         return false;
00163         }
00164 
00165         return true;
00166 #else
00167         UFATAL("This function should not be used with octomap < 1.8");
00168         return false;
00169 #endif
00170 }
00171 
00172 RtabmapColorOcTreeNode* RtabmapColorOcTree::averageNodeColor(const octomap::OcTreeKey& key,
00173                 uint8_t r,
00174                 uint8_t g,
00175                 uint8_t b) {
00176         RtabmapColorOcTreeNode* n = search(key);
00177         if (n != 0) {
00178                 if (n->isColorSet()) {
00179                         RtabmapColorOcTreeNode::Color prev_color = n->getColor();
00180                         n->setColor((prev_color.r + r)/2, (prev_color.g + g)/2, (prev_color.b + b)/2);
00181                 }
00182                 else {
00183                         n->setColor(r, g, b);
00184                 }
00185         }
00186         return n;
00187 }
00188 
00189 RtabmapColorOcTreeNode* RtabmapColorOcTree::integrateNodeColor(const octomap::OcTreeKey& key,
00190                 uint8_t r,
00191                 uint8_t g,
00192                 uint8_t b) {
00193         RtabmapColorOcTreeNode* n = search (key);
00194         if (n != 0) {
00195                 if (n->isColorSet()) {
00196                         RtabmapColorOcTreeNode::Color prev_color = n->getColor();
00197                         double node_prob = n->getOccupancy();
00198                         uint8_t new_r = (uint8_t) ((double) prev_color.r * node_prob
00199                                         +  (double) r * (0.99-node_prob));
00200                         uint8_t new_g = (uint8_t) ((double) prev_color.g * node_prob
00201                                         +  (double) g * (0.99-node_prob));
00202                         uint8_t new_b = (uint8_t) ((double) prev_color.b * node_prob
00203                                         +  (double) b * (0.99-node_prob));
00204                         n->setColor(new_r, new_g, new_b);
00205                 }
00206                 else {
00207                         n->setColor(r, g, b);
00208                 }
00209         }
00210         return n;
00211 }
00212 
00213 
00214 void RtabmapColorOcTree::updateInnerOccupancy() {
00215         this->updateInnerOccupancyRecurs(this->root, 0);
00216 }
00217 
00218 void RtabmapColorOcTree::updateInnerOccupancyRecurs(RtabmapColorOcTreeNode* node, unsigned int depth) {
00219 #ifndef OCTOMAP_PRE_18
00220         // only recurse and update for inner nodes:
00221         if (nodeHasChildren(node)){
00222                 // return early for last level:
00223                 if (depth < this->tree_depth){
00224                         for (unsigned int i=0; i<8; i++) {
00225                                 if (nodeChildExists(node, i)) {
00226                                         updateInnerOccupancyRecurs(getNodeChild(node, i), depth+1);
00227                                 }
00228                         }
00229                 }
00230                 node->updateOccupancyChildren();
00231                 node->updateColorChildren();
00232         }
00233 #else
00234         // only recurse and update for inner nodes:
00235         if (node->hasChildren()){
00236           // return early for last level:
00237           if (depth < this->tree_depth){
00238                 for (unsigned int i=0; i<8; i++) {
00239                   if (node->childExists(i)) {
00240                         updateInnerOccupancyRecurs(node->getChild(i), depth+1);
00241                   }
00242                 }
00243           }
00244           node->updateOccupancyChildren();
00245           node->updateColorChildren();
00246         }
00247 #endif
00248 }
00249 
00250 RtabmapColorOcTree::StaticMemberInitializer::StaticMemberInitializer() {
00251          RtabmapColorOcTree* tree = new RtabmapColorOcTree(0.1);
00252 
00253 #ifndef OCTOMAP_PRE_18
00254      tree->clearKeyRays();
00255 #endif
00256 
00257          AbstractOcTree::registerTreeType(tree);
00258  }
00259 
00260 
00262 // OctoMap
00264 
00265 OctoMap::OctoMap(const ParametersMap & parameters) :
00266                 hasColor_(false),
00267                 fullUpdate_(Parameters::defaultGridGlobalFullUpdate()),
00268                 updateError_(Parameters::defaultGridGlobalUpdateError()),
00269                 rangeMax_(Parameters::defaultGridRangeMax()),
00270                 rayTracing_(Parameters::defaultGridRayTracing())
00271 {
00272         float cellSize = Parameters::defaultGridCellSize();
00273         Parameters::parse(parameters, Parameters::kGridCellSize(), cellSize);
00274         UASSERT(cellSize>0.0f);
00275 
00276         minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
00277         maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
00278 
00279         float occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
00280         float probHit = Parameters::defaultGridGlobalProbHit();
00281         float probMiss = Parameters::defaultGridGlobalProbMiss();
00282         float clampingMin = Parameters::defaultGridGlobalProbClampingMin();
00283         float clampingMax = Parameters::defaultGridGlobalProbClampingMax();
00284         Parameters::parse(parameters, Parameters::kGridGlobalOccupancyThr(), occupancyThr);
00285         Parameters::parse(parameters, Parameters::kGridGlobalProbHit(), probHit);
00286         Parameters::parse(parameters, Parameters::kGridGlobalProbMiss(), probMiss);
00287         Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMin(), clampingMin);
00288         Parameters::parse(parameters, Parameters::kGridGlobalProbClampingMax(), clampingMax);
00289 
00290         octree_ = new RtabmapColorOcTree(cellSize);
00291         if(occupancyThr <= 0.0f)
00292         {
00293                 UWARN("Cannot set %s to null for OctoMap, using default value %f instead.",
00294                                 Parameters::kGridGlobalOccupancyThr().c_str(),
00295                                 Parameters::defaultGridGlobalOccupancyThr());
00296                 occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
00297         }
00298         octree_->setOccupancyThres(occupancyThr);
00299         octree_->setProbHit(probHit);
00300         octree_->setProbMiss(probMiss);
00301         octree_->setClampingThresMin(clampingMin);
00302         octree_->setClampingThresMax(clampingMax);
00303         Parameters::parse(parameters, Parameters::kGridGlobalFullUpdate(), fullUpdate_);
00304         Parameters::parse(parameters, Parameters::kGridGlobalUpdateError(), updateError_);
00305         Parameters::parse(parameters, Parameters::kGridRangeMax(), rangeMax_);
00306         Parameters::parse(parameters, Parameters::kGridRayTracing(), rayTracing_);
00307 }
00308 
00309 OctoMap::OctoMap(float cellSize, float occupancyThr, bool fullUpdate, float updateError) :
00310                 octree_(new RtabmapColorOcTree(cellSize)),
00311                 hasColor_(false),
00312                 fullUpdate_(fullUpdate),
00313                 updateError_(updateError),
00314                 rangeMax_(0.0f),
00315                 rayTracing_(true)
00316 {
00317         minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
00318         maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
00319 
00320         octree_->setOccupancyThres(occupancyThr);
00321         UASSERT(cellSize>0.0f);
00322 }
00323 
00324 OctoMap::~OctoMap()
00325 {
00326         this->clear();
00327         delete octree_;
00328 }
00329 
00330 void OctoMap::clear()
00331 {
00332         octree_->clear();
00333         cache_.clear();
00334         cacheClouds_.clear();
00335         cacheViewPoints_.clear();
00336         addedNodes_.clear();
00337         keyRay_ = octomap::KeyRay();
00338         hasColor_ = false;
00339         minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
00340         maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
00341 }
00342 
00343 void OctoMap::addToCache(int nodeId,
00344                 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & ground,
00345                 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & obstacles,
00346                 const pcl::PointXYZ & viewPoint)
00347 {
00348         UDEBUG("nodeId=%d", nodeId);
00349         cacheClouds_.erase(nodeId);
00350         cacheClouds_.insert(std::make_pair(nodeId, std::make_pair(ground, obstacles)));
00351         uInsert(cacheViewPoints_, std::make_pair(nodeId, cv::Point3f(viewPoint.x, viewPoint.y, viewPoint.z)));
00352 }
00353 void OctoMap::addToCache(int nodeId,
00354                 const cv::Mat & ground,
00355                 const cv::Mat & obstacles,
00356                 const cv::Mat & empty,
00357                 const cv::Point3f & viewPoint)
00358 {
00359         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());
00360         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());
00361         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());
00362         UDEBUG("nodeId=%d", nodeId);
00363         uInsert(cache_, std::make_pair(nodeId, std::make_pair(std::make_pair(ground, obstacles), empty)));
00364         uInsert(cacheViewPoints_, std::make_pair(nodeId, viewPoint));
00365 }
00366 
00367 void OctoMap::update(const std::map<int, Transform> & poses)
00368 {
00369         UDEBUG("Update (poses=%d addedNodes_=%d)", (int)poses.size(), (int)addedNodes_.size());
00370 
00371         // First, check of the graph has changed. If so, re-create the octree by moving all occupied nodes.
00372         bool graphOptimized = false; // If a loop closure happened (e.g., poses are modified)
00373         bool graphChanged = addedNodes_.size()>0; // If the new map doesn't have any node from the previous map
00374         std::map<int, Transform> transforms;
00375         std::map<int, Transform> updatedAddedNodes;
00376         float updateErrorSqrd = updateError_*updateError_;
00377         for(std::map<int, Transform>::iterator iter=addedNodes_.begin(); iter!=addedNodes_.end(); ++iter)
00378         {
00379                 std::map<int, Transform>::const_iterator jter = poses.find(iter->first);
00380                 if(jter != poses.end())
00381                 {
00382                         graphChanged = false;
00383                         UASSERT(!iter->second.isNull() && !jter->second.isNull());
00384                         Transform t = Transform::getIdentity();
00385                         if(iter->second.getDistanceSquared(jter->second) > updateErrorSqrd)
00386                         {
00387                                 t = jter->second * iter->second.inverse();
00388                                 graphOptimized = true;
00389                         }
00390                         transforms.insert(std::make_pair(jter->first, t));
00391                         updatedAddedNodes.insert(std::make_pair(jter->first, jter->second));
00392                 }
00393                 else
00394                 {
00395                         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);
00396                 }
00397         }
00398         if(graphOptimized || graphChanged)
00399         {
00400                 if(graphChanged)
00401                 {
00402                         UWARN("Graph has changed! The whole map should be rebuilt.");
00403                 }
00404                 else
00405                 {
00406                         UINFO("Graph optimized!");
00407                 }
00408 
00409                 minValues_[0] = minValues_[1] = minValues_[2] = 0.0;
00410                 maxValues_[0] = maxValues_[1] = maxValues_[2] = 0.0;
00411 
00412                 if(fullUpdate_ || graphChanged)
00413                 {
00414                         // clear all but keep cache
00415                         octree_->clear();
00416                         addedNodes_.clear();
00417                         keyRay_ = octomap::KeyRay();
00418                         hasColor_ = false;
00419                 }
00420                 else
00421                 {
00422                         RtabmapColorOcTree * newOcTree = new RtabmapColorOcTree(octree_->getResolution());
00423                         int copied=0;
00424                         int count=0;
00425                         UTimer t;
00426                         for (RtabmapColorOcTree::iterator it = octree_->begin(); it != octree_->end(); ++it, ++count)
00427                         {
00428                                 RtabmapColorOcTreeNode & nOld = *it;
00429                                 if(nOld.getNodeRefId() > 0)
00430                                 {
00431                                         std::map<int, Transform>::iterator jter = transforms.find(nOld.getNodeRefId());
00432                                         if(jter != transforms.end())
00433                                         {
00434                                                 octomap::point3d pt;
00435                                                 std::map<int, Transform>::iterator pter = addedNodes_.find(nOld.getNodeRefId());
00436                                                 UASSERT(pter != addedNodes_.end());
00437 
00438                                                 if(nOld.getOccupancyType() > 0)
00439                                                 {
00440                                                         pt = nOld.getPointRef();
00441                                                 }
00442                                                 else
00443                                                 {
00444                                                         pt = octree_->keyToCoord(it.getKey());
00445                                                 }
00446 
00447                                                 cv::Point3f cvPt(pt.x(), pt.y(), pt.z());
00448                                                 cvPt = util3d::transformPoint(cvPt, jter->second);
00449                                                 octomap::point3d ptTransformed(cvPt.x, cvPt.y, cvPt.z);
00450 
00451                                                 octomap::OcTreeKey key;
00452                                                 if(newOcTree->coordToKeyChecked(ptTransformed, key))
00453                                                 {
00454                                                         RtabmapColorOcTreeNode * n = newOcTree->search(key);
00455                                                         if(n)
00456                                                         {
00457                                                                 if(n->getNodeRefId() > nOld.getNodeRefId())
00458                                                                 {
00459                                                                         // The cell has been updated from more recent node, don't update the cell
00460                                                                         continue;
00461                                                                 }
00462                                                                 else if(nOld.getOccupancyType() <= 0 && n->getOccupancyType() > 0)
00463                                                                 {
00464                                                                         // empty cells cannot overwrite ground/obstacle cells
00465                                                                         continue;
00466                                                                 }
00467                                                         }
00468 
00469                                                         RtabmapColorOcTreeNode * nNew = newOcTree->updateNode(key, nOld.getLogOdds());
00470                                                         if(nNew)
00471                                                         {
00472                                                                 ++copied;
00473                                                                 updateMinMax(ptTransformed);
00474                                                                 nNew->setNodeRefId(nOld.getNodeRefId());
00475                                                                 if(nOld.getOccupancyType() > 0)
00476                                                                 {
00477                                                                         nNew->setPointRef(pt);
00478                                                                 }
00479                                                                 nNew->setOccupancyType(nOld.getOccupancyType());
00480                                                                 nNew->setColor(nOld.getColor());
00481                                                         }
00482                                                         else
00483                                                         {
00484                                                                 UERROR("Could not update node at (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
00485                                                         }
00486                                                 }
00487                                                 else
00488                                                 {
00489                                                         UERROR("Could not find key for (%f,%f,%f)", cvPt.x, cvPt.y, cvPt.z);
00490                                                 }
00491                                         }
00492                                         else if(jter == transforms.end())
00493                                         {
00494                                                 // Note: normal if old nodes were transfered to LTM
00495                                                 //UWARN("Could not find a transform for point linked to node %d (transforms=%d)", iter->second.nodeRefId_, (int)transforms.size());
00496                                         }
00497                                 }
00498                         }
00499                         UINFO("Graph optimization detected, moved %d/%d in %fs", copied, count, t.ticks());
00500                         delete octree_;
00501                         octree_ = newOcTree;
00502 
00503                         //update added poses
00504                         addedNodes_ = updatedAddedNodes;
00505                 }
00506         }
00507 
00508         // Original version from A. Hornung:
00509         // https://github.com/OctoMap/octomap_mapping/blob/jade-devel/octomap_server/src/OctomapServer.cpp#L356
00510         //
00511         std::list<std::pair<int, Transform> > orderedPoses;
00512 
00513         int lastId = addedNodes_.size()?addedNodes_.rbegin()->first:0;
00514         UDEBUG("Last id = %d", lastId);
00515 
00516         // add old poses that were not in the current map (they were just retrieved from LTM)
00517         for(std::map<int, Transform>::const_iterator iter=poses.upper_bound(0); iter!=poses.end(); ++iter)
00518         {
00519                 if(addedNodes_.find(iter->first) == addedNodes_.end())
00520                 {
00521                         orderedPoses.push_back(*iter);
00522                 }
00523         }
00524 
00525         // insert negative after
00526         for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00527         {
00528                 if(iter->first < 0)
00529                 {
00530                         orderedPoses.push_back(*iter);
00531                 }
00532                 else
00533                 {
00534                         break;
00535                 }
00536         }
00537 
00538         UDEBUG("orderedPoses = %d", (int)orderedPoses.size());
00539         float rangeMaxSqrd = rangeMax_*rangeMax_;
00540         float cellSize = octree_->getResolution();
00541         for(std::list<std::pair<int, Transform> >::const_iterator iter=orderedPoses.begin(); iter!=orderedPoses.end(); ++iter)
00542         {
00543                 std::map<int, std::pair<const pcl::PointCloud<pcl::PointXYZRGB>::Ptr, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr> >::iterator cloudIter;
00544                 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator occupancyIter;
00545                 std::map<int, cv::Point3f>::iterator viewPointIter;
00546                 cloudIter = cacheClouds_.find(iter->first);
00547                 occupancyIter = cache_.find(iter->first);
00548                 viewPointIter = cacheViewPoints_.find(iter->first);
00549                 if(occupancyIter != cache_.end() || cloudIter != cacheClouds_.end())
00550                 {
00551                         UDEBUG("Adding %d to octomap (resolution=%f)", iter->first, octree_->getResolution());
00552 
00553                         UASSERT(viewPointIter != cacheViewPoints_.end());
00554                         octomap::point3d sensorOrigin(iter->second.x(), iter->second.y(), iter->second.z());
00555                         sensorOrigin += octomap::point3d(viewPointIter->second.x, viewPointIter->second.y, viewPointIter->second.z);
00556 
00557                         updateMinMax(sensorOrigin);
00558 
00559                         octomap::OcTreeKey tmpKey;
00560                         if (!octree_->coordToKeyChecked(sensorOrigin, tmpKey)
00561                                         || !octree_->coordToKeyChecked(sensorOrigin, tmpKey))
00562                         {
00563                                 UERROR("Could not generate Key for origin ", sensorOrigin.x(), sensorOrigin.y(), sensorOrigin.z());
00564                         }
00565 
00566                         bool computeRays = rayTracing_ && (occupancyIter == cache_.end() || occupancyIter->second.second.empty());
00567 
00568                         // instead of direct scan insertion, compute update to filter ground:
00569                         octomap::KeySet free_cells;
00570                         // insert ground points only as free:
00571                         unsigned int maxGroundPts = occupancyIter != cache_.end()?occupancyIter->second.first.first.cols:cloudIter->second.first->size();
00572                         UDEBUG("%d: compute free cells (from %d ground points)", iter->first, (int)maxGroundPts);
00573                         Eigen::Affine3f t = iter->second.toEigen3f();
00574                         LaserScan tmpGround;
00575                         if(occupancyIter != cache_.end())
00576                         {
00577                                 tmpGround = LaserScan::backwardCompatibility(occupancyIter->second.first.first);
00578                                 UASSERT(tmpGround.size() == (int)maxGroundPts);
00579                         }
00580                         for (unsigned int i=0; i<maxGroundPts; ++i)
00581                         {
00582                                 pcl::PointXYZRGB pt;
00583                                 if(occupancyIter != cache_.end())
00584                                 {
00585                                         pt = util3d::laserScanToPointRGB(tmpGround, i);
00586                                         pt = pcl::transformPoint(pt, t);
00587                                 }
00588                                 else
00589                                 {
00590                                         pt = pcl::transformPoint(cloudIter->second.first->at(i), t);
00591                                 }
00592                                 octomap::point3d point(pt.x, pt.y, pt.z);
00593                                 bool ignoreOccupiedCell = false;
00594                                 if(rangeMaxSqrd > 0.0f)
00595                                 {
00596                                         octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
00597                                         if(v.norm_sq() > rangeMaxSqrd)
00598                                         {
00599                                                 // compute new point to max range
00600                                                 v.normalize();
00601                                                 v*=rangeMax_;
00602                                                 point = sensorOrigin + v;
00603                                                 ignoreOccupiedCell=true;
00604                                         }
00605                                 }
00606 
00607                                 if(!ignoreOccupiedCell)
00608                                 {
00609                                         // occupied endpoint
00610                                         octomap::OcTreeKey key;
00611                                         if (octree_->coordToKeyChecked(point, key))
00612                                         {
00613                                                 if(iter->first >0 && iter->first<lastId)
00614                                                 {
00615                                                         RtabmapColorOcTreeNode * n = octree_->search(key);
00616                                                         if(n && n->getNodeRefId() > 0 && n->getNodeRefId() > iter->first)
00617                                                         {
00618                                                                 // The cell has been updated from more recent node, don't update the cell
00619                                                                 continue;
00620                                                         }
00621                                                 }
00622 
00623                                                 updateMinMax(point);
00624                                                 RtabmapColorOcTreeNode * n = octree_->updateNode(key, true);
00625 
00626                                                 if(n)
00627                                                 {
00628                                                         if(!hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
00629                                                         {
00630                                                                 hasColor_ = true;
00631                                                         }
00632                                                         octree_->averageNodeColor(key, pt.r, pt.g, pt.b);
00633                                                         if(iter->first > 0)
00634                                                         {
00635                                                                 n->setNodeRefId(iter->first);
00636                                                                 n->setPointRef(point);
00637                                                         }
00638                                                         n->setOccupancyType(RtabmapColorOcTreeNode::kTypeGround);
00639                                                 }
00640                                         }
00641                                 }
00642 
00643                                 // only clear space (ground points)
00644                                 if (computeRays &&
00645                                         (iter->first < 0 || iter->first>lastId) &&
00646                                         octree_->computeRayKeys(sensorOrigin, point, keyRay_))
00647                                 {
00648                                         free_cells.insert(keyRay_.begin(), keyRay_.end());
00649                                 }
00650                         }
00651                         UDEBUG("%d: ground cells=%d free cells=%d", iter->first, (int)maxGroundPts, (int)free_cells.size());
00652 
00653                         // all other points: free on ray, occupied on endpoint:
00654                         unsigned int maxObstaclePts = occupancyIter != cache_.end()?occupancyIter->second.first.second.cols:cloudIter->second.second->size();
00655                         UDEBUG("%d: compute occupied cells (from %d obstacle points)", iter->first, (int)maxObstaclePts);
00656                         LaserScan tmpObstacle;
00657                         if(occupancyIter != cache_.end())
00658                         {
00659                                 tmpObstacle = LaserScan::backwardCompatibility(occupancyIter->second.first.second);
00660                                 UASSERT(tmpObstacle.size() == (int)maxObstaclePts);
00661                         }
00662                         for (unsigned int i=0; i<maxObstaclePts; ++i)
00663                         {
00664                                 pcl::PointXYZRGB pt;
00665                                 if(occupancyIter != cache_.end())
00666                                 {
00667                                         pt = util3d::laserScanToPointRGB(tmpObstacle, i);
00668                                         pt = pcl::transformPoint(pt, t);
00669                                 }
00670                                 else
00671                                 {
00672                                         pt = pcl::transformPoint(cloudIter->second.second->at(i), t);
00673                                 }
00674 
00675                                 octomap::point3d point(pt.x, pt.y, pt.z);
00676 
00677                                 bool ignoreOccupiedCell = false;
00678                                 if(rangeMaxSqrd > 0.0f)
00679                                 {
00680                                         octomap::point3d v(pt.x - cellSize - sensorOrigin.x(), pt.y - cellSize - sensorOrigin.y(), pt.z - cellSize - sensorOrigin.z());
00681                                         if(v.norm_sq() > rangeMaxSqrd)
00682                                         {
00683                                                 // compute new point to max range
00684                                                 v.normalize();
00685                                                 v*=rangeMax_;
00686                                                 point = sensorOrigin + v;
00687                                                 ignoreOccupiedCell=true;
00688                                         }
00689                                 }
00690 
00691                                 if(!ignoreOccupiedCell)
00692                                 {
00693                                         // occupied endpoint
00694                                         octomap::OcTreeKey key;
00695                                         if (octree_->coordToKeyChecked(point, key))
00696                                         {
00697                                                 if(iter->first >0 && iter->first<lastId)
00698                                                 {
00699                                                         RtabmapColorOcTreeNode * n = octree_->search(key);
00700                                                         if(n && n->getNodeRefId() > 0 && n->getNodeRefId() > iter->first)
00701                                                         {
00702                                                                 // The cell has been updated from more recent node, don't update the cell
00703                                                                 continue;
00704                                                         }
00705                                                 }
00706 
00707                                                 updateMinMax(point);
00708 
00709                                                 RtabmapColorOcTreeNode * n = octree_->updateNode(key, true);
00710                                                 if(n)
00711                                                 {
00712                                                         if(!hasColor_ && !(pt.r ==0 && pt.g == 0 && pt.b == 0) && !(pt.r ==255 && pt.g == 255 && pt.b == 255))
00713                                                         {
00714                                                                 hasColor_ = true;
00715                                                         }
00716                                                         octree_->averageNodeColor(key, pt.r, pt.g, pt.b);
00717                                                         if(iter->first > 0)
00718                                                         {
00719                                                                 n->setNodeRefId(iter->first);
00720                                                                 n->setPointRef(point);
00721                                                         }
00722                                                         n->setOccupancyType(RtabmapColorOcTreeNode::kTypeObstacle);
00723                                                 }
00724                                         }
00725                                 }
00726 
00727                                 // free cells
00728                                 if (computeRays &&
00729                                         (iter->first < 0 || iter->first>lastId) &&
00730                                         octree_->computeRayKeys(sensorOrigin, point, keyRay_))
00731                                 {
00732                                         free_cells.insert(keyRay_.begin(), keyRay_.end());
00733                                 }
00734                         }
00735                         UDEBUG("%d: occupied cells=%d free cells=%d", iter->first, (int)maxObstaclePts, (int)free_cells.size());
00736 
00737 
00738                         // mark free cells only if not seen occupied in this cloud
00739                         for(octomap::KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ++it)
00740                         {
00741                                 if(iter->first > 0)
00742                                 {
00743                                         RtabmapColorOcTreeNode * n = octree_->search(*it);
00744                                         if(n && n->getNodeRefId() > 0 && n->getNodeRefId() >= iter->first)
00745                                         {
00746                                                 // The cell has been updated from current node or more recent node, don't update the cell
00747                                                 continue;
00748                                         }
00749                                 }
00750 
00751                                 RtabmapColorOcTreeNode * n = octree_->updateNode(*it, false);
00752                                 if(n && n->getOccupancyType() == RtabmapColorOcTreeNode::kTypeUnknown)
00753                                 {
00754                                         n->setOccupancyType(RtabmapColorOcTreeNode::kTypeEmpty);
00755                                         if(iter->first > 0)
00756                                         {
00757                                                 n->setNodeRefId(iter->first);
00758                                         }
00759                                 }
00760                         }
00761 
00762                         // all empty cells
00763                         if(occupancyIter != cache_.end() && occupancyIter->second.second.cols)
00764                         {
00765                                 unsigned int maxEmptyPts = occupancyIter->second.second.cols;
00766                                 UDEBUG("%d: compute free cells (from %d empty points)", iter->first, (int)maxEmptyPts);
00767                                 LaserScan tmpEmpty = LaserScan::backwardCompatibility(occupancyIter->second.second);
00768                                 UASSERT(tmpEmpty.size() == (int)maxEmptyPts);
00769                                 for (unsigned int i=0; i<maxEmptyPts; ++i)
00770                                 {
00771                                         pcl::PointXYZ pt;
00772                                         pt = util3d::laserScanToPoint(tmpEmpty, i);
00773                                         pt = pcl::transformPoint(pt, t);
00774 
00775                                         octomap::point3d point(pt.x, pt.y, pt.z);
00776 
00777                                         bool ignoreCell = false;
00778                                         if(rangeMaxSqrd > 0.0f)
00779                                         {
00780                                                 octomap::point3d v(pt.x - sensorOrigin.x(), pt.y - sensorOrigin.y(), pt.z - sensorOrigin.z());
00781                                                 if(v.norm_sq() > rangeMaxSqrd)
00782                                                 {
00783                                                         ignoreCell=true;
00784                                                 }
00785                                         }
00786 
00787                                         if(!ignoreCell)
00788                                         {
00789                                                 octomap::OcTreeKey key;
00790                                                 if (octree_->coordToKeyChecked(point, key))
00791                                                 {
00792 
00793                                                         if(iter->first >0)
00794                                                         {
00795                                                                 RtabmapColorOcTreeNode * n = octree_->search(key);
00796                                                                 if(n && n->getNodeRefId() > 0 && n->getNodeRefId() >= iter->first)
00797                                                                 {
00798                                                                         // The cell has been updated from current node or more recent node, don't update the cell
00799                                                                         continue;
00800                                                                 }
00801                                                         }
00802 
00803                                                         updateMinMax(point);
00804 
00805                                                         RtabmapColorOcTreeNode * n = octree_->updateNode(key, false);
00806                                                         if(n && n->getOccupancyType() == RtabmapColorOcTreeNode::kTypeUnknown)
00807                                                         {
00808                                                                 n->setOccupancyType(RtabmapColorOcTreeNode::kTypeEmpty);
00809                                                                 if(iter->first > 0)
00810                                                                 {
00811                                                                         n->setNodeRefId(iter->first);
00812                                                                 }
00813                                                         }
00814                                                 }
00815                                         }
00816                                 }
00817                         }
00818 
00819                         // compress map
00820                         //octree_->prune();
00821 
00822                         // ignore negative ids as they are temporary clouds
00823                         if(iter->first > 0)
00824                         {
00825                                 addedNodes_.insert(*iter);
00826                         }
00827                         UDEBUG("%d: end", iter->first);
00828                 }
00829                 else
00830                 {
00831                         UDEBUG("Did not find %d in cache", iter->first);
00832                 }
00833         }
00834 
00835         if(!fullUpdate_)
00836         {
00837                 cache_.clear();
00838                 cacheClouds_.clear();
00839                 cacheViewPoints_.clear();
00840         }
00841 }
00842 
00843 void OctoMap::updateMinMax(const octomap::point3d & point)
00844 {
00845         if(point.x() < minValues_[0])
00846         {
00847                 minValues_[0] = point.x();
00848         }
00849         if(point.y() < minValues_[1])
00850         {
00851                 minValues_[1] = point.y();
00852         }
00853         if(point.z() < minValues_[2])
00854         {
00855                 minValues_[2] = point.z();
00856         }
00857         if(point.x() > maxValues_[0])
00858         {
00859                 maxValues_[0] = point.x();
00860         }
00861         if(point.y() > maxValues_[1])
00862         {
00863                 maxValues_[1] = point.y();
00864         }
00865         if(point.z() > maxValues_[2])
00866         {
00867                 maxValues_[2] = point.z();
00868         }
00869 }
00870 
00871 void OctoMap::HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
00872 {
00873         int i;
00874         float f, p, q, t;
00875         if( s == 0 ) {
00876                 // achromatic (grey)
00877                 *r = *g = *b = v;
00878                 return;
00879         }
00880         h /= 60;                        // sector 0 to 5
00881         i = floor( h );
00882         f = h - i;                      // factorial part of h
00883         p = v * ( 1 - s );
00884         q = v * ( 1 - s * f );
00885         t = v * ( 1 - s * ( 1 - f ) );
00886         switch( i ) {
00887                 case 0:
00888                         *r = v;
00889                         *g = t;
00890                         *b = p;
00891                         break;
00892                 case 1:
00893                         *r = q;
00894                         *g = v;
00895                         *b = p;
00896                         break;
00897                 case 2:
00898                         *r = p;
00899                         *g = v;
00900                         *b = t;
00901                         break;
00902                 case 3:
00903                         *r = p;
00904                         *g = q;
00905                         *b = v;
00906                         break;
00907                 case 4:
00908                         *r = t;
00909                         *g = p;
00910                         *b = v;
00911                         break;
00912                 default:                // case 5:
00913                         *r = v;
00914                         *g = p;
00915                         *b = q;
00916                         break;
00917         }
00918 }
00919 
00920 pcl::PointCloud<pcl::PointXYZRGB>::Ptr OctoMap::createCloud(
00921                 unsigned int treeDepth,
00922                 std::vector<int> * obstacleIndices,
00923                 std::vector<int> * emptyIndices,
00924                 std::vector<int> * groundIndices,
00925                 bool originalRefPoints) const
00926 {
00927         UASSERT(treeDepth <= octree_->getTreeDepth());
00928         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
00929         UDEBUG("depth=%d (maxDepth=%d) octree = %d",
00930                         (int)treeDepth, (int)octree_->getTreeDepth(), (int)octree_->size());
00931         cloud->resize(octree_->size());
00932         if(obstacleIndices)
00933         {
00934                 obstacleIndices->resize(octree_->size());
00935         }
00936         if(emptyIndices)
00937         {
00938                 emptyIndices->resize(octree_->size());
00939         }
00940         if(groundIndices)
00941         {
00942                 groundIndices->resize(octree_->size());
00943         }
00944 
00945         if(treeDepth == 0)
00946         {
00947                 treeDepth = octree_->getTreeDepth();
00948         }
00949 
00950         double minZ = minValues_[2];
00951         double maxZ = maxValues_[2];
00952 
00953         bool addAllPoints = obstacleIndices == 0 && groundIndices == 0 && emptyIndices == 0;
00954         int oi=0;
00955         int si=0;
00956         int ei=0;
00957         int gi=0;
00958         float halfCellSize = octree_->getNodeSize(treeDepth)/2.0f;
00959         for (RtabmapColorOcTree::iterator it = octree_->begin(treeDepth); it != octree_->end(); ++it)
00960         {
00961                 if(octree_->isNodeOccupied(*it) && (obstacleIndices != 0 || groundIndices != 0 || addAllPoints))
00962                 {
00963                         octomap::point3d pt = octree_->keyToCoord(it.getKey());
00964                         if(octree_->getTreeDepth() == it.getDepth() && hasColor_)
00965                         {
00966                                 (*cloud)[oi]  = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
00967                         }
00968                         else
00969                         {
00970                                 // Gradiant color on z axis
00971                                 float H = (maxZ - pt.z())*299.0f/(maxZ-minZ);
00972                                 float r,g,b;
00973                                 HSVtoRGB(&r, &g, &b, H, 1, 1);
00974                                 (*cloud)[oi].r = r*255.0f;
00975                                 (*cloud)[oi].g = g*255.0f;
00976                                 (*cloud)[oi].b = b*255.0f;
00977                         }
00978 
00979                         if(originalRefPoints && it->getOccupancyType() > 0)
00980                         {
00981                                 const octomap::point3d & p = it->getPointRef();
00982                                 (*cloud)[oi].x = p.x();
00983                                 (*cloud)[oi].y = p.y();
00984                                 (*cloud)[oi].z = p.z();
00985                         }
00986                         else
00987                         {
00988                                 (*cloud)[oi].x = pt.x()-halfCellSize;
00989                                 (*cloud)[oi].y = pt.y()-halfCellSize;
00990                                 (*cloud)[oi].z = pt.z();
00991                         }
00992 
00993                         if(it->getOccupancyType() == RtabmapColorOcTreeNode::kTypeGround)
00994                         {
00995                                 if(groundIndices)
00996                                 {
00997                                         groundIndices->at(gi++) = oi;
00998                                 }
00999                         }
01000                         else if(obstacleIndices)
01001                         {
01002                                 obstacleIndices->at(si++) = oi;
01003                         }
01004 
01005                         ++oi;
01006                 }
01007                 else if(!octree_->isNodeOccupied(*it) && (emptyIndices != 0 || addAllPoints))
01008                 {
01009                         octomap::point3d pt = octree_->keyToCoord(it.getKey());
01010                         (*cloud)[oi]  = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
01011                         (*cloud)[oi].x = pt.x()-halfCellSize;
01012                         (*cloud)[oi].y = pt.y()-halfCellSize;
01013                         (*cloud)[oi].z = pt.z();
01014                         if(emptyIndices)
01015                         {
01016                                 emptyIndices->at(ei++) = oi;
01017                         }
01018                         ++oi;
01019                 }
01020         }
01021 
01022         cloud->resize(oi);
01023         if(obstacleIndices)
01024         {
01025                 obstacleIndices->resize(si);
01026                 UDEBUG("obstacle=%d", si);
01027         }
01028         if(emptyIndices)
01029         {
01030                 emptyIndices->resize(ei);
01031                 UDEBUG("empty=%d", ei);
01032         }
01033         if(groundIndices)
01034         {
01035                 groundIndices->resize(gi);
01036                 UDEBUG("ground=%d", gi);
01037         }
01038 
01039         UDEBUG("");
01040         return cloud;
01041 }
01042 
01043 cv::Mat OctoMap::createProjectionMap(float & xMin, float & yMin, float & gridCellSize, float minGridSize, unsigned int treeDepth)
01044 {
01045         UDEBUG("minGridSize=%f, treeDepth=%d", minGridSize, (int)treeDepth);
01046         UASSERT(treeDepth <= octree_->getTreeDepth());
01047         if(treeDepth == 0)
01048         {
01049                 treeDepth = octree_->getTreeDepth();
01050         }
01051 
01052         gridCellSize = octree_->getNodeSize(treeDepth);
01053         float halfCellSize = gridCellSize/2.0f;
01054 
01055         cv::Mat obstaclesMat = cv::Mat(1, (int)octree_->size(), CV_32FC2);
01056         cv::Mat groundMat = cv::Mat(1, (int)octree_->size(), CV_32FC2);
01057         int gi=0;
01058         int oi=0;
01059         cv::Vec2f * oPtr = obstaclesMat.ptr<cv::Vec2f>(0,0);
01060         cv::Vec2f * gPtr = groundMat.ptr<cv::Vec2f>(0,0);
01061         for (RtabmapColorOcTree::iterator it = octree_->begin(treeDepth); it != octree_->end(); ++it)
01062         {
01063                 octomap::point3d pt = octree_->keyToCoord(it.getKey());
01064                 if(octree_->isNodeOccupied(*it) && it->getOccupancyType() == RtabmapColorOcTreeNode::kTypeObstacle)
01065                 {
01066                         // projected on ground
01067                         oPtr[oi][0] = pt.x()-halfCellSize;
01068                         oPtr[oi][1] = pt.y()-halfCellSize;
01069                         ++oi;
01070                 }
01071                 else
01072                 {
01073                         // projected on ground
01074                         gPtr[gi][0] = pt.x()-halfCellSize;
01075                         gPtr[gi][1] = pt.y()-halfCellSize;
01076                         ++gi;
01077                 }
01078         }
01079         obstaclesMat = obstaclesMat(cv::Range::all(), cv::Range(0, oi));
01080         groundMat = groundMat(cv::Range::all(), cv::Range(0, gi));
01081 
01082         std::map<int, Transform> poses;
01083         poses.insert(std::make_pair(1, Transform::getIdentity()));
01084         std::map<int, std::pair<cv::Mat, cv::Mat> > maps;
01085         maps.insert(std::make_pair(1, std::make_pair(groundMat, obstaclesMat)));
01086 
01087         cv::Mat map = util3d::create2DMapFromOccupancyLocalMaps(
01088                         poses,
01089                         maps,
01090                         gridCellSize,
01091                         xMin, yMin,
01092                         minGridSize,
01093                         false);
01094         UDEBUG("");
01095         return map;
01096 }
01097 
01098 bool OctoMap::writeBinary(const std::string & path)
01099 {
01100         return octree_->writeBinary(path);
01101 }
01102 
01103 } /* namespace rtabmap */


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:21