lsd-slam源码解读第二篇:DataStructures

本文是lsd-slam源码解读系列的第二篇,重点探讨了数据结构,包括Frame和FramePoseStruct。文章介绍了Frame类中的内存管理、帧数据结构及其初始化,以及FramePoseStruct与优化相关数据的细节。通过对源码的分析,揭示了帧的内存管理机制、图像金字塔构建和深度估计等关键概念。
摘要由CSDN通过智能技术生成

lsd-slam源码解读第二篇:DataStructures


第一篇: lsd-slam源码解读第一篇:Sophus/sophus

在进入具体算法之前,我觉得有必要先明白内部数据是怎样储存的,所以第一篇之后的内容自然是数据结构,这些这些数据包括图像,深度预测,帧的ID,以及变换矩阵等等,如果你不太清楚变换矩阵(包括平移,旋转等)是什么,请看我写的源码解读第一篇的内容


最科学的欣赏源码方式,必然是先看内存管理,即进入文件夹下的第二个文件FrameMemory.h
这个文件只有一个类FrameMemory,接口也不多,如下:

class FrameMemory
{
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    static FrameMemory& getInstance();
    float* getFloatBuffer(unsigned int size);
    void* getBuffer(unsigned int sizeInByte);
    void returnBuffer(void* buffer);


    boost::shared_lock<boost::shared_mutex> activateFrame(Frame* frame);
    void deactivateFrame(Frame* frame);
    void pruneActiveFrames();

    void releaseBuffes();
private:
    FrameMemory();
    void* allocateBuffer(unsigned int sizeInByte);

    boost::mutex accessMutex;
    std::unordered_map< void*, unsigned int > bufferSizes;
    std::unordered_map< unsigned int, std::vector< void* > > availableBuffers;


    boost::mutex activeFramesMutex;
    std::list<Frame*> activeFrames;
};

这个类偷偷地管理了每一帧的所有内存,第一个函数是getINstance();
注意到构造函数被私有化,显然这是初始化对象的函数,转到实现

FrameMemory& FrameMemory::getInstance()
{
    static FrameMemory theOneAndOnly;
    return theOneAndOnly;
}

这个函数实现就两行,你会发现内部维护的是一个static的对象,然后返回这个对象,也就是说,一个进程里面,有且仅有一个FrameMemory的对象

void* FrameMemory::getBuffer(unsigned int sizeInByte)
{
    boost::unique_lock<boost::mutex> lock(accessMutex);

    if (availableBuffers.count(sizeInByte) > 0)
    {
        std::vector< void* >& availableOfSize = availableBuffers.at(sizeInByte);
        if (availableOfSize.empty())
        {
            void* buffer = allocateBuffer(sizeInByte);
//          assert(buffer != 0);
            return buffer;
        }
        else
        {
            void* buffer = availableOfSize.back();
            availableOfSize.pop_back();
//          assert(buffer != 0);
            return buffer;
        }
    }
    else
    {
        void* buffer = allocateBuffer(sizeInByte);
//      assert(buffer != 0);
        return buffer;
    }
}

float* FrameMemory::getFloatBuffer(unsigned int size)
{
    return (float*)getBuffer(sizeof(float) * size);
}
    void* FrameMemory::allocateBuffer(unsigned int size)
{
    void* buffer = Eigen::internal::aligned_malloc(size);
    bufferSizes.insert(std::make_pair(buffer, size));
    return buffer;
}

这都是类中的函数,明显的是这三个函数是同一组的,因为getFloatBuffer明显调用了getBuffer这个函数
下面详细介绍一下getBuffer
首先进入这个函数的时候,直接调用boost里面的互斥锁,把这段函数里面的这段内存锁上了
这里会用到两个成员变量:

std::unordered_map< void*, unsigned int > bufferSizes;
std::unordered_map< unsigned int, std::vector< void* > > availableBuffers;

从字面上来说,这是两个无序映射
我上c++官网上查了下,实际上就是hash映射(http://www.cplusplus.com/referece/unordered_map/unordered_map/)

判断可用buffer中是否有sizeInByte这个大小的内存,如果有,那么返回1,没有返回0,所以,搜索到会进入if内部,否则进入else内部
进入if内部:首先是获取sizeInByte所对应的value的引用,也就是需要的内存的首地址,之后会判断

  • 如果是空的,那么会调用allocateBUffer申请一段内存,注意在allocateBuffer内部调用了Eigen的内存管理函数(底层实际上还是malloc,如果失败会抛出一个throw_std_bad_alloc),之后做一个映射,把buffer的首地址和尺寸映射起来,之后返回buffer的首地址,这样便可以得到一个buffer
  • 如果不是空,那么直接得到一个那个尺寸的内存,然后返回

进入else : 如果没有这个尺寸的内存,就调用allocateBuffer申请一段,之后返回


void FrameMemory::releaseBuffes()
{
    boost::unique_lock<boost::mutex> lock(accessMutex);
    int total = 0;


    for(auto p : availableBuffers)
    {
        if(printMemoryDebugInfo)
            printf("deleting %d buffers of size %d!\n", (int)p.second.size(), (int)p.first);

        total += p.second.size() * p.first;

        for(unsigned int i=0;i<p.second.size();i++)
        {
            Eigen::internal::aligned_free(p.second[i]);
            bufferSizes.erase(p.second[i]);
        }

        p.second.clear();
    }
    availableBuffers.clear();

    if(printMemoryDebugInfo)
        printf("released %.1f MB!\n", total / (1000000.0f));
}

void FrameMemory::returnBuffer(void* buffer)
{
    if(buffer==0) return;

    boost::unique_lock<boost::mutex> lock(accessMutex);

    unsigned int size = bufferSizes.at(buffer);
    //printf("returnFloatBuffer(%d)\n", size);
    if (availableBuffers.count(size) > 0)
        availableBuffers.at(size).push_back(buffer);
    else
    {
        std::vector< void* > availableOfSize;
        availableOfSize.push_back(buffer);
        availableBuffers.insert(std::make_pair(size, availableOfSize));
    }
}

有申请就有释放,以上两个函数是用来释放内存的,returnBuffer只是把内存还回去(放入map中),而真正释放是releaseBuffer,这里就不细讲了

还有三个函数,分别是

boost::shared_lock<boost::shared_mutex> activateFrame(Frame* frame);
void deactivateFrame(Frame* frame);
void pruneActiveFrames();

他们都是对成员std::list

Frame

帧这玩意儿贯穿始终,是slam中最基本的数据结构,我觉得想要理解这个类,应该从类中的结构体Data开始

struct Data
{
    int id;

    int width[PYRAMID_LEVELS], height[PYRAMID_LEVELS];

    Eigen::Matrix3f K[PYRAMID_LEVELS], KInv[PYRAMID_LEVELS];
    float fx[PYRAMID_LEVELS], fy[PYRAMID_LEVELS], cx[PYRAMID_LEVELS], cy[PYRAMID_LEVELS];
    float fxInv[PYRAMID_LEVELS], fyInv[PYRAMID_LEVELS],
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值