特征提取算法的綜合實驗(多種角度比較sift/surf/brisk/orb/akze)


一、基本概念:
作用特征點提取在“目標識別、圖像拼接、運動 跟蹤、圖像檢索、自動定位”等研究中起着重要作用;
主要算法
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 的替代
GFTT GoodFeatures to Track,1994,Determines strong corners on animage
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,速度的差別都不是很大。
 
 
五、結論
 
那么我們在做大型特征點提取的算法的時候,就需要綜合考慮速度、准確率等多種要素;很可能要自己設計新的算法,將這幾種典型算法包含其中,揚長避短了。
 
附:
 
//遍歷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;
 
};
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM