00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
00061 bool RtabmapColorOcTreeNode::pruneNode() {
00062 #ifdef OCTOMAP_PRE_18
00063
00064 if (!this->collapsible()) return false;
00065
00066 setLogOdds(getChild(0)->getLogOdds());
00067
00068 if (isColorSet()) color = getAverageChildColor();
00069
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
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
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
00129 node->copyData(*(getNodeChild(node, 0)));
00130
00131 if (node->isColorSet())
00132 node->setColor(node->getAverageChildColor());
00133
00134
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
00151
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
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
00221 if (nodeHasChildren(node)){
00222
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
00235 if (node->hasChildren()){
00236
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
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
00372 bool graphOptimized = false;
00373 bool graphChanged = addedNodes_.size()>0;
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
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
00460 continue;
00461 }
00462 else if(nOld.getOccupancyType() <= 0 && n->getOccupancyType() > 0)
00463 {
00464
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
00495
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
00504 addedNodes_ = updatedAddedNodes;
00505 }
00506 }
00507
00508
00509
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
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
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
00569 octomap::KeySet free_cells;
00570
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
00600 v.normalize();
00601 v*=rangeMax_;
00602 point = sensorOrigin + v;
00603 ignoreOccupiedCell=true;
00604 }
00605 }
00606
00607 if(!ignoreOccupiedCell)
00608 {
00609
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
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
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
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
00684 v.normalize();
00685 v*=rangeMax_;
00686 point = sensorOrigin + v;
00687 ignoreOccupiedCell=true;
00688 }
00689 }
00690
00691 if(!ignoreOccupiedCell)
00692 {
00693
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
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
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
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
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
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
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
00820
00821
00822
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
00877 *r = *g = *b = v;
00878 return;
00879 }
00880 h /= 60;
00881 i = floor( h );
00882 f = h - i;
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:
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
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
01067 oPtr[oi][0] = pt.x()-halfCellSize;
01068 oPtr[oi][1] = pt.y()-halfCellSize;
01069 ++oi;
01070 }
01071 else
01072 {
01073
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 }