標籤:電腦視覺
FLANN介紹
FLANN庫全稱是Fast Library for Approximate Nearest Neighbors,它是目前最完整的(近似)最近鄰開源庫。不但實現了一系列尋找演算法,還包含了一種自動選取最快演算法的機制。
flann::Index_類
該類模板是最近鄰索引類,該類用於抽象不同類型的最近鄰搜尋的索引。
以下是flann::Index_類的聲明:
template <typename T>class#ifndef _MSC_VER FLANN_DEPRECATED#endif Index_ {public: typedef typename L2<T>::ElementType ElementType; typedef typename L2<T>::ResultType DistanceType; Index_(const Mat& features, const ::cvflann::IndexParams& params); ~Index_(); void knnSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& params); void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params); int radiusSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& params); int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params); void save(std::string filename) { if (nnIndex_L1) nnIndex_L1->save(filename); if (nnIndex_L2) nnIndex_L2->save(filename); } int veclen() const { if (nnIndex_L1) return nnIndex_L1->veclen(); if (nnIndex_L2) return nnIndex_L2->veclen(); } int size() const { if (nnIndex_L1) return nnIndex_L1->size(); if (nnIndex_L2) return nnIndex_L2->size(); } ::cvflann::IndexParams getParameters() { if (nnIndex_L1) return nnIndex_L1->getParameters(); if (nnIndex_L2) return nnIndex_L2->getParameters(); } FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters() { if (nnIndex_L1) return nnIndex_L1->getIndexParameters(); if (nnIndex_L2) return nnIndex_L2->getIndexParameters(); }private: // providing backwards compatibility for L2 and L1 distances (most common) ::cvflann::Index< L2<ElementType> >* nnIndex_L2; ::cvflann::Index< L1<ElementType> >* nnIndex_L1;};
建構函式flann::Index_::Index_
flann::Index_<T>::Index_(const Mat& features, const IndexParams& params)/*Parameters: features – Matrix of containing the features(points) to index. The size of the matrix is num_features x feature_dimensionality and the data type of the elements in the matrix must coincide with the type of the index.params – Structure containing the index parameters. The type of index that will be constructed depends on the type of this parameter. See the description.*/
參數features,是包含用於構建索引的特徵的矩陣;參數params,是包含索引參數的結構。
該建構函式所執行個體的快速搜尋結構是根據參數params所指定的特定演算法來構建的。params是由IndexParams的衍生類別的引用。
其中:
* LinearIndexParams,該結構對應的索引進行線性、暴力(brute-force)的搜尋。
- KDTreeIndexParams,該方法對應的索引結構由一組隨機kd樹構成(randomized kd-trees),它可以平行地進行搜尋。
struct KDTreeIndexParams : public IndexParams{ KDTreeIndexParams( int trees = 4 );};//trees:The number of parallel kd-trees to use. Good values are in the range
- KMeansIndexParams,該方法對應的索引結構是一個層次k均值樹(a hierarchical k-means tree)。
struct KMeansIndexParams : public IndexParams{ KMeansIndexParams( int branching = 32, int iterations = 11, flann_centers_init_t centers_init = CENTERS_RANDOM, float cb_index = 0.2 );};
- CompositeIndexParams,該結構結合隨機kd樹和層次k均值樹來構建索引。
struct CompositeIndexParams : public IndexParams{ CompositeIndexParams( int trees = 4, int branching = 32, int iterations = 11, flann_centers_init_t centers_init = CENTERS_RANDOM, float cb_index = 0.2 );};
- LshIndexParams,該結構使用multi-probe LSH方法建立索引(Multi-Probe LSH: Efficient Indexing for High-Dimensional Similarity Search by Qin Lv, William Josephson, Zhe Wang, Moses Charikar, Kai Li., Proceedings of the 33rd International Conference on Very Large Data Bases (VLDB). Vienna, Austria. September 2007)。
struct LshIndexParams : public IndexParams{ LshIndexParams( unsigned int table_number, unsigned int key_size, unsigned int multi_probe_level );};
- AutotunedIndexParams,該結構是根據資料自動選取最優的索引類型來提供最好的效能。
struct AutotunedIndexParams : public IndexParams{ AutotunedIndexParams( float target_precision = 0.9, float build_weight = 0.01, float memory_weight = 0, float sample_fraction = 0.1 );};
- SavedIndexParams,該結構用於載入存放在硬碟的索引結構。
struct SavedIndexParams : public IndexParams{ SavedIndexParams( std::string filename );};//filename:The filename in which the index was saved.
flann::Index_::knnSearch
根據給定的查詢資料,利用構建的索引來執行k近鄰搜尋。
void flann::Index_<T>::knnSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& params)void flann::Index_<T>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params)
flann::Index_::radiusSearch
根據給定的查詢資料,執行基於半徑的最近鄰搜尋。
int flann::Index_<T>::radiusSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& params)int flann::Index_<T>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& params)
flann::Index_::save
將索引存成檔案。
void flann::Index_<T>::save(std::string filename)
flann::Index_::getIndexParameters
得到索引參數。
const IndexParams* flann::Index_<T>::getIndexParameters()
利用FLANN進行特徵點匹配
接下來給出一段小的官方樣本程式,使用 FlannBasedMatcher 介面以及函數 FLANN 實現快速高效匹配。
這段代碼的主要流程分為以下幾部分:
- 使用SURF特徵提取關鍵點
- 計算SURF特徵描述子
- 使用FLANN匹配器進行描述子向量匹配
OpenCV中KeyPoint Matching的方法
OpenCV提供了 兩種Matching方式 :
? Brute-force matcher (cv::BFMatcher)
? Flann-based matcher (cv::FlannBasedMatcher)
Brute-force matcher就是用暴力方法找到點集一中每個descriptor在點集二中距離最近的 descriptor;
Flann-based matcher 使用快速近似最近鄰搜尋演算法尋找。
為了提高檢測速度,你可以調用matching函數前,先訓練一個matcher。訓練過程可以首先使用cv:: FlannBasedMatcher來最佳化,為 descriptor建立索引樹,這種操作將在匹配大量資料時發揮巨大作用(比如在上百幅映像的資料集中尋找匹配映像)。而 Brute-force matcher在這個過程並不進行操作,它只是將train descriptors儲存在記憶體中。
程式碼範例
#include <stdio.h>#include <iostream>#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"#include "opencv2/nonfree/features2d.hpp"using namespace cv;/** @function main */int main( int argc, char** argv ){ Mat img_1 = imread("box.png", CV_LOAD_IMAGE_GRAYSCALE ); Mat img_2 = imread("box_in_scene.png", CV_LOAD_IMAGE_GRAYSCALE ); if( !img_1.data || !img_2.data ) { std::cout<< " --(!) Error reading images " << std::endl; return -1; } //-- Step 1: Detect the keypoints using SURF Detector int minHessian = 400; SurfFeatureDetector detector( minHessian ); std::vector<KeyPoint> keypoints_1, keypoints_2; detector.detect( img_1, keypoints_1 ); detector.detect( img_2, keypoints_2 ); //-- Step 2: Calculate descriptors (feature vectors) SurfDescriptorExtractor extractor; Mat descriptors_1, descriptors_2; extractor.compute( img_1, keypoints_1, descriptors_1 ); extractor.compute( img_2, keypoints_2, descriptors_2 ); //-- Step 3: Matching descriptor vectors using FLANN matcher FlannBasedMatcher matcher; std::vector< DMatch > matches; matcher.match( descriptors_1, descriptors_2, matches ); double max_dist = 0; double min_dist = 100; //-- Quick calculation of max and min distances between keypoints for( int i = 0; i < descriptors_1.rows; i++ ) { double dist = matches[i].distance; if( dist < min_dist ) min_dist = dist; if( dist > max_dist ) max_dist = dist; } printf("-- Max dist : %f \n", max_dist ); printf("-- Min dist : %f \n", min_dist ); //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist ) //-- PS.- radiusMatch can also be used here. std::vector< DMatch > good_matches; for( int i = 0; i < descriptors_1.rows; i++ ) { if( matches[i].distance < 2*min_dist ) { good_matches.push_back( matches[i]); } } //-- Draw only "good" matches Mat img_matches; drawMatches( img_1, keypoints_1, img_2, keypoints_2, good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); //-- Show detected matches imshow( "Good Matches", img_matches ); for( int i = 0; i < good_matches.size(); i++ ) { printf( "-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); } waitKey(0); return 0;}
實驗結果
參考資料
flann項目首頁
flann手冊 pdf
學習OpenCV——Surf(特徵點篇)&flann
OpenCV documentation:Fast Approximate Nearest Neighbor Search
轉載請註明作者Jason Ding及其出處
Github部落客頁(http://jasonding1354.github.io/)
CSDN部落格(http://blog.csdn.net/jasonding1354)
簡書首頁(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
【電腦視覺】OpenCV的最近鄰開源庫FLANN