【计算机视觉】OpenCV的最近邻开源库FLANN

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 实现快速高效匹配。

这段代码的主要流程分为以下几部分:

  1. 使用SURF特征提取关键点
  2. 计算SURF特征描述子
  3. 使用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)

时间: 2024-08-05 02:35:07

【计算机视觉】OpenCV的最近邻开源库FLANN的相关文章

快速近似最近邻搜索库 FLANN - Fast Library for Approximate Nearest Neighbors

What is FLANN? FLANN is a library for performing fast approximate nearest neighbor searches in high dimensional spaces. It contains a collection of algorithms we found to work best for nearest neighbor search and a system for automatically choosing t

计算机视觉、机器学习等开源库网站链接

http://rogerioferis.com/VisualRecognitionAndSearch2014/Resources.html http://www.cnblogs.com/einyboy/p/3594432.html 持续跟新 可以看看这个 http://blog.csdn.net/workerwu/article/details/46537849 场景识别: SegNet: A Deep Convolutional Encoder-Decoder Architecture for

介绍n款计算机视觉库/人脸识别开源库/软件

计算机视觉库 OpenCV OpenCV是Intel®开源计算机视觉库.它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法. OpenCV 拥有包括 300 多个C函数的跨平台的中.高层 API.它不依赖于其它的外部库——尽管也可以使用某些外部库. OpenCV 对非商业... 人脸识别 faceservice.cgi faceservice.cgi 是一个用来进行人脸识别的 CGI 程序, 你可以通过上传图像,然后该程序即告诉你人脸的大概坐标位置.face

人脸检测——基于OpenCV等开源库

一.人脸检测简介 人脸检测是自动人脸识别系统中的一个关键环节.早期的人脸识别研究主要针对具有较强约束条件的人脸图象(如无背景的图象),往往假设人脸位置一直或者容易获得,因此人脸检测问题并未受到重视.随着电子商务等应用的发展,人脸识别成为最有潜力的生物身份验证手段,这种应用背景要求自动人脸识别系统能够对一般图象具有一定的识别能力,由此所面临的一系列问题使得人脸检测开始作为一个独立的课题受到研究者的重视.今天,人脸检测的应用背景已经远远超出了人脸识别系统的范畴,在基于内容的检索.数字视频处理.视频检

opencv开源库

opencv是开源库 在Windows下编译扩展OpenCV 3.1.0 + opencv_contrib 为什么要CMake,这里我陈述自己的想法,作为一个刚使用opencv库的小白来说,有以下大概三点内容 1.由于在学习图像处理滤波器中,需要用到各种边缘保护滤波器(EPS)算法,但是这些算法在OpenCV 3.1.0的Release版本中存在很少,因为他们把大量的算法存放在opencv_contrib目录下面的未稳定功能模块里的ximgproc文件夹下,所以如果我们想要使用这个目录的功能,就

C++开源库,欢迎补充

C++在“商业应用”方面,曾经是天下第一的开发语言,但这一桂冠已经被java抢走多年.因为当今商业应用程序类型,已经从桌面应用迅速转移成Web应 用.当Java横行天下之后,MS又突然发力,搞出C#语言,有大片的曾经的C++程序员,以为C++要就此沉沦,未料,这三年来,C++的生命力突然被 严重地增强了.主力原因就是开源的软件.基础软件(比如并发原生支持,比如Android必定要推出原生的SDK).各种跨平台应用的出现. 开源C++库必须具有以下特点:必须是成熟的产品.跨平台的产品.相对通用的库

C++开源库大全(转)

程序员要站在巨人的肩膀上,C++拥有丰富的开源库,这里包括:标准库.Web应用框架.人工智能.数据库.图片处理.机器学习.日志.代码分析等. 标准库 C++ Standard Library:是一系列类和函数的集合,使用核心语言编写,也是C++ISO自身标准的一部分. Standard Template Library:标准模板库 C POSIX library : POSIX系统的C标准库规范 ISO C++ Standards Committee :C++标准委员会 框架 C++通用框架和库

站在巨人的肩膀上,C++开源库大全

程序员要站在巨人的肩膀上,C++拥有丰富的开源库,这里包括:标准库.Web应用框架.人工智能.数据库.图片处理.机器学习.日志.代码分析等. 标准库 C++ Standard Library:是一系列类和函数的集合,使用核心语言编写,也是C++ISO自身标准的一部分. Standard Template Library:标准模板库 C POSIX library : POSIX系统的C标准库规范 ISO C++ Standards Committee :C++标准委员会 框架 C++通用框架和库

[转]C&amp;C++图形图像处理开源库

本文章已收录于: .embody { padding: 10px 10px 10px; margin: 0 -20px; border-bottom: solid 1px #ededed } .embody_b { margin: 0; padding: 10px 0 } .embody .embody_t,.embody .embody_c { display: inline-block; margin-right: 10px } .embody_t { font-size: 12px; co