DBoW的编译和运行

本文最后更新于 2025年6月3日 晚上

本文主要分享了在Linux下DboW2和DBoW3的编译和示例运行。

安装依赖

  1. 安装 OpenCV 3.4.13

    OpenCV4因为安全性提升、解析器更复杂、兼容性增强等原因导致其读取*.yml文件的速度要远慢于OpenCV3。

  2. 安装Boost库(DBoW2需要):

    1
    2
    sudo apt-get update
    sudo apt-get install libboost-all-dev
  3. 完成。

DboW3

  1. 克隆代码:

    1
    2
    3
    cd your_floder
    git clone https://github.com/rmsalinas/DBow3.git
    cd DBow3
  2. (可选)在根目录的CMakeLists.txt中Line53 find_package(OpenCV REQUIRED) 前指定OpenCV的路径:

    1
    set(OpenCV_DIR /usr/local/opencv/opencv3413/share/OpenCV) 
  3. 编译代码:

    1
    2
    3
    4
    mkdir build
    cd build
    cmake .. -DBUILD_TESTS=ON
    make -j8
  4. 运行示例:

    1
    2
    # 把in.yml转存为DBoW3支持的二进制格式out.dbow以加快词袋的读取速度。
    ./tests/test_iobinary in.yml out.dbow
  5. 完成。

DBoW2

  1. 克隆代码:

    1
    2
    3
    4
    git clone https://github.com/raulmur/ORB_SLAM2.git
    cd ORB_SLAM2
    git fetch origin pull/21/head:pr-21
    git checkout pr-21

    后面只需要Thirdparty/下的DBoW2文件夹。

    这里使用了ORB-SLAM2中pr-21的修改后的DBoW2,其中添加了加载和保存二进制词袋的功能。主要修改文件为Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h,添加的内容为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    /**
    * Loads the vocabulary from a binary file
    * @param filename
    */
    bool loadFromBinaryFile(const std::string &filename);

    /**
    * Saves the vocabulary into a binary file
    * @param filename
    */
    void saveToBinaryFile(const std::string &filename) const;

    template<class TDescriptor, class F>
    bool TemplatedVocabulary<TDescriptor,F>::loadFromBinaryFile(const std::string &filename) {
    fstream f;
    f.open(filename.c_str(), ios_base::in|ios::binary);
    unsigned int nb_nodes, size_node;
    f.read((char*)&nb_nodes, sizeof(nb_nodes));
    f.read((char*)&size_node, sizeof(size_node));
    f.read((char*)&m_k, sizeof(m_k));
    f.read((char*)&m_L, sizeof(m_L));
    f.read((char*)&m_scoring, sizeof(m_scoring));
    f.read((char*)&m_weighting, sizeof(m_weighting));
    createScoringObject();

    m_words.clear();
    m_words.reserve(pow((double)m_k, (double)m_L + 1));
    m_nodes.clear();
    m_nodes.resize(nb_nodes+1);
    m_nodes[0].id = 0;
    char buf[size_node]; int nid = 1;
    while (!f.eof()) {
    f.read(buf, size_node);
    m_nodes[nid].id = nid;
    // FIXME
    const int* ptr=(int*)buf;
    m_nodes[nid].parent = *ptr;
    //m_nodes[nid].parent = *(const int*)buf;
    m_nodes[m_nodes[nid].parent].children.push_back(nid);
    m_nodes[nid].descriptor = cv::Mat(1, F::L, CV_8U);
    memcpy(m_nodes[nid].descriptor.data, buf+4, F::L);
    m_nodes[nid].weight = *(float*)(buf+4+F::L);
    if (buf[8+F::L]) { // is leaf
    int wid = m_words.size();
    m_words.resize(wid+1);
    m_nodes[nid].word_id = wid;
    m_words[wid] = &m_nodes[nid];
    }
    else
    m_nodes[nid].children.reserve(m_k);
    nid+=1;
    }
    f.close();
    return true;
    }

    template<class TDescriptor, class F>
    void TemplatedVocabulary<TDescriptor,F>::saveToBinaryFile(const std::string &filename) const {
    fstream f;
    f.open(filename.c_str(), ios_base::out|ios::binary);
    f.open ( filename.c_str (),ios_base::out|ios::binary);
    unsigned int nb_nodes = m_nodes.size();
    float _weight;
    unsigned int size_node = sizeof(m_nodes[0].parent) + F::L*sizeof(char) + sizeof(_weight) + sizeof(bool);
    f.write((char*)&nb_nodes, sizeof(nb_nodes));
    f.write((char*)&size_node, sizeof(size_node));
    f.write((char*)&m_k, sizeof(m_k));
    f.write((char*)&m_L, sizeof(m_L));
    f.write((char*)&m_scoring, sizeof(m_scoring));
    f.write((char*)&m_weighting, sizeof(m_weighting));
    for(size_t i=1; i<nb_nodes;i++) {
    const Node& node = m_nodes[i];
    f.write((char*)&node.parent, sizeof(node.parent));
    f.write((char*)node.descriptor.data, F::L);
    _weight = node.weight; f.write((char*)&_weight, sizeof(_weight));
    bool is_leaf = node.isLeaf(); f.write((char*)&is_leaf, sizeof(is_leaf)); // i put this one at the end for alignement....
    }
    f.close();
    }
  2. DBoW2/DBoW2/里添加demo.cpp文件,文件内容为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    /**
    * File: Demo.cpp
    * Date: November 2011
    * Author: Dorian Galvez-Lopez
    * Description: demo application of DBoW2
    * License: see the LICENSE.txt file
    */

    #include <iostream>
    #include <vector>
    #include <string>

    // DBoW2
    #include "FORB.h"
    #include "TemplatedVocabulary.h"

    // OpenCV
    #include <opencv2/core.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/features2d.hpp>


    using namespace DBoW2;
    using namespace std;

    //command line parser
    class CmdLineParser{int argc; char **argv; public: CmdLineParser(int _argc,char **_argv):argc(_argc),argv(_argv){} bool operator[] ( string param ) {int idx=-1; for ( int i=0; i<argc && idx==-1; i++ ) if ( string ( argv[i] ) ==param ) idx=i; return ( idx!=-1 ) ; } string operator()(string param,string defvalue="-1"){int idx=-1; for ( int i=0; i<argc && idx==-1; i++ ) if ( string ( argv[i] ) ==param ) idx=i; if ( idx==-1 ) return defvalue; else return ( argv[ idx+1] ); }};

    bool has_suffix(const std::string &str, const std::string &suffix) {
    std::size_t index = str.find(suffix, str.size() - suffix.size());
    return (index != std::string::npos);
    }

    int main(int argc,char **argv)
    {
    try{
    CmdLineParser cml(argc,argv);
    if (cml["-h"] || argc!=3){
    cerr<<"Usage: in.yml out.bin"<<endl;
    return -1;
    }
    DBoW2::TemplatedVocabulary<DBoW2::FORB::TDescriptor, DBoW2::FORB> voc;
    if (has_suffix(argv[1], ".txt")) {
    voc.loadFromTextFile(argv[1]);
    cout<<"loaded"<<endl;
    voc.saveToBinaryFile(argv[2]);
    cout<<"saved"<<endl;
    } else if (has_suffix(argv[1], ".yml")) {
    voc.load(argv[1]);
    cout<<"loaded"<<endl;
    voc.saveToBinaryFile(argv[2]);
    cout<<"saved"<<endl;
    } else {
    voc.loadFromBinaryFile(argv[1]);
    cout<<"loaded"<<endl;
    }
    }catch(std::exception &ex){
    cerr<<ex.what()<<endl;
    }

    return 0;
    }
  3. 修改根目录DBoW2/CMakeLists.txt文件:

    1
    2
    3
    4
    5
    6
    7
    # 在Line27 `find_package(OpenCV 3.0 QUIET)` 前指定OpenCV的路径:
    set(OpenCV_DIR /usr/local/opencv/opencv3413/share/OpenCV)

    # 在最后一行添加:
    add_executable(demo DBoW2/demo.cpp)
    target_link_libraries(demo DBoW2 ${OpenCV_LIBS})
    MESSAGE( STATUS "OPENCV_DIR= ${OpenCV_DIR} VERSION=${OpenCV_VERSION}" )
  4. 编译代码:

    1
    2
    3
    4
    5
    cd DBoW2
    mkdir build
    cd build
    cmake ..
    make -j8
  5. 运行示例:

    1
    ./demo in.yml out.bin
  6. 完成。


DBoW的编译和运行
http://zeyulong.com/posts/863b4e09/
作者
龙泽雨
发布于
2025年6月3日
许可协议