python opencv之SURF算法示例
本文介紹了python opencv之SURF算法示例,分享給大家,具體如下:
目標:
- SURF算法基礎
- opencv總SURF算法的使用
原理:
上節(jié)課使用了SIFT算法,當時這種算法效率不高,需要更快速的算法。在06年有人提出了SURF算法“加速穩(wěn)定特征”,從名字上來看,他是SIFT算法的加速版本。
(原文)
在SIFT算法當中使用高斯差分方程(Difference of Gaussian)對高斯拉普拉斯方程( Laplacian of Gaussian)進行近似。然而,SURF使用盒子濾波器進行近似,下面的圖片顯示了這種近似的方法。在進行卷積計算的時候可以利用積分圖像,這是使用盒子形濾波器的一個優(yōu)點,即計算某個窗口中的像素和的時候,計算量大小,也就是時間復雜度不受到窗口大小的影響。而且,這種運算可以在不用的尺度空間當中實現(xiàn)。
SURF算法計算關鍵點的尺度和位置信息使用Hessian矩陣實現(xiàn)。
(解釋)
文中的高斯拉普拉斯方程(算子)是檢測圖像中斑點的一種十分常用的方法。以一維高斯函數(shù)來檢測一維信號中的斑點為例。有一維信號f,高斯函數(shù)的一階導數(shù)
上面圖片是在一維情況下,使用高斯函數(shù)的一階導數(shù)的情況,另一種方法是使用高斯函數(shù)的二階導數(shù)與信號進行卷積,高斯函數(shù)的二階導數(shù)也叫做拉普拉斯變換。
但是,在一維信號斑點檢測的實際情況當中,一個斑點可以考慮成是兩個相鄰的跳突組成,如下圖。
類似于在圖像當中,一個輪胎可以當成一個斑點,一個蒼蠅也可以當成一個斑點。但是在使用高斯函數(shù)的二階導數(shù)來檢測斑點的時候,使用不同的高斯核(就是方差)運算不同大小的斑點時,計算出來的極值,即響應值會出現(xiàn)衰減。
此時,需要將高斯函數(shù)的二階導數(shù)進行正規(guī)化,去除方差值不同導致響應值出現(xiàn)的衰減。
以上,是一維高斯函數(shù)檢測一維信號的原理。二維的圖像信號,使用二維高斯函數(shù)來檢測斑點原理基本相同,此處的二維高斯函數(shù)的二階導數(shù),就叫做高斯拉普拉斯算子也就是LOG,通過改變不同的方差值,可以檢測不同尺寸的二維斑點,如圖。
文中的高斯差分方程是SIFT算法當中,發(fā)明者想要利用兩個相鄰高斯尺度空間的圖像相減來得到一個LOG的近似,因為這樣做可以節(jié)省時間,而且可以控制精度變化,類似于高等數(shù)學當中泰勒公式那玩意-_- 。關于SIFT原理可以看上一篇博客
文中提到的積分圖像實際上原理非常簡單,類似遞推方程。積分圖像的目的是想建立一個函數(shù),能夠快速得到一個矩形圖像區(qū)域當中所有像素值的和是多少。那么,設
如何求得
文中提到的Hessian矩陣,學過數(shù)學分析、最優(yōu)化、機器學習之類的人肯定對這玩意非常熟悉,實際上黑塞矩陣就是一個多元函數(shù)的二階偏導數(shù)構成的方陣,它的行列式值(Determinant of Hessian )可以反映的局部結(jié)構信息,簡稱DOH。與LOG類似,DOH可以使用不同方差生成高斯函數(shù)對各個元的二階偏導模板,以此來對圖像進行卷積運算。 同樣,DOH也會在卷積后的函數(shù)中,得到對圖像信號斑點極值的響應。如圖
在SURF算法當中,黑塞矩陣中的L,即為二維高斯函數(shù)與圖像的卷積,求得黑塞矩陣后,會得到如圖。
將上面得到的模板與圖像的卷積轉(zhuǎn)換為盒子濾波器,這里使用原文中的圖像,如圖。
得到三個不同的盒子濾波器以后,對其進行近似和簡化操作,并用其表示圖像中某點的斑點響應值,遍歷圖像當中的所有像素,就得到了在某一尺度下斑點檢測的響應圖像。然后,利用不同的模板尺寸,獲取多尺度斑點響應金字塔,在金字塔中搜索極值點,下面的操作就和SIFT算法類似了。
(原文)
為了給找到的特征點賦予方向,以特征點為中心,6s為半徑獲取水平和垂直小波響應運算結(jié)果,這里s是特征點尺度,同時使用高斯加權的方法。然后,他們會被繪制在如下圖當中。其中,特征點的主方向估計運算是有一個弧度為60的扇形窗口,在滑動的過程中不斷計算其中的響應值之和。有趣的是,小波響應值在任意尺度下使用積分圖像很容易被獲取。但是在多數(shù)情況下,旋轉(zhuǎn)不變性不是必須的,可以代碼當中將這一步取消,這樣還能夠提高算法計算速度,而且在+-15度的情況也保持穩(wěn)定,此時該方法稱作 U-SURF。用戶可以設置upright參數(shù),當參數(shù)為0計算方向,參數(shù)為1不計算方向。
對于特征點描述的建立,SURF再一次使用Haar小波響應,同時使用積分圖像使操作變得簡單。在一個矩形區(qū)域當中,以特征點為中心,劃取周圍20s×20s區(qū)域的大小,以特征點為原點,主方向為橫軸,分成四個子區(qū)域,每個子區(qū)域使用2s的Haar小波響應,對于每個子區(qū)域,獲取一個向量,記錄垂直、水平方向上的小波響應值,如圖。
這個特征描述符的長度使64,降低維度可以加速計算,又可以區(qū)分特征。為了更好的區(qū)分特征點,SURF還使用了長度為128特征描述符。當dy小于0或者大于0時,計算dx或|dx|的和。同樣,根據(jù)dx的符號計算不同的dy和。因此能夠獲得雙倍的特征。計算復雜度也不會增加。opencv當中的extended參數(shù)為0或1時分別對應64和128的特征。
另外一個重要的改善是對潛在的興趣點使用了拉普拉斯算子符號(黑塞矩陣的跡)。由于之前的計算已經(jīng)完成對黑塞矩陣的構造,所以這步不會增加復雜度。
拉普拉斯符號在不同明暗背景下區(qū)分不同亮度的斑點,在匹配階段,我們只需要比較擁有相同對比度的特征是否匹配即可,這樣加快了計算速度,如圖。
SURF算法的速度是SIFT速度的3倍,善于處理模糊和旋轉(zhuǎn)的圖像,但是不善于處理視角變化和關照變化。
(解釋)
文中的小波響應運算,全稱是haar小波運算。這里使用haar小波目的是為了獲取圖像梯度,使用之前計算好的圖像積分結(jié)果,這樣能夠提高計算速度。與SIFT算法類似,在對每個特征點獲取主方向時,使用原文中提到的一個π/3大小的扇形窗口,同時以0.2弧度為步長旋轉(zhuǎn)滑動此窗口,在每個窗口當中對的haar響應值的水平方向,垂直方向進行累加。由于時使用一個圓形區(qū)域,轉(zhuǎn)換成類似極坐標矢量的方式來表示,每個窗口中的結(jié)果
主方向最大Haar響應值累加對應的方向。其中,如果除了主方向,還有其它方向的響應累加值較大,算法當中還會額外添加一個特征點,并賦予另外一個次大方向。
文中建立的特征描述符顧名思義,就是描述一個特征點的一組向量,里面唯一確定了一個特征。SURF獲取主方向后,需要獲取特征點描述子。以特征點為原點,主方向為橫軸建立一個二維坐標系,區(qū)域大小是20s×20s,分成是個之塊,每個子塊利用2s的haar模板進行響應計算。然后統(tǒng)計
又4×4個子塊,每個子塊里面記錄四個值,所以描述子一共又4×4×4=64個特征。
最后將沿著主方向的小波響應值扭轉(zhuǎn)過來,原理就是簡單的旋轉(zhuǎn)矩陣。
代碼部分
opencv里面提供的SURF算法和SIFT差不多,這兩個玩意都是受到版權保護的,如果你是用pip 一條命令安裝的opencv,那么恭喜你用不了SURF和SIFT算法,印象中只有2.4.9版本的opencv庫才可以使用。
不過,辦法還是有的,再控制臺當中輸入pip install opencv-contrib-python 就可以用了。
如果還是無法安裝,可以直接網(wǎng)站早opencv-contrib-python的輪子,然后放到對應的文件下安裝就行了。
我的版本是opencv 3.2,和教程文檔中的使用方法不同。
詳細參數(shù)可以自己去查一查,一查一個準的
https://docs.opencv.org/master/d5/df7/classcv_1_1xfeatures2d_1_1SURF.html
import cv2 import numpy as np img = cv2.imread('feng.jpg') #參數(shù)為hessian矩陣的閾值 surf = cv2.xfeatures2d.SURF_create(400) #找到關鍵點和描述符 key_query,desc_query = surf.detectAndCompute(img,None) #把特征點標記到圖片上 img=cv2.drawKeypoints(img,key_query,img) cv2.imshow('sp',img) cv2.waitKey(0)
鳳的嘴上特征點占了這么多,辨識度還是蠻高的~ -_-|||
下面是設置方向,和輸出一些值的方法
import cv2 import numpy as np img = cv2.imread('feng.jpg') #參數(shù)為hessian矩陣的閾值 surf = cv2.xfeatures2d.SURF_create(4000) #設置是否要檢測方向 surf.setUpright(True) #輸出設置值 print(surf.getUpright()) #找到關鍵點和描述符 key_query,desc_query = surf.detectAndCompute(img,None) img=cv2.drawKeypoints(img,key_query,img) #輸出描述符的個數(shù) print(surf.descriptorSize()) cv2.imshow('sp',img) cv2.waitKey(0)
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
使用python實現(xiàn)學生信息管理系統(tǒng)
這篇文章主要為大家詳細介紹了使用python實現(xiàn)學生信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-02-02如何用scheduler實現(xiàn)learning-rate學習率動態(tài)變化
這篇文章主要介紹了如何用scheduler實現(xiàn)learning-rate學習率動態(tài)變化問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09Python實現(xiàn)數(shù)據(jù)庫編程方法詳解
這篇文章主要介紹了Python實現(xiàn)數(shù)據(jù)庫編程方法,較為詳細的總結(jié)了Python數(shù)據(jù)庫編程涉及的各種常用技巧與相關組件,需要的朋友可以參考下2015-06-06Python讀取txt內(nèi)容寫入xls格式excel中的方法
今天小編就為大家分享一篇Python讀取txt內(nèi)容寫入xls格式excel中的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10在django admin中配置搜索域是一個外鍵時的處理方法
這篇文章主要介紹了在django admin中配置搜索域是一個外鍵時的處理方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05Anaconda修改默認虛擬環(huán)境安裝位置的方案分享
新安裝Anaconda后,在創(chuàng)建環(huán)境時環(huán)境自動安裝在C盤,但是C盤空間有限,下面這篇文章主要給大家介紹了關于Anaconda修改默認虛擬環(huán)境安裝位置的相關資料,需要的朋友可以參考下2023-01-01