意义:1. 保证估计的轨迹和地图在长时间下的正确性
2. 可以利用回环检测进行重定位
基于外观的检测方法
特点:基于外观的方法。与前后端的估计都无关,仅考虑两幅图像的相似性。
核心问题:如何计算图像的相似性
引入:准确率和召回率
准确率:算法提取的所有回环中确实是真实回环的概率
召回率:所有真实回环被正确检测出来的概率
这两个率通常是一对矛盾:
词袋模型
步骤
1. 构建字典
2. 确定图像里出现了那些word。用单词出现的情况转化成向量的描述。(假如“人”“车”“狗”是记录在字典里的.A=(1,1,0)可以表述图像里有人,有狗)
3. 比较上一步描述的相似程度。求差有不同的方法:如
构建字典
K-means法
基于K-means的k叉树法
该字典一共可以容纳个单词。在查询某个特征给定的单词时,只需将它与每个中间节点的聚类比较(一共k次)。
代码
1. 查找特征点
2. DBow3::Vocabulary vocab;
vocab.create(descriptors);
int main( int argc, char** argv ) {
// read the image
cout<<"reading images... "<<endl;
vector<Mat> images;
for ( int i=0; i<10; i++ )
{
string path = "./data/"+to_string(i+1)+".png";
images.push_back( imread(path) );
}
// detect ORB features
cout<<"detecting ORB features ... "<<endl;
Ptr< Feature2D > detector = ORB::create();
vector<Mat> descriptors;
for ( Mat& image:images )
{
vector<KeyPoint> keypoints;
Mat descriptor;
detector->detectAndCompute( image, Mat(), keypoints, descriptor );
descriptors.push_back( descriptor );
}
// create vocabulary
cout<<"creating vocabulary ... "<<endl;
DBoW3::Vocabulary vocab;
vocab.create( descriptors );
cout<<"vocabulary info: "<<vocab<<endl;
vocab.save( "vocabulary.yml.gz" );
cout<<"done"<<endl;
return 0;
}
相似度计算
1. 已有建立好的字典进行权重
我们在建立字典的时候计算IDF:。 n是所有特征的数量,子叶点的特征点数量是n_i
因此,该图像的权重为:
2. 两个图像进行对比:
其中一种范数:
代码
1. 读取字典
DBoW3::Vocabulary vocab("./vocabulary.yml.gz");
2. 读取图像
vector<Mat> images;
for (int i = 0; i < 10; i++) {
string path = "./data/" + to_string(i + 1) + ".png";
images.push_back(imread(path));
}
3. 检测图像的特征
cout << "detecting ORB features ... " << endl;
Ptr<Feature2D> detector = ORB::create();
vector<Mat> descriptors;
for (Mat &image:images) {
vector<KeyPoint> keypoints;
Mat descriptor;
detector->detectAndCompute(image, Mat(), keypoints, descriptor);
descriptors.push_back(descriptor);
}
4. 对比图像
方法一:图像与图像直接对比
其中,把特征转化为BoW:vocab.transform(descriptors[i],v1);
得出分数:double score = vocab.score(v1, v2);
cout << "comparing images with images " << endl;
for (int i = 0; i < images.size(); i++) {
DBoW3::BowVector v1;
vocab.transform(descriptors[i], v1);
for (int j = i; j < images.size(); j++) {
DBoW3::BowVector v2;
vocab.transform(descriptors[j], v2);
double score = vocab.score(v1, v2);
cout << "image " << i << " vs image " << j << " : " << score << endl;
}
cout << endl;
}
方法二:图像与数据库里的对比(数据库在这个例子其实也是所有图像转化来的)
cout << "comparing images with database " << endl;
DBoW3::Database db(vocab, false, 0);
for (int i = 0; i < descriptors.size(); i++)
db.add(descriptors[i]);
cout << "database info: " << db << endl;
for (int i = 0; i < descriptors.size(); i++) {
DBoW3::QueryResults ret;
db.query(descriptors[i], ret, 4); // 在数据库里找4个最相似的图像
cout << "searching for image " << i << " returns " << ret << endl << endl;
}