Python OpenCV學習之特征點檢測與匹配詳解
背景
提取圖像的特征點是圖像領域中的關鍵任務,不管在傳統還是在深度學習的領域中,特征代表著圖像的信息,對於分類、檢測任務都是至關重要的;
特征點應用的一些場景:
圖像搜索:以圖搜圖(電商、教育領域)
圖像拼接:全景拍攝(關聯圖像拼接)
拼圖遊戲:遊戲領域
一、Harris角點
哈裡斯角點檢測主要有以下三種情況:
- 光滑區域:無論向哪個方向移動,衡量系數不變;
- 邊緣區域:垂直邊緣移動時,衡量系數變化強烈;
- 角點區域:不管往哪個方向移動,衡量系數變化強烈;
函數原型:
cornerHarris(img,blockSize,ksize,k)
blockSize
:檢測窗口大小;
k
:權重系數,一般取0.02~0.04之間;
代碼案例:
img = cv2.imread('chess.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) dst = cv2.cornerHarris(gray, 2, 3, 0.04) img[dst > 0.01*dst.max()] = (0, 0, 255) cv2.imshow('harris', img) cv2.waitKey(0)
二、Shi-Tomasi角點檢測
說明:是Harris角點檢測的改進,在Harris中需要知道k這個經驗值,而在Shi-Tomasi不需要;
函數原型:
goodFeaturesToTrack(img,…)
maxCorners
:角點的最大數量,值為0表示所有;
qualityLevel
:角點的質量,一般在0.01~0.1之間(低於的過濾掉);
minDistance
:角點之間最小歐式距離,忽略小於此距離的點;
mask
:感興趣區域;
useHarrisDetector
:是否使用Harris算法(默認為false)
代碼案例:
img = cv2.imread('chess.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) dst = cv2.goodFeaturesToTrack(gray, 1000, 0.01, 10) dst = np.int0(dst) # 實際上也是np.int64 for i in dst: x, y = i.ravel() # 數組降維成一維數組(inplace的方式) cv2.circle(img, (x, y), 3, (0, 0, 255), -1) cv2.imshow('harris', img) cv2.waitKey(0)
本質上和Harris角點檢測相同,效果會好一些,角點數量會多一些;
三、SIFT關鍵點
中文簡譯:與縮放無關的特征轉換;
說明:Harris角點檢測具有旋轉不變性,也就是旋轉圖像並不會影響檢測效果;但其並不具備縮放不變性,縮放大小會影響角點檢測的效果;SIFT具備縮放不變性的性質;
實現步驟:
創建SIFT對象 —— 進行檢測(sift.detect) —— 繪制關鍵點(drawKeypoints)
代碼案例:
img = cv2.imread('chess.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) sift = cv2.xfeatures2d.SIFT_create() kp = sift.detect(gray, None) # 第二個參數為mask區域 cv2.drawKeypoints(gray, kp, img) cv2.imshow('sift', img) cv2.waitKey(0)
四、SIFT描述子
首先需要說明,關鍵點和描述子是兩個概念;
關鍵點:位置、大小和方向;
關鍵點描述子:記錄瞭關鍵點周圍對其有貢獻的像素點的一組向量值,其不受仿射變換,光照變換等影響;描述子的作用就是用於特征匹配;
同時計算關鍵點和描述子的函數(主要使用):
detectAndCompute(img,…)
代碼案例:
img = cv2.imread('chess.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) sift = cv2.xfeatures2d.SIFT_create() kp, dst = sift.detectAndCompute(gray, None) # 第二個參數為mask區域
得到的dst即為描述子的信息;
五、SURF
中譯:加速的魯棒性特征檢測;
說明:SIFT最大的缺點是速度慢,因此才會有SURF(速度快);
實現步驟與SIFT一致,代碼如下:
surf = cv2.xfeatures2d.SURF_create() kp, dst = surf.detectAndCompute(gray, None) # 第二個參數為mask區域 cv2.drawKeypoints(gray, kp, img)
由於安裝的opencv-contrib版本過高(有版權問題),已經不支持該功能瞭,在此就不作展示瞭;
六、ORB
說明:最大的優勢就是做到實時檢測,缺點就是缺失瞭很多信息(準確性下降);
主要是兩個技術的結合:FAST(特征點實時檢測)+ BRIEE(快速描述子建立,降低特征匹配時間)
使用步驟與之前的SIFT一致,代碼如下:
img = cv2.imread('chess.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) orb = cv2.ORB_create() kp, dst = orb.detectAndCompute(gray, None) # 第二個參數為mask區域 cv2.drawKeypoints(gray, kp, img) cv2.imshow('orb', img) cv2.waitKey(0)
可以看出,相比於SIFT以及SURF關鍵點變少瞭,但是其速度有瞭很大提升;
七、暴力特征匹配(BF)
匹配原理:類似於窮舉匹配機制,使用第一組中每個特征的描述子與第二組中的進行匹配,計算相似度,返回最接近的匹配項;
實現步驟:
創建匹配器:BFMatcher(normType,crossCheck)
進行特征匹配:bf.match(des1,des2)
繪制匹配點:cv2.drawMatches(img1,kp1,img2,kp2)
代碼案例:
img1 = cv2.imread('opencv_search.png') img2 = cv2.imread('opencv_orig.png') g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) sift = cv2.SIFT_create() kp1, dst1 = sift.detectAndCompute(g1, None) # 第二個參數為mask區域 kp2, dst2 = sift.detectAndCompute(g2, None) # 第二個參數為mask區域 bf = cv2.BFMatcher_create(cv2.NORM_L1) match = bf.match(dst1, dst2) img3 = cv2.drawMatches(img1, kp1, img2, kp2, match, None) cv2.imshow('result', img3) cv2.waitKey(0)
從上圖可看出,匹配的效果還是不錯的,隻有一個特征點匹配錯誤;
八、FLANN特征匹配
優點:在進行批量特征匹配時,FLANN速度更快;
缺點:由於使用的時鄰近近似值,所有精度較差;
實現步驟與暴力匹配法一致,代碼如下:
img1 = cv2.imread('opencv_search.png') img2 = cv2.imread('opencv_orig.png') g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) sift = cv2.SIFT_create() kp1, dst1 = sift.detectAndCompute(g1, None) # 第二個參數為mask區域 kp2, dst2 = sift.detectAndCompute(g2, None) # 第二個參數為mask區域 index_params = dict(algorithm = 1, trees = 5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matchs = flann.knnMatch(dst1, dst2, k=2) good = [] for i, (m, n) in enumerate(matchs): if m.distance < 0.7 * n.distance: good.append(m) img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None) cv2.imshow('result', img3) cv2.waitKey(0)
上圖可以看出,匹配的特征點數量相比暴力匹配明顯變少瞭,但速度會快很多;
九、圖像查找
實現原理:特征匹配 + 單應性矩陣;
單應性矩陣原理介紹:
上圖中表示從兩個不同角度對原圖的拍攝,其中H為單應性矩陣,可通過該矩陣將圖像進行轉換;
下面使用兩個函數實現圖像查找的功能:
findHomography():獲得單應性矩陣;
perspectivveTransform():仿射變換函數;
代碼實現如下:
img1 = cv2.imread('opencv_search.png') img2 = cv2.imread('opencv_orig.png') g1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) g2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) sift = cv2.SIFT_create() kp1, dst1 = sift.detectAndCompute(g1, None) # 第二個參數為mask區域 kp2, dst2 = sift.detectAndCompute(g2, None) # 第二個參數為mask區域 index_params = dict(algorithm = 1, trees = 5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matchs = flann.knnMatch(dst1, dst2, k=2) good = [] for i, (m, n) in enumerate(matchs): if m.distance < 0.7 * n.distance: good.append(m) if len(good) >= 4: # 獲得源和目標點的數組 srcPts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dstPts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) # 獲得單應性矩陣H H, _ = cv2.findHomography(srcPts, dstPts, cv2.RANSAC, 5.0) h, w = img1.shape[:2] pts = np.float32([[0,0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2) # 進行放射變換 dst = cv2.perspectiveTransform(pts, H) # 繪制查找到的區域 cv2.polylines(img2, [np.int32(dst)], True, (0,0,255)) else: print('good must more then 4.') exit() img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None) cv2.imshow('result', img3) cv2.waitKey(0)
總結
本篇主要介紹瞭特征點檢測和匹配,其中重要的部分時SIFT算法以及FLANN算法;通過所學的知識,可以簡單實現一個圖像查找的功能,也就是找子圖的功能。甚至可以目標識別的效果;當然這裡需要的是完全一致的,不同於深度學習中的目標識別任務
以上就是Python OpenCV學習之特征點檢測與匹配詳解的詳細內容,更多關於Python OpenCV特征點檢測與匹配的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- OpenCV-Python 實現兩張圖片自動拼接成全景圖
- Opencv Python實現兩幅圖像匹配
- Java OpenCV圖像處理之SIFT角點檢測詳解
- 使用python和opencv的mask實現摳圖疊加
- python中opencv圖像疊加、圖像融合、按位操作的具體實現