Program Listing for File KeyFrameGraph.cpp

Return to documentation for file (lib/GlobalMapping/KeyFrameGraph.cpp)

#include <boost/thread/shared_lock_guard.hpp>

#include "GlobalMapping/KeyFrameGraph.h"
#include "DataStructures/Frame.h"

#include <g2o/core/sparse_optimizer.h>
#include <g2o/solvers/pcg/linear_solver_pcg.h>
#include <g2o/solvers/csparse/linear_solver_csparse.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/solver.h>
#include <g2o/core/optimization_algorithm_dogleg.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/core/robust_kernel_impl.h>
#include <g2o/core/estimate_propagator.h>
#include <g2o/core/sparse_optimizer_terminate_action.h>

#include "opencv2/opencv.hpp"

#include <g2o/types/sim3/sim3.h>
#include "GlobalMapping/g2oTypeSim3Sophus.h"


#include "IOWrapper/ImageDisplay.h"

// for mkdir
#include <sys/types.h>
#include <sys/stat.h>
// for iterating over files in a directory
#include <dirent.h>
#include <queue>

#include <iostream>
#include <fstream>

#include "util/globalFuncs.h"

namespace lsd_slam
{


KFConstraintStruct::~KFConstraintStruct()
{
    if(edge != 0)
        delete edge;
}

KeyFrameGraph::KeyFrameGraph()
: nextEdgeId(0)
{
    typedef g2o::BlockSolver_7_3 BlockSolver;
    typedef g2o::LinearSolverCSparse<BlockSolver::PoseMatrixType> LinearSolver;
    //typedef g2o::LinearSolverPCG<BlockSolver::PoseMatrixType> LinearSolver;
    LinearSolver* solver = new LinearSolver();
    BlockSolver* blockSolver = new BlockSolver( std::unique_ptr<LinearSolver>(solver));
    g2o::OptimizationAlgorithmLevenberg* algorithm = new g2o::OptimizationAlgorithmLevenberg(std::unique_ptr<BlockSolver>(blockSolver));
    graph.setAlgorithm(algorithm);

  graph.setVerbose(false); // printOptimizationInfo
    solver->setWriteDebug(true);
    blockSolver->setWriteDebug(true);
    algorithm->setWriteDebug(true);


    totalPoints=0;
    totalEdges=0;
    totalVertices=0;


}

KeyFrameGraph::~KeyFrameGraph()
{
    // deletes edges
    for (KFConstraintStruct* edge : newEdgeBuffer)
        delete edge;    // deletes the g2oedge, which deletes the kernel.

    // deletes keyframes (by deleting respective shared pointers).

    idToKeyFrame.clear();
    //allFramePoses.clear();
}


// void KeyFrameGraph::addFrame(const Frame::SharedPtr &frame)
// {
//
//  frame->pose->isRegisteredToGraph = true;
//
//  allFramePosesMutex.lock();
//  allFramePoses.push_back(frame->pose);
//  allFramePosesMutex.unlock();
//
//  // if( conf().SLAMEnabled )
//  // {
//  //  boost::shared_lock_guard<boost::shared_mutex> lock( idToKeyFrameMutex );
//  //  idToKeyFrame.insert(std::make_pair( kf->id(), kf ));
//  // }
// }

void KeyFrameGraph::dropKeyFrame(const KeyFrame::SharedPtr &kf)
{
    // {
    //  boost::shared_lock_guard< boost::shared_mutex > lock( allFramePosesMutex );
    //  for(auto p : allFramePoses)
    //  {
    //      if(p->frame.isTrackingParent( kf->frame() ) ) {
    //          p->frame.setTrackingParent( nullptr );
    //      }
    //  }
    // }

    {
        boost::shared_lock_guard< boost::shared_mutex > lock(idToKeyFrameMutex);
        idToKeyFrame.erase(kf->id());
    }
}

void KeyFrameGraph::dumpMap(std::string folder)
{
    printf("DUMP MAP: dumping to %s\n", folder.c_str());

    keyframesAllMutex.lock_shared();
    char buf[100];
    int succ = system(("rm -rf "+folder).c_str());
    succ += system(("mkdir "+folder).c_str());

    //
    // for(unsigned int i=0;i<keyframesAll.size();i++)
    // {
    //  snprintf(buf, 100, "%s/depth-%d.png", folder.c_str(), i);
    //  cv::imwrite(buf, getDepthRainbowPlot(keyframesAll[i].get(), 0));
    //
    //  snprintf(buf, 100, "%s/frame-%d.png", folder.c_str(), i);
    //  cv::imwrite(buf, cv::Mat(keyframesAll[i]->height(), keyframesAll[i]->width(),CV_32F,keyframesAll[i]->image()));
    //
    //  snprintf(buf, 100, "%s/var-%d.png", folder.c_str(), i);
    //  cv::imwrite(buf, getVarRedGreenPlot(keyframesAll[i]->idepthVar(),keyframesAll[i]->image(),keyframesAll[i]->width(),keyframesAll[i]->height()));
    // }
    //
    //
    // int i = keyframesAll.size()-1;
    // Util::displayImage("VAR PREVIEW", getVarRedGreenPlot(keyframesAll[i]->idepthVar(),keyframesAll[i]->image(),keyframesAll[i]->width(),keyframesAll[i]->height()));

    printf("DUMP MAP (succ %d): dumped %d depthmaps\n", succ,  (int)keyframesAll.size());

    Eigen::MatrixXf res, resD, resP, huber, usage, consistency, distance, error;
    Eigen::VectorXf meanRootInformation, usedPixels;

    res.resize(keyframesAll.size(), keyframesAll.size());
    resD.resize(keyframesAll.size(), keyframesAll.size());
    resP.resize(keyframesAll.size(), keyframesAll.size());
    usage.resize(keyframesAll.size(), keyframesAll.size());
    consistency.resize(keyframesAll.size(), keyframesAll.size());
    distance.resize(keyframesAll.size(), keyframesAll.size());
    error.resize(keyframesAll.size(), keyframesAll.size());
    meanRootInformation.resize(keyframesAll.size());
    usedPixels.resize(keyframesAll.size());
    res.setZero();
    resD.setZero();
    resP.setZero();
    usage.setZero();
    consistency.setZero();
    distance.setZero();
    error.setZero();
    meanRootInformation.setZero();
    usedPixels.setZero();

    // for(unsigned int i=0;i<keyframesAll.size();i++)
    // {
    //  meanRootInformation[i] = keyframesAll[i]->meanInformation;
    //  usedPixels[i] = keyframesAll[i]->numPoints / (float)keyframesAll[i]->numMappablePixels;
    // }
    //
    // edgesListsMutex.lock_shared();
    // for(unsigned int i=0;i<edgesAll.size();i++)
    // {
    //  KFConstraintStruct* e = edgesAll[i];
    //
    //  res(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->meanResidual;
    //  resD(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->meanResidualD;
    //  resP(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->meanResidualP;
    //  usage(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->usage;
    //  consistency(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->reciprocalConsistency;
    //  distance(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->secondToFirst.translation().norm();
    //  error(e->firstFrame->idxInKeyframes, e->secondFrame->idxInKeyframes) = e->edge->chi2();
    // }
    // edgesListsMutex.unlock_shared();
     keyframesAllMutex.unlock_shared();


    std::ofstream fle;

    fle.open(folder+"/residual.txt");
    fle << res;
    fle.close();

    fle.open(folder+"/residualD.txt");
    fle << resD;
    fle.close();

    fle.open(folder+"/residualP.txt");
    fle << resP;
    fle.close();

    fle.open(folder+"/usage.txt");
    fle << usage;
    fle.close();

    fle.open(folder+"/consistency.txt");
    fle << consistency;
    fle.close();

    fle.open(folder+"/distance.txt");
    fle << distance;
    fle.close();

    fle.open(folder+"/error.txt");
    fle << error;
    fle.close();

    fle.open(folder+"/meanRootInformation.txt");
    fle << meanRootInformation;
    fle.close();

    fle.open(folder+"/usedPixels.txt");
    fle << usedPixels;
    fle.close();

    printf("DUMP MAP: dumped %d edges\n", (int)edgesAll.size());
}



void KeyFrameGraph::addKeyFrame( const KeyFrame::SharedPtr &keyframe)
{
    CHECK( (bool)keyframe ) << "Received null keyframe";
    if(keyframe->frame()->pose->graphVertex != nullptr)
        return;

    _keyFrames.push_back( keyframe );

    // Insert vertex into g2o graph
    VertexSim3* vertex = new VertexSim3();
    vertex->setId(keyframe->id());

    Sophus::Sim3d camToWorld_estimate = keyframe->frame()->getCamToWorld();

    if(!keyframe->frame()->hasTrackingParent())
        vertex->setFixed(true);

    vertex->setEstimate(camToWorld_estimate);
    vertex->setMarginalized(false);

    keyframe->frame()->pose->graphVertex = vertex;

    newKeyframesBuffer.push_back(keyframe);

}

void KeyFrameGraph::insertConstraint(KFConstraintStruct* constraint)
{
    EdgeSim3* edge = new EdgeSim3();
    edge->setId(nextEdgeId);
    ++ nextEdgeId;

    totalEdges++;

    edge->setMeasurement(constraint->secondToFirst);
    edge->setInformation(constraint->information);
    edge->setRobustKernel(constraint->robustKernel);

    edge->resize(2);
    assert(constraint->firstFrame->frame()->pose->graphVertex != nullptr);
    edge->setVertex(0, constraint->firstFrame->frame()->pose->graphVertex);
    assert(constraint->secondFrame->frame()->pose->graphVertex != nullptr);
    edge->setVertex(1, constraint->secondFrame->frame()->pose->graphVertex);

    constraint->edge = edge;
    newEdgeBuffer.push_back(constraint);


    constraint->firstFrame->neighbors.insert(constraint->secondFrame);
    constraint->secondFrame->neighbors.insert(constraint->firstFrame);

    for(int i=0;i<totalVertices;i++)
    {
        //shortestDistancesMap
    }



    edgesListsMutex.lock();
    constraint->idxInAllEdges = edgesAll.size();
    edgesAll.push_back(constraint);
    edgesListsMutex.unlock();
}


bool KeyFrameGraph::addElementsFromBuffer()
{
    std::lock_guard< std::mutex > lock( newKeyFrameMutex );

    bool added = false;

    keyframesForRetrackMutex.lock();
    for (auto newKF : newKeyframesBuffer)
    {
        graph.addVertex(newKF->frame()->pose->graphVertex);
        CHECK(!newKF->frame()->pose->isInGraph) << "Keyframe" << newKF->id() << " was already in the graph when attempted to add it";
        newKF->frame()->pose->isInGraph = true;

        keyframesForRetrack.push_back(newKF);

        added = true;
    }
    keyframesForRetrackMutex.unlock();

    newKeyframesBuffer.clear();
    for (auto edge : newEdgeBuffer)
    {
        graph.addEdge(edge->edge);
        added = true;
    }
    newEdgeBuffer.clear();

    return added;
}

int KeyFrameGraph::optimize(int num_iterations)
{
    // Abort if graph is empty, g2o shows an error otherwise
    if (graph.edges().size() == 0)
        return 0;

    graph.setVerbose(false); // printOptimizationInfo
    graph.initializeOptimization();


    return graph.optimize(num_iterations, false);

}



void KeyFrameGraph::calculateGraphDistancesToFrame(const KeyFrame::SharedPtr &startFrame, std::unordered_map< KeyFrame::SharedPtr, int > &distanceMap)
{
    distanceMap.insert(std::make_pair(startFrame, 0));

    std::multimap< int, KeyFrame::SharedPtr > priorityQueue;
    priorityQueue.insert(std::make_pair(0, startFrame));

    while (! priorityQueue.empty())
    {
        auto it = priorityQueue.begin();
        int length = it->first;
        KeyFrame::SharedPtr frame( it->second );
        priorityQueue.erase(it);

        auto mapEntry = distanceMap.find(frame);

        if (mapEntry != distanceMap.end() && length > mapEntry->second)
        {
            continue;
        }

        for (auto neighbor : frame->neighbors)
        {
            auto neighborMapEntry = distanceMap.find(neighbor);

            if (neighborMapEntry != distanceMap.end() && length + 1 >= neighborMapEntry->second)
                continue;

            if (neighborMapEntry != distanceMap.end())
                neighborMapEntry->second = length + 1;
            else
                distanceMap.insert(std::make_pair(neighbor, length + 1));

            priorityQueue.insert(std::make_pair(length + 1, neighbor));
        }
    }
}

}