void DBDriver::loadLinks(int signatureId, std::map<int, Link> & links, Link::Type type) const { bool found = false; // look in the trash _trashesMutex.lock(); if(uContains(_trashSignatures, signatureId)) { const Signature * s = _trashSignatures.at(signatureId); UASSERT(s != 0); for(std::map<int, Link>::const_iterator nIter = s->getLinks().begin(); nIter!=s->getLinks().end(); ++nIter) { if(type == Link::kUndef || nIter->second.type() == type) { links.insert(*nIter); } } found = true; } _trashesMutex.unlock(); if(!found) { _dbSafeAccessMutex.lock(); this->loadLinksQuery(signatureId, links, type); _dbSafeAccessMutex.unlock(); } }
bool DBDriver::getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, std::vector<unsigned char> & userData) const { bool found = false; // look in the trash _trashesMutex.lock(); if(uContains(_trashSignatures, signatureId)) { pose = _trashSignatures.at(signatureId)->getPose(); mapId = _trashSignatures.at(signatureId)->mapId(); weight = _trashSignatures.at(signatureId)->getWeight(); label = _trashSignatures.at(signatureId)->getLabel(); stamp = _trashSignatures.at(signatureId)->getStamp(); userData = _trashSignatures.at(signatureId)->getUserData(); found = true; } _trashesMutex.unlock(); if(!found) { _dbSafeAccessMutex.lock(); found = this->getNodeInfoQuery(signatureId, pose, mapId, weight, label, stamp, userData); _dbSafeAccessMutex.unlock(); } return found; }
void DBDriver::getInvertedIndexNi(int signatureId, int & ni) const { bool found = false; // look in the trash _trashesMutex.lock(); if(uContains(_trashSignatures, signatureId)) { ni = _trashSignatures.at(signatureId)->getWords().size(); found = true; } _trashesMutex.unlock(); if(!found) { _dbSafeAccessMutex.lock(); this->getInvertedIndexNiQuery(signatureId, ni); _dbSafeAccessMutex.unlock(); } }
void DBDriver::getWeight(int signatureId, int & weight) const { bool found = false; // look in the trash _trashesMutex.lock(); if(uContains(_trashSignatures, signatureId)) { weight = _trashSignatures.at(signatureId)->getWeight(); found = true; } _trashesMutex.unlock(); if(!found) { _dbSafeAccessMutex.lock(); this->getWeightQuery(signatureId, weight); _dbSafeAccessMutex.unlock(); } }
void DBDriver::loadNodeData(std::list<Signature *> & signatures, bool loadMetricData) const { // Don't look in the trash, we assume that if we want to load // data of a signature, it is not in thrash! Print an error if so. _trashesMutex.lock(); if(_trashSignatures.size()) { for(std::list<Signature *>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter) { UASSERT(*iter != 0); UASSERT_MSG(!uContains(_trashSignatures, (*iter)->id()), uFormat("Signature %d should not be used when transferred to trash!!!!", (*iter)->id()).c_str()); } } _trashesMutex.unlock(); _dbSafeAccessMutex.lock(); this->loadNodeDataQuery(signatures, loadMetricData); _dbSafeAccessMutex.unlock(); }
void DBDriver::getNodeData( int signatureId, cv::Mat & imageCompressed, cv::Mat & depthCompressed, cv::Mat & laserScanCompressed, float & fx, float & fy, float & cx, float & cy, Transform & localTransform, int & laserScanMaxPts) const { bool found = false; // look in the trash _trashesMutex.lock(); if(uContains(_trashSignatures, signatureId)) { const Signature * s = _trashSignatures.at(signatureId); if(!s->getImageCompressed().empty() || !s->isSaved()) { imageCompressed = s->getImageCompressed(); depthCompressed = s->getDepthCompressed(); laserScanCompressed = s->getLaserScanCompressed(); fx = s->getFx(); fy = s->getFy(); cx = s->getCx(); cy = s->getCy(); localTransform = s->getLocalTransform(); laserScanMaxPts = s->getLaserScanMaxPts(); found = true; } } _trashesMutex.unlock(); if(!found) { _dbSafeAccessMutex.lock(); this->getNodeDataQuery(signatureId, imageCompressed, depthCompressed, laserScanCompressed, fx, fy, cx, cy, localTransform, laserScanMaxPts); _dbSafeAccessMutex.unlock(); } }
void DBDriver::getNodeData(int signatureId, cv::Mat & imageCompressed) const { bool found = false; // look in the trash _trashesMutex.lock(); if(uContains(_trashSignatures, signatureId)) { const Signature * s = _trashSignatures.at(signatureId); if(!s->getImageCompressed().empty() || !s->isSaved()) { imageCompressed = s->getImageCompressed(); found = true; } } _trashesMutex.unlock(); if(!found) { _dbSafeAccessMutex.lock(); this->getNodeDataQuery(signatureId, imageCompressed); _dbSafeAccessMutex.unlock(); } }
cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction, const Memory * memory, const std::vector<int> & oldIds, const std::vector<int> & newIds) const { UTimer timer; UDEBUG(""); UASSERT(memory && oldIds.size() && newIds.size() && oldIds.size() == (unsigned int)oldPrediction.cols && oldIds.size() == (unsigned int)oldPrediction.rows); cv::Mat prediction = cv::Mat::zeros(newIds.size(), newIds.size(), CV_32FC1); // Create id to index maps std::map<int, int> oldIdToIndexMap; std::map<int, int> newIdToIndexMap; for(unsigned int i=0; i<oldIds.size() || i<newIds.size(); ++i) { if(i<oldIds.size()) { UASSERT(oldIds[i]); oldIdToIndexMap.insert(oldIdToIndexMap.end(), std::make_pair(oldIds[i], i)); //UDEBUG("oldIdToIndexMap[%d] = %d", oldIds[i], i); } if(i<newIds.size()) { UASSERT(newIds[i]); newIdToIndexMap.insert(newIdToIndexMap.end(), std::make_pair(newIds[i], i)); //UDEBUG("newIdToIndexMap[%d] = %d", newIds[i], i); } } UDEBUG("time creating id-index maps = %fs", timer.restart()); //Get removed ids std::set<int> removedIds; for(unsigned int i=0; i<oldIds.size(); ++i) { if(!uContains(newIdToIndexMap, oldIds[i])) { removedIds.insert(removedIds.end(), oldIds[i]); UDEBUG("removed id=%d at oldIndex=%d", oldIds[i], i); } } UDEBUG("time getting removed ids = %fs", timer.restart()); int added = 0; // get ids to update std::set<int> idsToUpdate; for(unsigned int i=0; i<oldIds.size() || i<newIds.size(); ++i) { if(i<oldIds.size()) { if(removedIds.find(oldIds[i]) != removedIds.end()) { unsigned int cols = oldPrediction.cols; for(unsigned int j=0; j<cols; ++j) { if(((const float *)oldPrediction.data)[i + j*cols] != 0.0f && j!=i && removedIds.find(oldIds[j]) == removedIds.end()) { //UDEBUG("to update id=%d from id=%d removed (value=%f)", oldIds[j], oldIds[i], ((const float *)oldPrediction.data)[i + j*cols]); idsToUpdate.insert(oldIds[j]); } } } } if(i<newIds.size() && !uContains(oldIdToIndexMap,newIds[i])) { std::map<int, int> neighbors = memory->getNeighborsId(newIds[i], _predictionLC.size()-1, 0); float sum = this->addNeighborProb(prediction, i, neighbors, newIdToIndexMap); this->normalize(prediction, i, sum, newIds[0]<0); ++added; for(std::map<int,int>::iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter) { if(uContains(oldIdToIndexMap, iter->first) && removedIds.find(iter->first) == removedIds.end()) { idsToUpdate.insert(iter->first); } } } } UDEBUG("time getting ids to update = %fs", timer.restart()); // update modified/added ids int modified = 0; for(std::set<int>::iterator iter = idsToUpdate.begin(); iter!=idsToUpdate.end(); ++iter) { std::map<int, int> neighbors = memory->getNeighborsId(*iter, _predictionLC.size()-1, 0); int index = newIdToIndexMap.at(*iter); float sum = this->addNeighborProb(prediction, index, neighbors, newIdToIndexMap); this->normalize(prediction, index, sum, newIds[0]<0); ++modified; } UDEBUG("time updating modified/added ids = %fs", timer.restart()); //UDEBUG("oldIds.size()=%d, oldPrediction.cols=%d, oldPrediction.rows=%d", oldIds.size(), oldPrediction.cols, oldPrediction.rows); //UDEBUG("newIdToIndexMap.size()=%d, prediction.cols=%d, prediction.rows=%d", newIdToIndexMap.size(), prediction.cols, prediction.rows); // copy not changed probabilities int copied = 0; for(unsigned int i=0; i<oldIds.size(); ++i) { if(oldIds[i]>0 && removedIds.find(oldIds[i]) == removedIds.end() && idsToUpdate.find(oldIds[i]) == idsToUpdate.end()) { for(int j=0; j<oldPrediction.cols; ++j) { if(removedIds.find(oldIds[j]) == removedIds.end() && ((const float *)oldPrediction.data)[i + j*oldPrediction.cols] != 0.0f) { //UDEBUG("i=%d, j=%d", i, j); //UDEBUG("oldIds[i]=%d, oldIds[j]=%d", oldIds[i], oldIds[j]); //UDEBUG("newIdToIndexMap.at(oldIds[i])=%d", newIdToIndexMap.at(oldIds[i])); //UDEBUG("newIdToIndexMap.at(oldIds[j])=%d", newIdToIndexMap.at(oldIds[j])); ((float *)prediction.data)[newIdToIndexMap.at(oldIds[i]) + newIdToIndexMap.at(oldIds[j])*prediction.cols] = ((const float *)oldPrediction.data)[i + j*oldPrediction.cols]; } } ++copied; } } UDEBUG("time copying = %fs", timer.restart()); //update virtual place if(newIds[0] < 0) { if(prediction.cols>1) // The first must be the virtual place { ((float*)prediction.data)[0] = _virtualPlacePrior; float val = (1.0-_virtualPlacePrior)/(prediction.cols-1); for(int j=1; j<prediction.cols; j++) { ((float*)prediction.data)[j*prediction.cols] = val; } } else if(prediction.cols>0) { ((float*)prediction.data)[0] = 1; } } UDEBUG("time updating virtual place = %fs", timer.restart()); UDEBUG("Modified=%d, Added=%d, Copied=%d", modified, added, copied); return prediction; }
// OpenGL thread int RTABMapApp::Render() { // should be before clearSceneOnNextRender_ in case openDatabase is called std::list<rtabmap::Statistics> rtabmapEvents; { boost::mutex::scoped_lock lock(rtabmapMutex_); rtabmapEvents = rtabmapEvents_; rtabmapEvents_.clear(); } if(clearSceneOnNextRender_) { odomMutex_.lock(); odomEvents_.clear(); odomMutex_.unlock(); poseMutex_.lock(); poseEvents_.clear(); poseMutex_.unlock(); main_scene_.clear(); clearSceneOnNextRender_ = false; createdMeshes_.clear(); rawPoses_.clear(); totalPoints_ = 0; totalPolygons_ = 0; lastDrawnCloudsCount_ = 0; renderingFPS_ = 0.0f; } // Process events rtabmap::Transform pose; { boost::mutex::scoped_lock lock(poseMutex_); if(poseEvents_.size()) { pose = poseEvents_.back(); poseEvents_.clear(); } } if(!pose.isNull()) { // update camera pose? main_scene_.SetCameraPose(pose); } bool notifyDataLoaded = false; if(rtabmapEvents.size()) { LOGI("Process rtabmap events"); // update buffered signatures std::map<int, rtabmap::SensorData> bufferedSensorData; if(!trajectoryMode_) { for(std::list<rtabmap::Statistics>::iterator iter=rtabmapEvents.begin(); iter!=rtabmapEvents.end(); ++iter) { for(std::map<int, rtabmap::Signature>::const_iterator jter=iter->getSignatures().begin(); jter!=iter->getSignatures().end(); ++jter) { if(!jter->second.sensorData().imageRaw().empty() && !jter->second.sensorData().depthRaw().empty()) { uInsert(bufferedSensorData, std::make_pair(jter->first, jter->second.sensorData())); uInsert(rawPoses_, std::make_pair(jter->first, jter->second.getPose())); } else if(!jter->second.sensorData().imageCompressed().empty() && !jter->second.sensorData().depthOrRightCompressed().empty()) { // uncompress rtabmap::SensorData data = jter->second.sensorData(); cv::Mat tmpA,tmpB; data.uncompressData(&tmpA, &tmpB); uInsert(bufferedSensorData, std::make_pair(jter->first, data)); uInsert(rawPoses_, std::make_pair(jter->first, jter->second.getPose())); notifyDataLoaded = true; } } } } std::map<int, rtabmap::Transform> poses = rtabmapEvents.back().poses(); // Transform pose in OpenGL world for(std::map<int, rtabmap::Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter) { if(!graphOptimization_) { std::map<int, rtabmap::Transform>::iterator jter = rawPoses_.find(iter->first); if(jter != rawPoses_.end()) { iter->second = opengl_world_T_rtabmap_world*jter->second; } } else { iter->second = opengl_world_T_rtabmap_world*iter->second; } } const std::multimap<int, rtabmap::Link> & links = rtabmapEvents.back().constraints(); if(poses.size()) { //update graph main_scene_.updateGraph(poses, links); // update clouds boost::mutex::scoped_lock lock(meshesMutex_); std::set<std::string> strIds; for(std::map<int, rtabmap::Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter) { int id = iter->first; if(!iter->second.isNull()) { if(main_scene_.hasCloud(id)) { //just update pose main_scene_.setCloudPose(id, iter->second); main_scene_.setCloudVisible(id, true); std::map<int, Mesh>::iterator meshIter = createdMeshes_.find(id); if(meshIter!=createdMeshes_.end()) { meshIter->second.pose = iter->second; } else { UERROR("Not found mesh %d !?!?", id); } } else if(uContains(bufferedSensorData, id)) { rtabmap::SensorData & data = bufferedSensorData.at(id); if(!data.imageRaw().empty() && !data.depthRaw().empty()) { // Voxelize and filter depending on the previous cloud? pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; pcl::IndicesPtr indices(new std::vector<int>); LOGI("Creating node cloud %d (image size=%dx%d)", id, data.imageRaw().cols, data.imageRaw().rows); cloud = rtabmap::util3d::cloudRGBFromSensorData(data, data.imageRaw().rows/data.depthRaw().rows, maxCloudDepth_, 0, indices.get()); if(cloud->size() && indices->size()) { UTimer time; // pcl::organizedFastMesh doesn't take indices, so set to NaN points we don't need to mesh pcl::PointCloud<pcl::PointXYZRGB>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGB>); pcl::ExtractIndices<pcl::PointXYZRGB> filter; filter.setIndices(indices); filter.setKeepOrganized(true); filter.setInputCloud(cloud); filter.filter(*output); std::vector<pcl::Vertices> polygons = rtabmap::util3d::organizedFastMesh(output, meshAngleToleranceDeg_*M_PI/180.0, false, meshTrianglePix_); pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputCloud(new pcl::PointCloud<pcl::PointXYZRGB>); std::vector<pcl::Vertices> outputPolygons; outputCloud = output; outputPolygons = polygons; LOGI("Creating mesh, %d polygons (%fs)", (int)outputPolygons.size(), time.ticks()); if(outputCloud->size() && outputPolygons.size()) { totalPolygons_ += outputPolygons.size(); main_scene_.addCloud(id, outputCloud, outputPolygons, iter->second, data.imageRaw()); // protect createdMeshes_ used also by exportMesh() method std::pair<std::map<int, Mesh>::iterator, bool> inserted = createdMeshes_.insert(std::make_pair(id, Mesh())); UASSERT(inserted.second); inserted.first->second.cloud = outputCloud; inserted.first->second.polygons = outputPolygons; inserted.first->second.pose = iter->second; inserted.first->second.texture = data.imageCompressed(); } else { LOGE("Not mesh could be created for node %d", id); } } totalPoints_+=indices->size(); } } } } } //filter poses? if(poses.size() > 2) { if(nodesFiltering_) { for(std::multimap<int, rtabmap::Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter) { if(iter->second.type() != rtabmap::Link::kNeighbor) { int oldId = iter->second.to()>iter->second.from()?iter->second.from():iter->second.to(); poses.erase(oldId); } } } } //update cloud visibility std::set<int> addedClouds = main_scene_.getAddedClouds(); for(std::set<int>::const_iterator iter=addedClouds.begin(); iter!=addedClouds.end(); ++iter) { if(*iter > 0 && poses.find(*iter) == poses.end()) { main_scene_.setCloudVisible(*iter, false); } } } else { rtabmap::OdometryEvent event; bool set = false; { boost::mutex::scoped_lock lock(odomMutex_); if(odomEvents_.size()) { LOGI("Process odom events"); event = odomEvents_.back(); odomEvents_.clear(); set = true; } } main_scene_.setCloudVisible(-1, odomCloudShown_ && !trajectoryMode_); //just process the last one if(set && !event.pose().isNull()) { if(odomCloudShown_ && !trajectoryMode_) { if(!event.data().imageRaw().empty() && !event.data().depthRaw().empty()) { pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; cloud = rtabmap::util3d::cloudRGBFromSensorData(event.data(), event.data().imageRaw().rows/event.data().depthRaw().rows, maxCloudDepth_); if(cloud->size()) { LOGI("Created odom cloud (rgb=%dx%d depth=%dx%d cloud=%dx%d)", event.data().imageRaw().cols, event.data().imageRaw().rows, event.data().depthRaw().cols, event.data().depthRaw().rows, (int)cloud->width, (int)cloud->height); std::vector<pcl::Vertices> polygons = rtabmap::util3d::organizedFastMesh(cloud, meshAngleToleranceDeg_*M_PI/180.0, false, meshTrianglePix_); main_scene_.addCloud(-1, cloud, polygons, opengl_world_T_rtabmap_world*event.pose(), event.data().imageRaw()); main_scene_.setCloudVisible(-1, true); } else { LOGE("Generated cloud is empty!"); } } else { LOGE("Odom data images are empty!"); } } } } UTimer fpsTime; lastDrawnCloudsCount_ = main_scene_.Render(); renderingFPS_ = 1.0/fpsTime.elapsed(); if(rtabmapEvents.size()) { // send statistics to GUI LOGI("Posting PostRenderEvent!"); UEventsManager::post(new PostRenderEvent(rtabmapEvents.back())); } return notifyDataLoaded?1:0; }