DBoW的编译和运行
本文最后更新于 2025年6月3日 晚上
本文主要分享了在Linux下DboW2和DBoW3的编译和示例运行。
安装依赖
-
OpenCV4因为安全性提升、解析器更复杂、兼容性增强等原因导致其读取
*.yml
文件的速度要远慢于OpenCV3。 -
安装Boost库(DBoW2需要):
1
2sudo apt-get update
sudo apt-get install libboost-all-dev -
完成。
DboW3
-
克隆代码:
1
2
3cd your_floder
git clone https://github.com/rmsalinas/DBow3.git
cd DBow3 -
(可选)在根目录的
CMakeLists.txt
中Line53find_package(OpenCV REQUIRED)
前指定OpenCV的路径:1
set(OpenCV_DIR /usr/local/opencv/opencv3413/share/OpenCV)
-
编译代码:
1
2
3
4mkdir build
cd build
cmake .. -DBUILD_TESTS=ON
make -j8 -
运行示例:
1
2# 把in.yml转存为DBoW3支持的二进制格式out.dbow以加快词袋的读取速度。
./tests/test_iobinary in.yml out.dbow -
完成。
DBoW2
-
克隆代码:
1
2
3
4git 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();
} -
在
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;
} -
修改根目录
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}" ) -
编译代码:
1
2
3
4
5cd DBoW2
mkdir build
cd build
cmake ..
make -j8 -
运行示例:
1
./demo in.yml out.bin
-
完成。
DBoW的编译和运行
http://zeyulong.com/posts/863b4e09/