Program Listing for File SlamSystem.cpp¶
↰ Return to documentation for file (lib/SlamSystem.cpp)
#include <memory>
#include "SlamSystem.h"
#include <boost/thread/shared_lock_guard.hpp>
#include <g3log/g3log.hpp>
#ifdef ANDROID
#include <android/log.h>
#endif
#include <opencv2/opencv.hpp>
#include "DataStructures/Frame.h"
#include "DataStructures/FrameMemory.h"
#include "GlobalMapping/KeyFrameGraph.h"
#include "GlobalMapping/TrackableKeyFrameSearch.h"
#include "util/globalFuncs.h"
#include "SlamSystem/ConstraintSearchThread.h"
#include "SlamSystem/MappingThread.h"
#include "SlamSystem/OptimizationThread.h"
using namespace lsd_slam;
SlamSystem::SlamSystem()
: _perf(), _outputWrappers(), _finalized(), _initialized(false),
// _keyFrames(),
_keyFrameGraph(new KeyFrameGraph),
_trackableKeyFrameSearch(new TrackableKeyFrameSearch(_keyFrameGraph)) {
// Because some of these rely on Conf(), need to explicitly call after
// static initialization. Is this true?
const bool threaded = Conf().runRealTime;
_optThread.reset(new OptimizationThread(*this, threaded));
_mapThread.reset(new MappingThread(*this, threaded));
_constraintThread.reset(new ConstraintSearchThread(*this, threaded));
_trackingThread.reset(new TrackingThread(*this, threaded));
timeLastUpdate.start();
}
SlamSystem::~SlamSystem() {
// make sure no-one is waiting for something.
LOG(INFO) << "... waiting for all threads to exit";
_mapThread.reset();
_constraintThread.reset();
_optThread.reset();
_trackingThread.reset();
LOG(INFO) << "DONE waiting for all threads to exit";
FrameMemory::getInstance().releaseBuffers();
}
SlamSystem *SlamSystem::fullReset(void) {
SlamSystem *newSystem = new SlamSystem();
for (auto &wrapper : _outputWrappers) {
newSystem->addOutputWrapper(wrapper);
}
return newSystem;
}
void SlamSystem::finalize() {
LOG(INFO) << "Finalizing Graph... adding final constraints!!";
// Run this in the foreground
_constraintThread->doFullReConstraintSearch();
_constraintThread->fullReConstraintSearchComplete.wait();
LOG(INFO) << "Finalizing Graph... optimizing!!";
// This happens in the foreground
// This will kick off a final map publication with the newly optimized offsets
// (also in foreground)
_optThread->doFinalOptimization();
_optThread->finalOptimizationComplete.wait();
_mapThread->optimizationUpdateMerged.wait();
LOG(INFO) << "Done Finalizing Graph.!!";
_finalized.notify();
LOG(INFO) << "Done Finalizing Graph.!!";
_finalized.notify();
}
// std::shared_ptr<KeyFrame> &SlamSystem::currentKeyFrame()
// Thin wrapper which turns a bare cv::Mat image into an ImageSe
void SlamSystem::nextImage(unsigned int id, const cv::Mat &img,
const libvideoio::Camera &cam) {
nextImageSet(std::make_shared<ImageSet>(id, img, cam));
}
void SlamSystem::nextImageSet(const std::shared_ptr<ImageSet> &set) {
if (!_initialized) {
_mapThread->createFirstKeyFrame(set);
_initialized = true;
return;
}
_trackingThread->doTrackSet(set);
logPerformanceData();
}
//=== Keyframe maintenance functions ====
// void SlamSystem::addKeyFrame( const KeyFrame::SharedPtr &keyframe )
// {
// _keyFrames.push_back( keyframe );
//
//
// keyFrameGraph()->idToKeyFrame.insert(std::make_pair(keyframe->id(),
// keyframe));
// }
// void SlamSystem::changeKeyframe( const Frame::SharedPtr &candidate, bool
// noCreate, bool force, float maxScore)
// {
// Frame::SharedPtr newReferenceKF(nullptr);
//
// if( Conf().doKFReActivation && Conf().SLAMEnabled )
// {
// Timer timer;
// newReferenceKF =
// trackableKeyFrameSearch()->findRePositionCandidate( candidate, maxScore );
// _perf.findReferences.update( timer );
// }
//
// if(newReferenceKF != 0) {
// LOG(INFO) << "Reloading existing key frame " <<
// newReferenceKF->id(); loadNewCurrentKeyframe(newReferenceKF);
// } else { if(force)
// {
// if(noCreate)
// {
// LOG(INFO) << "mapping is disabled & moved outside
// of known map. Starting Relocalizer!";
// trackingThread->setTrackingIsBad();
// //nextRelocIdx = -1; /// What does this do?
// }
// else
// {
// createNewCurrentKeyframe( candidate );
// }
// }
// }
// // createNewKeyFrame = false;
// }
//
// void SlamSystem::loadNewCurrentKeyframe( const Frame::SharedPtr
// &keyframeToLoad)
// {
// depthMap()->activateExistingKF(keyframeToLoad);
//
// LOG_IF(DEBUG, Conf().print.regularizeStatistics ) << "re-activate frame
// " << keyframeToLoad->id() << "!";
//
// // Not entirely sure why they're doing this lookup...
// //_currentKeyFrame =
// keyFrameGraph()->idToKeyFrame.find(keyframeToLoad->id())->second;
// //currentKeyFrame()->depthHasBeenUpdatedFlag = false;
// }
//
//
// void SlamSystem::createNewCurrentKeyframe( const Frame::SharedPtr
// &newKeyframeCandidate)
// {
// LOG_IF(INFO, Conf().print.threadingInfo) << "CREATE NEW KF " <<
// newKeyframeCandidate->id() << ", replacing " << currentKeyFrame()->id();
//
// if( Conf().SLAMEnabled)
// {
// boost::shared_lock_guard< boost::shared_mutex > lock(
// keyFrameGraph()->idToKeyFrameMutex );
// keyFrameGraph()->idToKeyFrame.insert(std::make_pair(newKeyframeCandidate->id(),
// newKeyframeCandidate));
// }
//
// // propagate & make new.
// depthMap()->createKeyFrame(newKeyframeCandidate);
// }
//===== Debugging output functions =====
void SlamSystem::logPerformanceData() {
float sPassed = timeLastUpdate.reset();
if (sPassed > 1.0f) {
// LOGF(DEBUG, "Mapping: %3.1fms (%.1fHz); Track: %3.1fms (%.1fHz); Create:
// %3.1fms (%.1fHz); FindRef: %3.1fms (%.1fHz); PermaTrk: %3.1fms (%.1fHz);
// Opt: %3.1fms (%.1fHz); FindConst: %3.1fms (%.1fHz);\n",
// depthMap()->perf().update.ms(),
// depthMap()->perf().update.rate(),
// _trackingThread->perf().track.ms(), _trackingThread->perf().track.rate(),
// depthMap()->perf().create.ms()+depthMap()->perf().finalize.ms(),
// depthMap()->perf().create.rate(),
// _perf.findReferences.ms(), _perf.findReferences.rate(),
// 0.0, 0.0,
// //trackableKeyFrameSearch != 0 ?
// trackableKeyFrameSearch->trackPermaRef.ms() : 0, trackableKeyFrameSearch
// != 0 ? trackableKeyFrameSearch->trackPermaRef.rate() : 0,
// _optThread->perf.ms(), _optThread->perf.rate(),
// _constraintThread->perf().findConstraint.ms(),
// _constraintThread->perf().findConstraint.rate() );
//
// depthMap()->logPerformanceData();
}
}
void SlamSystem::updateDisplayDepthMap() {
if (!Conf().displayDepthMap)
return;
const double scale = (bool)currentKeyFrame()
? currentKeyFrame()->frame()->getCamToWorld().scale()
: 1.0;
// debug plot depthmap
char buf1[200] = "";
char buf2[200] = "";
if (Conf().onSceenInfoDisplay) {
// snprintf(buf1,200,"Map: Upd %3.0fms (%2.0fHz); Trk %3.0fms (%2.0fHz); %d
// / %d", depthMap()->perf().update.ms(),
// depthMap()->perf().update.rate(), _trackingThread->perf().track.ms(),
// _trackingThread->perf().track.rate(),
// currentKeyFrame()->numFramesTrackedOnThis,
// currentKeyFrame()->numMappedOnThis ); //,
// (int)unmappedTrackedFrames().size());
// snprintf(buf2,200,"dens %2.0f%%; good %2.0f%%; scale %2.2f; res %2.1f/;
// usg %2.0f%%; Map: %d F, %d KF, %d E, %.1fm Pts",
// 100*currentKeyFrame->numPoints/(float)(Conf().slamImage.area()),
// 100*tracking_lastGoodPerBad,
// scale,
// tracking_lastResidual,
// 100*tracking_lastUsage,
// (int)keyFrameGraph()->allFramePoses.size(),
// keyFrameGraph()->totalVertices,
// (int)keyFrameGraph()->edgesAll.size(),
// 1e-6 * (float)keyFrameGraph()->totalPoints);
}
currentKeyFrame()->depthMap()->plotDepthMap(buf1, buf2);
CHECK(currentKeyFrame()->depthMap()->debugImages().depthImage().data != NULL);
publishDepthImage(
currentKeyFrame()->depthMap()->debugImages().depthImage().data);
}
//=== OutputWrapper functions ==
#define OUTPUT_FOR_EACH(func) \
for (auto &wrapper : _outputWrappers) { \
wrapper->func; \
}
void SlamSystem::publishPose(const Sophus::Sim3f &pose) {
OUTPUT_FOR_EACH(publishPose(pose))
}
void SlamSystem::publishTrackedFrame(const Frame::SharedPtr &frame) {
OUTPUT_FOR_EACH(publishTrackedFrame(frame))
}
void SlamSystem::publishKeyframeGraph(void) {
OUTPUT_FOR_EACH(publishKeyframeGraph(keyFrameGraph()))
}
void SlamSystem::publishDepthImage(unsigned char *data) {
OUTPUT_FOR_EACH(updateDepthImage(data))
}
void SlamSystem::publishKeyframe(const Frame::SharedPtr &frame) {
OUTPUT_FOR_EACH(publishKeyframe(frame))
}
void SlamSystem::publishCurrentKeyframe() {
if (currentKeyFrame()) {
OUTPUT_FOR_EACH(publishKeyframe(currentKeyFrame()->frame()))
OUTPUT_FOR_EACH(publishPointCloud(currentKeyFrame()->frame()))
} else {
LOG(DEBUG) << "No currentKeyframe, unable to publish";
}
}