小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

特征點(diǎn)檢測學(xué)習(xí)_2(surf算法)

 Jack_WangChong 2016-06-06

  

  在上篇博客特征點(diǎn)檢測學(xué)習(xí)_1(sift算法) 中簡單介紹了經(jīng)典的sift算法,sift算法比較穩(wěn)定,檢測到的特征點(diǎn)也比較多,其最大的確定是計算復(fù)雜度較高。后面有不少學(xué)者對其進(jìn)行了改進(jìn),其中比較出名的就是本文要介紹的surf算法,surf的中文意思為快速魯棒特征。本文不是專門介紹surf所有理論(最好的理論是作者的論文)的,只是對surf算法進(jìn)行了下整理,方便以后查閱。

  網(wǎng)上有些文章對surf做了介紹,比如:

  http://wuzizhang.blog.163.com/blog/static/78001208201138102648854/

  surf算法原理,有一些簡單介紹.

  http://blog.csdn.net/andkobe/article/details/5778739

  對surf的某些細(xì)節(jié)做了通俗易懂的解釋.

  http://www./DancingWind/

  這篇文章名字叫做《surf原文翻譯》,寫得非常好,看完會對surf中采用的一些技術(shù)更加深入的理解,不過本文卻不是翻譯英文的,而是該作者自己的理解,對積分圖,Hessian矩陣等引入的原因都做了通俗的解釋,推薦一看。

 

 

    一、Surf描述子形成步驟

         1. 構(gòu)造高斯金字塔尺度空間

         其實surf構(gòu)造的金字塔圖像與sift有很大不同,就是因為這些不同才加快了其檢測的速度。Sift采用的是DOG圖像,而surf采用的是Hessian矩陣行列式近似值圖像。首先來看看圖像中某個像素點(diǎn)的Hessian矩陣,如下:

          

         即每一個像素點(diǎn)都可以求出一個Hessian矩陣。但是由于我們的特征點(diǎn)需要具備尺度無關(guān)性,所以在進(jìn)行Hessian矩陣構(gòu)造前,需要對其進(jìn)行高斯濾波。這樣,經(jīng)過濾波后在進(jìn)行Hessian的計算,其公式如下:

   

         公式中的符號,估計有點(diǎn)數(shù)學(xué)基礎(chǔ)的朋友都能夠猜到,這里就不多解釋了。

         最終我們要的是原圖像的一個變換圖像,因為我們要在這個變換圖像上尋找特征點(diǎn),然后將其位置反映射到原圖中,例如在sift中,我們是在原圖的DOG圖上尋找特征點(diǎn)的。那么在surf中,這個變換圖是什么呢?從surf的眾多資料來看,就是原圖每個像素的Hessian矩陣行列式的近似值構(gòu)成的。其行列式近似公式如下:

          

         其中0.9是作者給出的一個經(jīng)驗值,其實它是有一套理論計算的,具體去看surf的英文論文。

         由于求Hessian時要先高斯平滑,然后求二階導(dǎo)數(shù),這在離散的像素點(diǎn)是用模板卷積形成的,這2中操作合在一起用一個模板代替就可以了,比如說y方向上的模板如下:

            

         該圖的左邊即用高斯平滑然后在y方向上求二階導(dǎo)數(shù)的模板,為了加快運(yùn)算用了近似處理,其處理結(jié)果如右圖所示,這樣就簡化了很多。并且右圖可以采用積分圖來運(yùn)算,大大的加快了速度,關(guān)于積分圖的介紹,可以去查閱相關(guān)的資料。

         同理,x和y方向的二階混合偏導(dǎo)模板如下所示:

    

 

  上面講的這么多只是得到了一張近似hessian行列式圖,這例比sift中的DOG圖,但是在金字塔圖像中分為很多層,每一層叫做一個octave,每一個octave中又有幾張尺度不同的圖片。在sift算法中,同一個octave層中的圖片尺寸(即大小)相同,但是尺度(即模糊程度)不同,而不同的octave層中的圖片尺寸大小也不相同,因為它是由上一層圖片降采樣得到的。在進(jìn)行高斯模糊時,sift的高斯模板大小是始終不變的,只是在不同的octave之間改變圖片的大小。而在surf中,圖片的大小是一直不變的,不同的octave層得到的待檢測圖片是改變高斯模糊尺寸大小得到的,當(dāng)然了,同一個octave中個的圖片用到的高斯模板尺度也不同。Surf采用這種方法節(jié)省了降采樣過程,其處理速度自然也就提上去了。其金字塔圖像如下所示:

  

    

 

  2. 利用非極大值抑制初步確定特征點(diǎn)

  此步驟和sift類似,將經(jīng)過hessian矩陣處理過的每個像素點(diǎn)與其3維領(lǐng)域的26個點(diǎn)進(jìn)行大小比較,如果它是這26個點(diǎn)中的最大值或者最小值,則保留下來,當(dāng)做初步的特征點(diǎn)。

 

  3. 精確定位極值點(diǎn)

  這里也和sift算法中的類似,采用3維線性插值法得到亞像素級的特征點(diǎn),同時也去掉那些值小于一定閾值的點(diǎn)。

 

  4. 選取特征點(diǎn)的主方向。

  這一步與sift也大有不同。Sift選取特征點(diǎn)主方向是采用在特征點(diǎn)領(lǐng)域內(nèi)統(tǒng)計其梯度直方圖,取直方圖bin值最大的以及超過最大bin值80%的那些方向做為特征點(diǎn)的主方向。而在surf中,不統(tǒng)計其梯度直方圖,而是統(tǒng)計特征點(diǎn)領(lǐng)域內(nèi)的harr小波特征。即在特征點(diǎn)的領(lǐng)域(比如說,半徑為6s的圓內(nèi),s為該點(diǎn)所在的尺度)內(nèi),統(tǒng)計60度扇形內(nèi)所有點(diǎn)的水平haar小波特征和垂直haar小波特征總和,haar小波的尺寸變長為4s,這樣一個扇形得到了一個值。然后60度扇形以一定間隔進(jìn)行旋轉(zhuǎn),最后將最大值那個扇形的方向作為該特征點(diǎn)的主方向。該過程的示意圖如下:

    

 

  5. 構(gòu)造surf特征點(diǎn)描述算子

  在sift中,是在特征點(diǎn)周圍取16*16的鄰域,并把該領(lǐng)域化為4*4個的小區(qū)域,每個小區(qū)域統(tǒng)計8個方向梯度,最后得到4*4*8=128維的向量,該向量作為該點(diǎn)的sift描述子。

  在surf中,也是在特征點(diǎn)周圍取一個正方形框,框的邊長為20s(s是所檢測到該特征點(diǎn)所在的尺度)。該框帶方向,方向當(dāng)然就是第4步檢測出來的主方向了。然后把該框分為16個子區(qū)域,每個子區(qū)域統(tǒng)計25個像素的水平方向和垂直方向的haar小波特征,這里的水平和垂直方向都是相對主方向而言的。該haar小波特征為水平方向值之和,水平方向絕對值之和,垂直方向之和,垂直方向絕對值之和。該過程的示意圖如下所示:

    

 

  這樣每個小區(qū)域就有4個值,所以每個特征點(diǎn)就是16*4=64維的向量,相比sift而言,少了一半,這在特征匹配過程中會大大加快匹配速度。

 

 

  二、特征點(diǎn)的匹配過程

  surf特征點(diǎn)的匹配過程和sift類似,這里不做詳細(xì)介紹

 

 

  三、實驗部分

  本次實驗采用網(wǎng)上流行的open surf,用c++完成的,用到了opencv庫,下載地址為:http://www./computer-vision-opensurf.html

  該代碼的作者給出的主函數(shù)實現(xiàn)了6中功能,包括靜態(tài)圖片特征點(diǎn)的檢測,視頻中特征點(diǎn)的檢測,圖片之間的匹配,視頻與圖片之間的匹配,特征點(diǎn)聚類等6中功能。本次實驗就簡單的測試了圖片的檢測,匹配和特征點(diǎn)聚類3個功能。并加入了簡單的界面。

  開發(fā)環(huán)境為:opencv2.4.2+Qt4.8.2+open surf+windosxp

  實驗分為下面3個部分來描述。

 

  Surf特征點(diǎn)檢測和描述

  打開軟件,單擊Open Image按鈕,選擇一張待檢測的圖片,效果如下:

  

 

  單擊Surf Detect按鈕,程序會對該圖片進(jìn)行特征點(diǎn)檢測,并顯示特征結(jié)果,包括特征點(diǎn)的主方向,尺度等信息。效果如下:

  

  單擊Close 按鈕退出程序。

 

  Surf特征點(diǎn)匹配

  打開軟件,單擊Open Image 按鈕,依次打開2幅待匹配的圖片,這2幅圖片要有相同的內(nèi)容,只是尺度,旋轉(zhuǎn),光照等不同。打開圖片后如下:

  

 

  單擊Surf Detect按鈕,和上面類似,會先對圖片進(jìn)行檢測,效果如下:

  

 

  單擊Surf Match 按鈕,程序會對檢測到的圖片進(jìn)行特征點(diǎn)匹配,效果如下:

  

  單擊Close 按鈕退出程序。

 

  Surf特征點(diǎn)聚類

  打開軟件,單擊Open Image 按鈕,選擇一張待特征點(diǎn)分類的圖片,如下所示:

  

 

  單擊Surf Detect按鈕,首先對該圖片進(jìn)行surf特征點(diǎn)檢測,如下:

  

 

  單擊Kmeans Cluster按鈕,程序會對這些特征點(diǎn)集合進(jìn)行聚類,并顯示其結(jié)果,如下所示:

  

   單擊Close 按鈕退出程序。

   

  實驗主要函數(shù)部分及代碼(附錄有工程code下載鏈接):

opensurf.h:

復(fù)制代碼
#ifndef OPENSURF_H
#define OPENSURF_H

#include <QDialog>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include "ipoint.h"
#include "kmeans.h"

using namespace cv;

namespace Ui {
class OpenSurf;
}

class OpenSurf : public QDialog
{
    Q_OBJECT
    
public:
    explicit OpenSurf(QWidget *parent = 0);
    ~OpenSurf();
    
private slots:
    void on_openButton_clicked();

    void on_detectButton_clicked();

    void on_matchButton_clicked();

    void on_closeButton_clicked();

    void on_clusterButton_clicked();

private:
    Ui::OpenSurf *ui;
    IplImage *img1, *img2, *img_match1, *img_match2;
    IpVec ipts, ipts1, ipts2;
    IpPairVec matches;
    Kmeans km;
    int open_image_num;

};

#endif // OPENSURF_H
復(fù)制代碼

 

opensurf.cpp:

復(fù)制代碼
#include "opensurf.h"
#include "ui_opensurf.h"
#include <QtGui>
#include <QtCore>
#include "surflib.h"

using namespace std;

OpenSurf::OpenSurf(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OpenSurf)
{
    open_image_num = 0;
    ui->setupUi(this);
}

OpenSurf::~OpenSurf()
{
    delete ui;
}

void OpenSurf::on_openButton_clicked()
{
    QString img_name = QFileDialog::getOpenFileName(this, "Open Image", "../open_surf",
                                                           tr("Image Files(*.png *.jpeg *.jpg *.bmp)"));
       if(0 == open_image_num)
           ui->textBrowser->clear();
       open_image_num ++;
       if( 1 == open_image_num )
           {
               img1 = cvLoadImage(img_name.toAscii().data());
               img_match1 = cvLoadImage(img_name.toAscii().data());
               cvSaveImage("../open_surf/load_img1.jpg", img1);
               ui->textBrowser->setFixedSize(img1->width, img1->height);
               ui->textBrowser->insertHtml("<img src=../open_surf/load_img1.jpg>");
           }
       else if(2 == open_image_num)
           {
               img2 = cvLoadImage(img_name.toAscii().data());
               img_match2 = cvLoadImage(img_name.toAscii().data());
               cvSaveImage("../open_surf/load_img2.jpg", img2);
               ui->textBrowser->setFixedSize(img1->width+img2->width, std::max(img1->height, img2->height));
               //取消自動換行模式,讓2幅圖片水平顯示
               ui->textBrowser->setWordWrapMode (QTextOption::NoWrap);
               ui->textBrowser->insertHtml("<img src=../open_surf/load_img2.jpg>");
           }
       else if(3 == open_image_num)
           {
               open_image_num = 0;
               ui->textBrowser->clear();
           }
}

void OpenSurf::on_detectButton_clicked()
{
    if( 1 == open_image_num )
        {
            //用surf對特征點(diǎn)進(jìn)行檢測
            surfDetDes(img1, ipts, false, 5, 4, 2, 0.0004f);
            //在圖像中將特征點(diǎn)畫出來
            drawIpoints(img1, ipts);
            cvSaveImage("../open_surf/detect_img1.jpg", img1);
            ui->textBrowser->clear();
            ui->textBrowser->setFixedSize(img1->width, img1->height);
            ui->textBrowser->insertHtml("<img src=../open_surf/detect_img1.jpg>");
        }
    else if (2 == open_image_num)
        {
            //用surf對特征點(diǎn)進(jìn)行檢測
            surfDetDes(img1, ipts1, false, 5, 4, 2, 0.0004f);
            //在圖像中將特征點(diǎn)畫出來
            drawIpoints(img1, ipts1);
            cvSaveImage("../open_surf/detect_img1.jpg", img1);
            //用surf對特征點(diǎn)進(jìn)行檢測
            surfDetDes(img2, ipts2, false, 5, 4, 2, 0.0004f);
            //在圖像中將特征點(diǎn)畫出來
            drawIpoints(img2, ipts2);
            cvSaveImage("../open_surf/detect_img2.jpg", img2);
            ui->textBrowser->clear();
            ui->textBrowser->insertHtml("<img src=../open_surf/detect_img1.jpg>");

            ui->textBrowser->setFixedSize(img1->width+img2->width, std::max(img1->height, img2->height));
            //取消自動換行模式,讓2幅圖片水平顯示
            ui->textBrowser->setWordWrapMode (QTextOption::NoWrap);
            ui->textBrowser->insertHtml("<img src=../open_surf/detect_img2.jpg>");
        }
}

void OpenSurf::on_matchButton_clicked()
{
    if(2 == open_image_num)
        {
            getMatches(ipts1,ipts2,matches);
            for (unsigned int i = 0; i < matches.size(); ++i)
              {
                drawPoint(img_match1,matches[i].first);
                drawPoint(img_match2,matches[i].second);

                const int & w = img1->width;
                const int & h1 = img1->height;
                const int & h2 = img2->height;
                //這里因為我事先已經(jīng)知道了圖片的相對打開后顯示的位置,所以在畫匹配的直線時加了點(diǎn)常識
                //因此該方法不通用,只是適合本例中給的圖片,最好的方法就像Rob Hess的sift算法那樣
                //把2張圖片合成一張,然后在一張圖片上畫匹配直線
                cvLine(img_match1,cvPoint(matches[i].first.x,matches[i].first.y),
                       cvPoint(matches[i].second.x+w,matches[i].second.y+std::abs(h1-h2)),
                       cvScalar(255,255,255),1);
                cvLine(img_match2,cvPoint(matches[i].first.x-w,matches[i].first.y-std::abs(h1-h2)),
                       cvPoint(matches[i].second.x,matches[i].second.y),
                       cvScalar(255,255,255),1);
              }
            cvSaveImage("../open_surf/match_img1.jpg", img_match1);
            cvSaveImage("../open_surf/match_img2.jpg", img_match2);
            ui->textBrowser->clear();
            ui->textBrowser->insertHtml("<img src=../open_surf/match_img1.jpg>");

            ui->textBrowser->setFixedSize(img1->width+img2->width, std::max(img1->height, img2->height));
            //取消自動換行模式,讓2幅圖片水平顯示
            ui->textBrowser->setWordWrapMode (QTextOption::NoWrap);
            ui->textBrowser->insertHtml("<img src=../open_surf/match_img2.jpg>");
        }
}


void OpenSurf::on_clusterButton_clicked()
{
    for (int repeat = 0; repeat < 10; ++repeat)
      {

        km.Run(&ipts, 5, true);
        drawPoints(img1, km.clusters);

        for (unsigned int i = 0; i < ipts.size(); ++i)
        {
          cvLine(img1, cvPoint(ipts[i].x,ipts[i].y), cvPoint(km.clusters[ipts[i].clusterIndex].x ,km.clusters[ipts[i].clusterIndex].y),cvScalar(255,255,255));
        }
        cvSaveImage("../open_surf/kmeans_img1.jpg", img1);
        ui->textBrowser->clear();
        ui->textBrowser->setFixedSize(img1->width, img1->height);
        ui->textBrowser->insertHtml("<img src=../open_surf/kmeans_img1.jpg>");
      }
}


void OpenSurf::on_closeButton_clicked()
{
    close();
}
復(fù)制代碼

 

   

  總結(jié):

     Surf在速度上比sift要快許多,這主要得益于它的積分圖技術(shù),已經(jīng)Hessian矩陣的利用減少了降采樣過程,另外它得到的特征向量維數(shù)也比較少,有利于更快的進(jìn)行特征點(diǎn)匹配。

 

 

 附錄一:

  1、和RobHesson運(yùn)行時一樣,這里的open surf運(yùn)行時出現(xiàn)如下錯誤:

  ipoint.obj:-1: error: LNK2019: 無法解析的外部符號 _cvFindHomography,該符號在函數(shù) "int __cdecl translateCorners(class std::vector<struct std::pair<class Ipoint,class Ipoint>,class std::allocator<struct std::pair<class Ipoint,class Ipoint> > > &,struct CvPoint const * const,struct CvPoint * const)" (?translateCorners@@YAHAAV?$vector@U?$pair@VIpoint@@V1@@std@@V?$allocator@U?$pair@VIpoint@@V1@@std@@@2@@std@@QBUCvPoint@@QAU3@@Z) 中被引用

  不過這次的原因是沒有opencv_calib3d242d.lib庫,因為本open surf在進(jìn)行特征匹配時用到了opencv中的3維重建有關(guān)的函數(shù)cvFindHomography(該函數(shù)是求2個圖像間的單應(yīng)矩陣),所以很多人都會忘了添加這個庫文件,就會導(dǎo)致這個錯誤。

 

  2、如果用了Qt或MFC等界面設(shè)計代碼時,編譯該程序會報如下錯誤:

  moc_open_surf.obj:-1: error: LNK2005: "public: void __thiscall Kmeans::SetIpoints(class std::vector<class Ipoint,class std::allocator<class Ipoint> > *)" (?SetIpoints@Kmeans@@QAEXPAV?$vector@VIpoint@@V?$allocator@VIpoint@@@std@@@std@@@Z) 已經(jīng)在 main.obj 中定義

  其實是Open Surf的作者可能沒有考慮周全,它在kmeans.h文件中把Kmeans這個類的成員函數(shù)方法在頭文件中實現(xiàn)了,其實這在標(biāo)準(zhǔn)c++中是不支持的。解決方法就是把kmeans.h改造成kemans.hpp(該方法我沒有去試過);另外一種方法就是新建一個kmeans.cpp文件,把成員函數(shù)的實現(xiàn)過程放在cpp文件中實現(xiàn),我這次試驗就是采用的這個方法。

 

 

  附錄二:

  實驗工程code下載

 

 

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多