opencv feature2D模塊(二)

  • ORB特徵提取
    ORB是ORiented Brief的簡稱,是brief算法的改進版本。ORB是在2011年《ORB:an efficient alternative to SIFT or SURF》文章中被提出。我們首先認識Brief描述子。
    Brief是Binary Robust Independent Elementary Features的縮寫。這個特徵是在ECCV2010上提出,主要思路就是在特徵點附近隨機選取若干點對,將這些點對的灰度值的大小,組合成一個二進制串,並將這個二進制串作爲該特徵點的特徵描述子。
    Brief的優點在於速度,而缺點也很多:
    不具備旋轉不變性和尺度不變性,對噪聲敏感。
    ORB算法就是爲了解決旋轉不變性和噪聲敏感,對於尺度不變性沒有更正。因爲他的特徵點是基於FAST的,而FAST本身就不具有尺度不變性,這種只求速度的特徵描述子,一般都是用在實時的視頻處理中,這樣可以通過跟蹤還有一些啓發式的策略來解決尺度不變性的問題。

OpenCV中已經將其實現:

    OrbFeatureDetector detect;
    detect.detect();
    OrbDescriptorExtractor extract;
    extract.detect();

OrbFeatureDetector OrbFeatureDetector 是一個typedef的類型,等價

我們還需要重點研究下:FLANN
以下部分來自:
http://blog.csdn.net/jasonding1354/article/details/44038539
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_::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

include

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;

}
“`

發佈了83 篇原創文章 · 獲贊 12 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章