1. 程式人生 > >《視覺SLAM十四講精品總結》12 迴環檢測建立字典

《視覺SLAM十四講精品總結》12 迴環檢測建立字典

 


這部分並不難,主要用到了一個詞袋模型(BoW),對兩幅影象的特徵點進行匹配。

建立字典:一個單詞是某一類特徵的集合,字典生成是個聚類問題,可使用K-meams演算法。

匹配相似性:暴力計算量太大,可用二分查詢提升效率,以及k叉樹表達字典(層次聚類)


目錄:

feature_training.cpp

loop_closure.cpp


feature_training.cpp

 #include "DBoW3/DBoW3.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <vector>
#include <string>

using namespace cv;
using namespace std;

/***************************************************
 * 本節演示瞭如何根據data/目錄下的十張圖訓練字典
 * ************************************************/

int main( int argc, char** argv )
{
    // 1.讀入10張影象
    cout<<"reading images... "<<endl;
    vector<Mat> images; 
    for ( int i=0; i<10; i++ )
    {
        string path = "./data/"+to_string(i+1)+".png";//to_string數值轉為字串
        images.push_back( imread(path) );
    }
    // 2.檢測ORB特徵點
    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 );
    }
    
    //3.建立字典
    cout<<"creating vocabulary ... "<<endl;
	//建立一個字典物件
    DBoW3::Vocabulary vocab;
	//呼叫create函式,用描述子陣列建立
    vocab.create( descriptors );
    cout<<"vocabulary info: "<<vocab<<endl;
	//save函式輸出字典壓縮包
    vocab.save( "vocabulary.yml.gz" );
    cout<<"done"<<endl;
    
    return 0;
}

基本流程:讀入照片、檢測ORB特徵點、建立字典

  • 載入影象,路徑的表達

    vector<Mat> images; 
    for ( int i=0; i<10; i++ )
    {
        string path = "./data/"+to_string(i+1)+".png";
        images.push_back( imread(path) );

    }

  • 建立字典部分

    DBoW3::Vocabulary vocab;//建立字典物件
    vocab.create( descriptors );//描述子作為內容
    vocab.save( "vocabulary.yml.gz" );//輸出字典壓縮包


loop_closure.cpp

#include "DBoW3/DBoW3.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <vector>
#include <string>

using namespace cv;
using namespace std;

/***************************************************
 * 本節演示瞭如何根據前面訓練的字典計算相似性評分
 * ************************************************/
int main( int argc, char** argv )
{
    // 1.讀入影象和字典庫
    cout<<"reading database"<<endl;
    DBoW3::Vocabulary vocab("./vocabulary.yml.gz");
    // DBoW3::Vocabulary vocab("./vocab_larger.yml.gz");  // use large vocab if you want: 
    if ( vocab.empty() )
    {
        cerr<<"Vocabulary does not exist."<<endl;
        return 1;
    }
    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) );
    }
    
    // NOTE: in this case we are comparing images with a vocabulary generated by themselves, this may leed to overfitting.  
    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 );
    }
    
    // we can compare the images directly or we can compare one image to a database 
    // images :
	//影象與影象對比
    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;
			//transform函式將影象轉為描述向量
            vocab.transform( descriptors[j], v2 );
			//score函式,傳入兩個詞袋描述向量,取得相似性得分
            double score = vocab.score(v1, v2);
            cout<<"image "<<i<<" vs image "<<j<<" : "<<score<<endl;
        }
        cout<<endl;
    }
    
    // 用字典建立資料集
    cout<<"comparing images with database "<<endl;
	// 建立資料集,把所有描述向量加進去,query函式輸出與所有圖匹配結果
    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);      // max result=4
        cout<<"searching for image "<<i<<" returns "<<ret<<endl<<endl;
    }
    cout<<"done."<<endl;
}
  • 讀入生成的字典庫    DBoW3::Vocabulary vocab("./vocabulary.yml.gz");
  • 匹配時暴力匹配所有影象

/** * 影象與影象之間的檢測比較簡單:

* 根據影象的描述子,呼叫transform()函式將影象轉化成描述向量,

* 根據描述向量,呼叫score()函式求兩張影象相似性得分。 

  • 影象與整個資料集匹配

*字典建立資料集

*所有影象描述子加進去

*利用query函式輸出各個圖匹配結果