1. 程式人生 > >opencv影象特徵檢測及匹配(harris,sift,surf,fast,breif,orb,BFmatch,FlannBasedMatcher)

opencv影象特徵檢測及匹配(harris,sift,surf,fast,breif,orb,BFmatch,FlannBasedMatcher)

本文簡單概括各種演算法的提出背景及opencv實現,對具體原理不做討論


一般而言,一個物體的角點最能夠代表物體的特徵,所以所謂的特徵檢測又叫角點(Corner)檢測
harris是最早提出的特徵提取演算法:
opencv實現如下:


dst=cv2.cornerHarris(gray,blockSize=2,ksize=5,k=0.04)
# blockSize -檢測的臨點數
# •ksize - sobel邊緣檢測的核
# •k - 目標函式的一個引數(一般取值較小)


sift:harris Corner演算法能夠解決旋轉不變性問題,但不能解決尺度變化問題,由此背景提出了sift演算法
opencv實現如下:


sift=cv2.xfeatures2d.SIFT_create()
kp,des=sift.detectAndCompute(gray,None) #計算描述子
其中kp指關鍵點 des指關鍵點的特徵描述


surf:儘管sift的計算效果較好,但是計算速度較慢 surf(speed up robust features)演算法是一個加速演算法
速度是sift演算法的3倍。
opencv實現如下:


# 400 是Hessian矩陣的閾值,閾值越大能檢測的特徵就越少
surf=cv2.xfeatures2d.SURF_create(400)
# None為mask引數
kp,des=surf.detectAndCompute(gray,None)


下面結合surf演算法做一個簡單的測試,上程式碼:


import cv2
import numpy as np
import matplotlib.pyplot as plt


img=cv2.imread('../images/example_01.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Here I set Hessian Threshold to 400 閾值越大能檢測的特徵就越少
surf=cv2.xfeatures2d.SURF_create(400)
# None 為mask引數
kp,des=surf.detectAndCompute(gray,None)


surf.setHessianThreshold(5000)
kp,des=surf.detectAndCompute(gray,None)




img2=cv2.drawKeypoints(img,kp,None,(0,255,0),4)
plt.imshow(img2),plt.title('surf'),plt.xticks([]),plt.yticks([]),plt.show()


上效果:


orb演算法結合了fast演算法與brief演算法優點,是目前最快的目標檢測演算法:
fast演算法是特徵檢測的再提速(能夠滿足實時檢測關鍵點的要求),breif是特徵描述子計算的簡化與提速,sift與surf演算法
每個關鍵的特徵描述子是128維都是單精度,所以每個描述子佔128*4=512bytes的記憶體,breif每個特徵描述子32bytes,大大減少記憶體,
且運算快(利於嵌入式開發)
orb的opencv實現:
import numpy as np
import cv2
import matplotlib.pyplot as plt


img=cv2.imread('../images/example_01.jpg',0)


orb=cv2.ORB_create()
# kp=orb.detect(img,None)
# kp,des=orb.compute(img,kp)


kp,des=orb.detectAndCompute(img,None)
img2=cv2.drawKeypoints(img,kp,None,(0,255,0),flags=0)
plt.imshow(img2),plt.show()
上效果:


特徵匹配:
BFmatch(暴力匹配):計算匹配圖層的一個特徵描述子與待匹配圖層的所有特徵描述子的距離返回最近距離。
上程式碼:
import cv2
import numpy as np
import matplotlib.pyplot as plt
train=cv2.imread('../images/train.jpg',0)
query=cv2.imread('../images/example_01.jpg',0)
# 暴力匹配
orb=cv2.ORB_create()
kp1,des1=orb.detectAndCompute(train,None)
kp2,des2=orb.detectAndCompute(query,None)
# 針對ORB演算法 NORM_HAMMING 計算特徵距離 True判斷交叉驗證
bf=cv2.BFMatcher(cv2.NORM_HAMMING,crossCheck=True)
# 特徵描述子匹配
matches=bf.match(des1,des2)


matches=sorted(matches,key=lambda x:x.distance)
# print(len(matches))
img3=cv2.drawMatches(train,kp1,query,kp2,matches[:20],None,flags=2)
plt.imshow(img3),plt.show()

上效果:


FlannBasedMatcher:是目前最快的特徵匹配演算法(最近鄰搜尋)
上程式碼:
import cv2
import numpy as np
import matplotlib.pyplot as plt
train=cv2.imread('../images/train.jpg',0)
query=cv2.imread('../images/example_01.jpg',0)


sift=cv2.xfeatures2d.SIFT_create()
kp1,des1=sift.detectAndCompute(train,None)
kp2,des2=sift.detectAndCompute(query,None)


# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(train,None)
kp2, des2 = sift.detectAndCompute(query,None)


# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary


flann = cv2.FlannBasedMatcher(index_params,search_params)


matches = flann.knnMatch(des1,des2,k=2)


# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]


# ratio test as per Lowe's paper

for i,(m,n) in enumerate(matches):

#如果第一個鄰近距離比第二個鄰近距離的0.7倍小,則保留

    if m.distance < 0.7*n.distance:
        matchesMask[i]=[1,0]


draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)


img3 = cv2.drawMatchesKnn(train,kp1,query,kp2,matches,None,**draw_params)
plt.imshow(img3,),plt.show()


上效果: