特征提取算法的综合实验(多种角度比较sift/surf/brisk/orb/akze)

https://www.cnblogs.com/jsxyhelu/p/7834416.html

一、基本概念:

作用:特征点提取在“目标识别、图像拼接、运动跟踪、图像检索、自动定位”等研究中起着重要作用;

主要算法

•FAST ,Machine Learning forHigh-speed Corner Detection, 2006

SIFT,Distinctive ImageFeatures from Scale-Invariant Keypoints,2004,invariant to image translation, scaling, and rotation, partially invariant toillumination changes and robust to local geometric distortion

SURF,Speeded Up RobustFeatures,2006,SIFT启发,比SIFT快,健壮

ORB,ORB: an efficientalternative to SIFT or SURF,2011,基于FAST,比SIFT快两个数量级,可作为SIFT的替代

BRISKBRISK:Binary Robust Invariant Scalable Keypoints

•STAR,Censure: Centersurround extremas for realtime featuredetection and matching,引用次数不高

•MSER,RobustWide Baseline Stereo from Maximally Stable ExtremalRegions,2002,斑点检测

•GFTT,GoodFeatures to Track,1994,Determines strong corners on animage

•HARRIS,Harris and M. Stephens (1988).“A combined corner and edge detector”,也是一种角点检测方法

•FREAK

•AKAZE等

其中标红的5项是在OpenCV中已经进行了实现的。

特征点识别主要流程为:

1、检测关键点、提取描述向量和特征匹配;

2、通过检测关键点和提取描述向量构造出局部特征描述子,

3、然后进行特征匹配

二、数据准备:

数据集为pascal中取出的6个数据,分别针对特征点提取的6个方面

其中特征点识别在以下6个方面进行比较

1、算法匹配速度比较 (ubc)

测试方法:在相同的匹配环境下,即使用同样配置的计算机,对相同的一对图像进行比较,测试算法的执行时间

2、旋转变换鲁棒性比较 (bark)

测试方法:对同一图像进行一定角度的旋转,旋转角度逐步递增,旋转后的图像逐一与原始图像进行匹配,比较能够正确匹配的特征点对数,并观察正确匹配对数的变化幅度

3、模糊变换鲁棒性比较 (bikes)

测试方法:对同一图像用不同的高斯核进行模糊处理,模糊处理后的图像逐一与原始图像进

行匹配,比较能够正确匹配的特征点对数,并观察正确匹配对数的变化幅度 

4、光照变换鲁棒性比较 (leuven)

测试方法:对同一图像的亮度进行改变,逐

渐降低亮度,改变亮度后的图像逐一与原始图像进行匹配,比较能够正确匹配的特征点对数,并观察正确匹配对数的变化幅度

5、尺度变换鲁棒性比较 (bark)

测试方法:对原图像的尺度大小进行改变,尺度变化后的图像逐一与原始图像进行匹配,比较能够正确匹配的特征点对数,并观察正确匹配对数的变化幅度

6、视角变换鲁棒性比较 (graf)

测试方法:对原场景转一定角度进行拍摄,不同视角的图像逐一与原始图像进行匹配,比较能够正确匹配的特征点对数,并观察正确匹配对

数的变化幅度 

三、实验步骤:

1、依次对各个数据集进行特征点提取并进行两两特征点的比较,也就是match。这个流程是正常的流程,执行的过程中要注意错误控制

                //使用img1对比余下的图片,得出结果    

                img1 = imread(files[0],0);

                imgn = imread(files[iimage],0);

                //生成特征点算法及其匹配方法

                Ptr<Feature2D>  extractor;

                BFMatcher matcher;

                switch (imethod)

                {

                case 0: //"SIFT"

                    extractorSIFT::create();

                    matcher = BFMatcher(NORM_L2);    

                    break;

                case 1: //"SURF"

                    extractorSURF::create();

                    matcher = BFMatcher(NORM_L2);    

                    break;

                case 2: //"BRISK"

                    extractor = BRISK::create();

                    matcher = BFMatcher(NORM_HAMMING);

                    break;

                case 3: //"ORB"

                    extractorORB::create();

                    matcher = BFMatcher(NORM_HAMMING);    

                    break;

                case 4: //"AKAZE"

                    extractorAKAZE::create();

                    matcher = BFMatcher(NORM_HAMMING);    

                    break;

                }

                try

                {

                    extractor->detectAndCompute(img1,Mat(),keypoints1,descriptors1);

                    extractor->detectAndCompute(imgn,Mat(),keypoints2,descriptors2);

                    matcher.matchdescriptors1descriptors2matches );

                }

                catch (CExceptione)

                {

                    cout<<" 特征点提取时发生错误 "<<endl;

                    continue;

                }

 

                //对特征点进行粗匹配

                double max_dist = 0; 

                double min_dist = 100;

                forint a = 0; a < matches.size(); a++ )

                {

                    double dist = matches[a].distance;

                    ifdist < min_dist ) min_dist = dist;

                    ifdist > max_dist ) max_dist = dist;

                }

                forint a = 0; a < matches.size(); a++ )

                { 

                    ifmatches[a].distance <= max(2*min_dist, 0.02) )

                        good_matches.push_backmatches[a]); 

                }

                if (good_matches.size()<4)

                {

                    cout<<" 有效特征点数目小于4个,粗匹配失败 "<<endl;

                    continue;

                }

2、对match的结果进行RANSAC提纯计算,计算“内点”。主要是RANSAC提纯的一个过程,这个过程在图像拼接中也是很常见的。

 

                //通过RANSAC方法,对现有的特征点对进行“提纯”

                std::vector<Point2fobj;

                std::vector<Point2fscene;

                forint a = 0; a < (int)good_matches.size(); a++ )

                {    

                    //分别将两处的good_matches对应的点对压入向量,只需要压入点的信息就可以

                    obj.push_backkeypoints1[good_matches[a].queryIdx ].pt );

                    scene.push_backkeypoints2[good_matches[a].trainIdx ].pt );

                }

                //计算单应矩阵(在calib3d中)

                Mat H ;

                try

                {

                    H = findHomographyobjsceneCV_RANSAC );

                }

                catch (CExceptione)

                {

                    cout<<" findHomography失败 "<<endl;

                    continue;

                }

                if (H.rows < 3)

                {

                    cout<<" findHomography失败 "<<endl;

                    continue;

                }

              //计算内点数目

                Mat matObj;

                Mat matScene;

                CvMatpcvMat = &(CvMat)H;

                const doubleHmodel = pcvMat->data.db;

                double Htmp = Hmodel[6];

                forint isize = 0; isize < obj.size(); isize++ )

                {

                    double ww = 1./(Hmodel[6]*obj[isize].x + Hmodel[7]*obj[isize].y + 1.);

                    double dx = (Hmodel[0]*obj[isize].x + Hmodel[1]*obj[isize].y + Hmodel[2])*ww - scene[isize].x;

                    double dy = (Hmodel[3]*obj[isize].x + Hmodel[4]*obj[isize].y + Hmodel[5])*ww - scene[isize].y;

                    float err = (float)(dx*dx + dy*dy); //3个像素之内认为是同一个点

                    if (err< 9)

                    {

                        innersize = innersize+1;

                    }

                }

 

3、比较“耗时”和“内点比例”两个因素。其中建立数学模型,就是用"准确率“/“内点比例”,这样得到一个正向的结论。

 

4、结合相关数据,得出综合结论

四、实验结果:

1、sift和surf一直提供了较高的准确率,并且结果比较稳定;sift较surf更准一些,但是也有brisk最好的时候;

 

2、orb的速度非常快,但是最容易出现问题;

 

3、AKAZA也很容易出现问题;

 

 

 

4、其他算法,包括AKAZA,速度的差别都不是很大。

 

 

五、结论

 

那么我们在做大型特征点提取的算法的时候,就需要综合考虑速度、准确率等多种要素;很可能要自己设计新的算法,将这几种典型算法包含其中,扬长避短了。

 

附:

配套课程:http://edu.51cto.com/course/11555.html (实验可以免费观看)

 

//遍历dateset,分别对SIFT、SURF、BRISK、ORB、FREAK算法进行运算,得出初步结论

//jsxyhelu 2017年11月3日

#include "stdafx.h"

#include <opencv2/core/utility.hpp>

#include "opencv2/imgproc.hpp"

#include "opencv2/videoio.hpp"

#include "opencv2/highgui.hpp"

#include "opencv2/calib3d.hpp"

#include "opencv2/xfeatures2d.hpp"

#include <iostream>

#include <ctype.h>

#include "GOCVHelper.h"

#define DATESET_COUNT 8

#define METHOD_COUNT 5

using namespace cv;

using namespace std;

using namespace xfeatures2d;

 

void main()

{

    string strDateset[DATESET_COUNT];

    strDateset[0] = "bark";strDateset[1] = "bikes";strDateset[2] = "boat";strDateset[3] = "graf";strDateset[4] = "leuven";

    strDateset[5] = "trees";strDateset[6] = "ubc";strDateset[7] = "wall";

    string strMethod[METHOD_COUNT];

    strMethod[0] = "SIFT";strMethod[1]="SURF";strMethod[2]="BRISK";strMethod[3]="ORB";strMethod[4]="AKAZE";

    递归读取目录下全部文件

    vector<stringfiles;

    Mat descriptors1;  

    std::vector<KeyPointkeypoints1;

    Mat descriptors2;

    std::vector<KeyPointkeypoints2;

    std::vectorDMatch > matches;

    std::vectorDMatch > good_matches;

    用于模型验算

    int innersize = 0;

    Mat img1;

    Mat imgn;

    int64 t = getTickCount();

    std::cout<<"SIFT、SURF、BRISK、ORB、A K A Z E算法测试实验开始"<<endl;

    //遍历各种特征点寻找方法

    for (int imethod=METHOD_COUNT-1;imethod<METHOD_COUNT;imethod++)

    {

 

        string _strMethod = strMethod[imethod];

        std::cout<<"开始测试"<<_strMethod<<"方法"<<endl;

        //遍历各个路径

        for (int idateset = 0;idateset<DATESET_COUNT;idateset++)

        {

            //获得测试图片绝对地址

            string path = "E:/template/dateset/"+strDateset[idateset];

            std::cout<<"数据集为"<<strDateset[idateset];

            //获得当个数据集中的图片

            GO::getFiles(path,files,"r");

            std::cout<<" 共"<<files.size()<<"张图片"<<endl;

            for (int iimage=1;iimage<files.size();iimage++)

            {

                //使用img1对比余下的图片,得出结果    

                img1 = imread(files[0],0);

                imgn = imread(files[iimage],0);

                //生成特征点算法及其匹配方法

                Ptr<Feature2D>  extractor;

                BFMatcher matcher;

                switch (imethod)

                {

                case 0: //"SIFT"

                    extractorSIFT::create();

                    matcher = BFMatcher(NORM_L2);    

                    break;

                case 1: //"SURF"

                    extractorSURF::create();

                    matcher = BFMatcher(NORM_L2);    

                    break;

                case 2: //"BRISK"

                    extractor = BRISK::create();

                    matcher = BFMatcher(NORM_HAMMING);

                    break;

                case 3: //"ORB"

                    extractorORB::create();

                    matcher = BFMatcher(NORM_HAMMING);    

                    break;

                case 4: //"AKAZE"

                    extractorAKAZE::create();

                    matcher = BFMatcher(NORM_HAMMING);    

                    break;

                }

                try

                {

                    extractor->detectAndCompute(img1,Mat(),keypoints1,descriptors1);

                    extractor->detectAndCompute(imgn,Mat(),keypoints2,descriptors2);

                    matcher.matchdescriptors1descriptors2matches );

                }

                catch (CExceptione)

                {

                    cout<<" 特征点提取时发生错误 "<<endl;

                    continue;

                }

 

                //对特征点进行粗匹配

                double max_dist = 0; 

                double min_dist = 100;

                forint a = 0; a < matches.size(); a++ )

                {

                    double dist = matches[a].distance;

                    ifdist < min_dist ) min_dist = dist;

                    ifdist > max_dist ) max_dist = dist;

                }

                forint a = 0; a < matches.size(); a++ )

                { 

                    ifmatches[a].distance <= max(2*min_dist, 0.02) )

                        good_matches.push_backmatches[a]); 

                }

                if (good_matches.size()<4)

                {

                    cout<<" 有效特征点数目小于4个,粗匹配失败 "<<endl;

                    continue;

                }

                //通过RANSAC方法,对现有的特征点对进行“提纯”

                std::vector<Point2fobj;

                std::vector<Point2fscene;

                forint a = 0; a < (int)good_matches.size(); a++ )

                {    

                    //分别将两处的good_matches对应的点对压入向量,只需要压入点的信息就可以

                    obj.push_backkeypoints1[good_matches[a].queryIdx ].pt );

                    scene.push_backkeypoints2[good_matches[a].trainIdx ].pt );

                }

                //计算单应矩阵(在calib3d中)

                Mat H ;

                try

                {

                    H = findHomographyobjsceneCV_RANSAC );

                }

                catch (CExceptione)

                {

                    cout<<" findHomography失败 "<<endl;

                    continue;

                }

                if (H.rows < 3)

                {

                    cout<<" findHomography失败 "<<endl;

                    continue;

                }

                //计算内点数目

                Mat matObj;

                Mat matScene;

                CvMatpcvMat = &(CvMat)H;

                const doubleHmodel = pcvMat->data.db;

                double Htmp = Hmodel[6];

                forint isize = 0; isize < obj.size(); isize++ )

                {

                    double ww = 1./(Hmodel[6]*obj[isize].x + Hmodel[7]*obj[isize].y + 1.);

                    double dx = (Hmodel[0]*obj[isize].x + Hmodel[1]*obj[isize].y + Hmodel[2])*ww - scene[isize].x;

                    double dy = (Hmodel[3]*obj[isize].x + Hmodel[4]*obj[isize].y + Hmodel[5])*ww - scene[isize].y;

                    float err = (float)(dx*dx + dy*dy); //3个像素之内认为是同一个点

                    if (err< 9)

                    {

                        innersize = innersize+1;

                    }

                }

                //打印内点占全部特征点的比率

                float ff = (float)innersize / (float)good_matches.size();

                cout<<ff;

                //打印时间

                cout <<" "<<((getTickCount() - t) / getTickFrequency())<< endl;

                t = getTickCount();

                //如果效果较好,则打印出来

                Mat matTmp;

                if (ff == 1.0)

                {

                    drawMatches(img1,keypoints1,imgn,keypoints2,good_matches,matTmp);

                    char charJ[255];sprintf_s(charJ,"_%d.jpg",iimage);

                    string strResult = "E:/template/result/"+strDateset[idateset]+_strMethod+charJ;

                    imwrite(strResult,matTmp);

                }

                ff = 0;

                innersize = 0;

                matches.clear();

                good_matches.clear(); 

            }

            files.clear();

        }

    }

    getchar();

    waitKey();

    return;

 

};

BRISK特征提取算法

https://www.cnblogs.com/welen/articles/6088639.html

简介

        BRISK算法是2011年ICCV上《BRISK:Binary Robust Invariant Scalable Keypoints》文章中,提出来的一种特征提取算法,也是一种二进制的特征描述算子。

       它具有较好的旋转不变性、尺度不变性,较好的鲁棒性等。在图像配准应用中,速度比较:SIFT<SURF<BRISK<FREAK<ORB,在对有较大模糊的图像配准时,BRISK算法在其中表现最为出色。

BRISK算法

特征点检测

        BRISK算法主要利用FAST9-16进行特征点检测(为什么是主要?因为用到一次FAST5-8),可参见博客:FAST特征点检测算法。要解决尺度不变性,就必须在尺度空间进行特征点检测,于是BRISK算法中构造了图像金字塔进行多尺度表达。

建立尺度空间

        构造n个octave层(用ci表示)和n个intra-octave层(用di表示),文章中n=4,i={0,1,...,n-1}。假设有图像img,octave层的产生:c0层就是img原图像,c1层是c0层的2倍下采样,c2层是c1层的2倍下采样,以此类推。intra-octave层的产生:d0层是img的1.5倍下采样,d1层是d0层的2倍下采样(即img的2*1.5倍下采样),d2层是d1层的2倍下采样,以此类推。

则ci、di层与原图像的尺度关系用t表示为:

ci、di层与原图像大小关系为:

        由于n=4,所以一共可以得到8张图,octave层之间尺度(缩放因子)是2倍关系,intra-octave层之间尺度(缩放因子)也是2倍关系。

特征点检测

        对这8张图进行FAST9-16角点检测,得到具有角点信息的8张图,对原图像img进行一次FAST5-8角点检测(当做d(-1)层,虚拟层),总共会得到9幅有角点信息的图像。

非极大值抑制

        对这9幅图像,进行空间上的非极大值抑制(同SIFT算法的非极大值抑制):特征点在位置空间(8邻域点)和尺度空间(上下层2x9个点),共26个邻域点的FAST的得分值要最大,否则不能当做特征点;此时得到的极值点还比较粗糙,需要进一步精确定位。

亚像素插值

        进过上面步骤,得到了图像特征点的位置和尺度,在极值点所在层及其上下层所对应的位置,对FAST得分值(共3个)进行二维二次函数插值(x、y方向),得到真正意义上的得分极值点及其精确的坐标位置(作为特征点位置);再对尺度方向进行一维插值,得到极值点所对应的尺度(作为特征点尺度)。

特征点描述

高斯滤波

       现在,我们得到了特征点的位置和尺度(t)后,要对特征点赋予其描述符。均匀采样模式:以特征点为中心,构建不同半径的同心圆,在每个圆上获取一定数目的等间隔采样点(所有采样点包括特征点,一共N个),由于这种邻域采样模式会引起混叠效应,所以需要对同心圆上的采样点进行高斯滤波。

       采样模式如下图,蓝圈表示;以采样点为中心,为方差进行高斯滤波,滤波半径大小与高斯方差的大小成正比,红圈表示。最终用到的N个采样点是经过高斯平滑后的采样点。下图是t=1时的。(文章中:N=60)

局部梯度计算

         由于有N个采样点,则采样点两两组合成一对,共有N(N-1)/2钟组合方式,所有组合方式的集合称作采样点对,用集合表示,其中像素分别是,δ表示尺度。用表示特征点局部梯度集合,则有:

定义短距离点对子集、长距离点对子集(L个):

其中,,t是特征点所在的尺度。

现在要利用上面得到的信息,来计算特征点的主方向(注意:此处只用到了长距离子集),如下:

特征描述符

         要解决旋转不变性,则需要对特征点周围的采样区域进行旋转到主方向,旋转后得到新的采样区域,采样模式同上。BRISK描述子是二进制的特征,由采样点集合可得到N(N-1)/2对采样点对,就可以得到N(N-1)/2个距离的集合(包含长、短距离子集),考虑其中短距离子集中的512个短距离点对,进行二进制编码,判断方式如下:

其中,带有上标,表示经过旋转a角度后的,新的采样点。由此可得到,512Bit的二进制编码,也就是64个字节(BRISK64)。

匹配方法

汉明距离进行比较,与其他二进制描述子的匹配方式一样

  • 2
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值