特征匹配

Python 使用Opencv實現圖像特征檢測與匹配

2018-06-13 11:36:58?Xy-Huang?閱讀數 19203更多

分類專欄:?Python?人工智能

版權聲明:本文為博主原創文章,遵循?CC 4.0 BY-SA?版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/HuangZhang_123/article/details/80660688

----------歡迎加入學習交流QQ群:657341423


特征檢測是計算機對一張圖像中最為明顯的特征進行識別檢測并將其勾畫出來。大多數特征檢測都會涉及圖像的角點、邊和斑點的識別、或者是物體的對稱軸。
角點檢測?是由Opencv的cornerHarris函數實現,其他函數參數說明如下:

cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04)
# cornerHarris參數:
# src - 數據類型為 float32 的輸入圖像。
# blockSize - 角點檢測中要考慮的領域大小。
# ksize - Sobel 求導中使用的窗口大小
# k - Harris 角點檢測方程中的自由參數,取值參數為 [0,04,0.06].
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以國際象棋為例,這是計算機視覺最為常見的分析對象,如圖所示:
這里寫圖片描述
角點檢測代碼如下:

import cv2
import numpy as npimg = cv2.imread('chess_board.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cornerHarris函數圖像格式為 float32 ,因此需要將圖像轉換 float32 類型
gray = np.float32(gray)
# cornerHarris參數:
# src - 數據類型為 float32 的輸入圖像。
# blockSize - 角點檢測中要考慮的領域大小。
# ksize - Sobel 求導中使用的窗口大小
# k - Harris 角點檢測方程中的自由參數,取值參數為 [0,04,0.06].
dst = cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04)
# 變量a的閾值為0.01 * dst.max(),如果dst的圖像值大于閾值,那么該圖像的像素點設為True,否則為False
# 將圖片每個像素點根據變量a的True和False進行賦值處理,賦值處理是將圖像角點勾畫出來
a = dst>0.01 * dst.max()
img[a] = [0, 0, 255]
# 顯示圖像
while (True):cv2.imshow('corners', img)if cv2.waitKey(120) & 0xff == ord("q"):breakcv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

運行代碼,結果如圖所示:
這里寫圖片描述


但有時候,圖像的像素大小對角點存在一定的影響。比如圖像越小,角點看上去趨向近似一條直線,這樣很容易造成角點的丟失。如果按照上述的檢測方法,會造成角點檢測結果不相符,因此引入DoG和SIFT算法進行檢測Opencv的SIFT類是DoG和SIFT算法組合。
DoG是對同一圖像使用不同高斯濾波器所得的結果。
SIFT是通過一個特征向量來描述關鍵點周圍區域的情況。
我們以下圖為例:
這里寫圖片描述

import cv2
# 讀取圖片并灰度處理
imgpath = 'varese.jpg'
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 創建SIFT對象
sift = cv2.xfeatures2d.SIFT_create()
# 將圖片進行SURF計算,并找出角點keypoints,keypoints是檢測關鍵點
# descriptor是描述符,這是圖像一種表示方式,可以比較兩個圖像的關鍵點描述符,可作為特征匹配的一種方法。
keypoints, descriptor = sift.detectAndCompute(gray, None)# cv2.drawKeypoints() 函數主要包含五個參數:
# image: 原始圖片
# keypoints:從原圖中獲得的關鍵點,這也是畫圖時所用到的數據
# outputimage:輸出
# color:顏色設置,通過修改(b,g,r)的值,更改畫筆的顏色,b=藍色,g=綠色,r=紅色。
# flags:繪圖功能的標識設置,標識如下:
# cv2.DRAW_MATCHES_FLAGS_DEFAULT  默認值
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
# cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG
# cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
img = cv2.drawKeypoints(image=img, outImage=img, keypoints = keypoints, flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT, color = (51, 163, 236))# 顯示圖片
cv2.imshow('sift_keypoints', img)
while (True):if cv2.waitKey(120) & 0xff == ord("q"):break
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

運行代碼,結果如圖所示:
這里寫圖片描述


除了SIFT算法檢測之外,還有SURF特征檢測算法,比SIFT算法快,并吸收了SIFT算法的思想。SURF采用Hessian算法檢測關鍵點,而SURF是提取特征,這個與SIFT很像。Opencv的SURF類是Hessian算法和SURF算法組合。我們根據SIFT的代碼進行修改,代碼如下:

import cv2
# 讀取圖片并灰度處理
imgpath = 'varese.jpg'
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 創建SURF對象,對象參數float(4000)為閾值,閾值越高,識別的特征越小。
sift = cv2.xfeatures2d.SURF_create(float(4000))
# 將圖片進行SURF計算,并找出角點keypoints,keypoints是檢測關鍵點
# descriptor是描述符,這是圖像一種表示方式,可以比較兩個圖像的關鍵點描述符,可作為特征匹配的一種方法。
keypoints, descriptor = sift.detectAndCompute(gray, None)# cv2.drawKeypoints() 函數主要包含五個參數:
# image: 原始圖片
# keypoints:從原圖中獲得的關鍵點,這也是畫圖時所用到的數據
# outputimage:輸出
# color:顏色設置,通過修改(b,g,r)的值,更改畫筆的顏色,b=藍色,g=綠色,r=紅色。
# flags:繪圖功能的標識設置,標識如下:
# cv2.DRAW_MATCHES_FLAGS_DEFAULT  默認值
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
# cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG
# cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
img = cv2.drawKeypoints(image=img, outImage=img, keypoints = keypoints, flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT, color = (51, 163, 236))# 顯示圖片
cv2.imshow('sift_keypoints', img)
while (True):if cv2.waitKey(120) & 0xff == ord("q"):break
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

上述代碼我們只修改sift = cv2.xfeatures2d.SURF_create(float(4000))即可實現SURF特征檢測算法。運行結果如圖所示:
這里寫圖片描述


對比SURF和SIFT算法,ORB算法更處于起步階段,在2011年才首次發布。但比前兩者的速度更快。ORB基于FAST關鍵點檢測和BRIEF的描述符技術相結合,因此我們先了解FAST和BRIEF。
FAST:特征檢測算法。
BRIEF:只是一個描述符,這是圖像一種表示方式,可以比較兩個圖像的關鍵點描述符,可作為特征匹配的一種方法。
暴力匹配:比較兩個描述符并產生匹配結果。
在上述的例子中,我們只是將檢測的關鍵點進行勾畫,在這例子中,將使用ORB檢測關鍵點之外,還將兩圖進行匹配,匹配的圖像如下:
這里寫圖片描述
實現方法:首先分別對兩圖進行ORB處理,然后將兩圖的關鍵點進行暴力匹配。具體代碼如下:
# ORB算法實現特征檢測+暴力匹配

import numpy as np
import cv2
from matplotlib import pyplot as plt# 讀取圖片內容
img1 = cv2.imread('aa.jpg',0)
img2 = cv2.imread('bb.png',0)# 使用ORB特征檢測器和描述符,計算關鍵點和描述符
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)# 暴力匹配BFMatcher,遍歷描述符,確定描述符是否匹配,然后計算匹配距離并排序
# BFMatcher函數參數:
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的優先選擇,NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1,des2)
matches = sorted(matches, key = lambda x:x.distance)
# matches是DMatch對象,具有以下屬性:
# DMatch.distance - 描述符之間的距離。 越低越好。
# DMatch.trainIdx - 訓練描述符中描述符的索引
# DMatch.queryIdx - 查詢描述符中描述符的索引
# DMatch.imgIdx - 訓練圖像的索引。# 使用plt將兩個圖像的匹配結果顯示出來
img3 = cv2.drawMatches(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches, outImg=img2, flags=2)
plt.imshow(img3),plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

運行結果如圖所示:
這里寫圖片描述
# SURF和SIFT算法+暴力匹配
暴力匹配BFMatcher是一種匹配方法,只要提供兩個關鍵點即可實現匹配。若將上述例子改為SURF和SIFT算法,只需修改以下代碼:

將orb = cv2.ORB_create()改為
orb = cv2.xfeatures2d.SURF_create(float(4000))將bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)改為
bf = cv2.BFMatcher(normType=cv2.NORM_L1, crossCheck=True)
  • 1
  • 2
  • 3
  • 4
  • 5

# 獲取匹配關鍵點的坐標位置
在上述例子中,matches是DMatch對象,DMatch是以列表的形式表示,每個元素代表兩圖能匹配得上的點。如果想獲取某個點的坐標位置,在上述例子添加以下代碼:

# 由于匹配順序是:matches = bf.match(des1,des2),先des1后des2。
# 因此,kp1的索引由DMatch對象屬性為queryIdx決定,kp2的索引由DMatch對象屬性為trainIdx決定# 獲取aa.jpg的關鍵點位置
x,y = kp1[matches[0].queryIdx].pt
cv2.rectangle(img1, (int(x),int(y)), (int(x) + 5, int(y) + 5), (0, 255, 0), 2)
cv2.imshow('a', img1)# 獲取bb.png的關鍵點位置
x,y = kp2[matches[0].trainIdx].pt
cv2.rectangle(img2, (int(x1),int(y1)), (int(x1) + 5, int(y1) + 5), (0, 255, 0), 2)
cv2.imshow('b', img2)# 使用plt將兩個圖像的第一個匹配結果顯示出來
img3 = cv2.drawMatches(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches[:1], outImg=img2, flags=2)
plt.imshow(img3),plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

運行結果如圖所示:
這里寫圖片描述


上述講到的暴力匹配是使用BFMatcher匹配器實現的,然后由match函數實現匹配。接下來講解K-最近鄰匹配(KNN),并在BFMatcher匹配下實現。在所有機器學習的算法中,KNN可能是最為簡單的算法。針對上述例子,改為KNN匹配,實現代碼如下:

import numpy as np
import cv2
from matplotlib import pyplot as plt# 讀取圖片內容
img1 = cv2.imread('aa.jpg',0)
img2 = cv2.imread('bb.png',0)# 使用ORB特征檢測器和描述符,計算關鍵點和描述符
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)# 暴力匹配BFMatcher,遍歷描述符,確定描述符是否匹配,然后計算匹配距離并排序
# BFMatcher函數參數:
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的優先選擇,NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
# knnMatch 函數參數k是返回符合匹配的個數,暴力匹配match只返回最佳匹配結果。
matches = bf.knnMatch(des1,des2,k=1)# 使用plt將兩個圖像的第一個匹配結果顯示出來
# 若使用knnMatch進行匹配,則需要使用drawMatchesKnn函數將結果顯示
img3 = cv2.drawMatchesKnn(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches, outImg=img2, flags=2)
plt.imshow(img3),plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

最后是介紹FLANN匹配,相對暴力匹配BFMatcher來講,這匹配算法比較準確、快速和使用方便。FLANN具有一種內部機制,可以根據數據本身選擇最合適的算法來處理數據集。值得注意的是,FLANN匹配器只能使用SURF和SIFT算法。
FLANN實現方式如下:

import numpy as np
import cv2
from matplotlib import pyplot as pltqueryImage = cv2.imread('aa.jpg',0)
trainingImage = cv2.imread('bb.png',0)# 只使用SIFT 或 SURF 檢測角點
sift = cv2.xfeatures2d.SIFT_create()
# sift = cv2.xfeatures2d.SURF_create(float(4000))
kp1, des1 = sift.detectAndCompute(queryImage,None)
kp2, des2 = sift.detectAndCompute(trainingImage,None)# 設置FLANN匹配器參數
# algorithm設置可參考https://docs.opencv.org/3.1.0/dc/d8c/namespacecvflann.html
indexParams = dict(algorithm=0, trees=5)
searchParams = dict(checks=50)
# 定義FLANN匹配器
flann = cv2.FlannBasedMatcher(indexParams,searchParams)
# 使用 KNN 算法實現匹配
matches = flann.knnMatch(des1,des2,k=2)# 根據matches生成相同長度的matchesMask列表,列表元素為[0,0]
matchesMask = [[0,0] for i in range(len(matches))]# 去除錯誤匹配
for i,(m,n) in enumerate(matches):if m.distance < 0.7*n.distance:matchesMask[i] = [1,0]# 將圖像顯示
# matchColor是兩圖的匹配連接線,連接線與matchesMask相關
# singlePointColor是勾畫關鍵點
drawParams = dict(matchColor = (0,255,0),singlePointColor = (255,0,0),matchesMask = matchesMask,flags = 0)
resultImage = cv2.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches,None,**drawParams)
plt.imshow(resultImage,),plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

運行結果如圖所示:
這里寫圖片描述


FLANN的單應性匹配,單應性是一個條件,該條件表面當兩幅圖像中的一副出像投影畸變時,他們還能匹配。FLANN的單應性實現代碼如下:

import numpy as np
import cv2
from matplotlib import pyplot as pltMIN_MATCH_COUNT = 10img1 = cv2.imread('tattoo_seed.jpg',0)
img2 = cv2.imread('hush.jpg',0)# 使用SIFT檢測角點
sift = cv2.xfeatures2d.SIFT_create()
# 獲取關鍵點和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)# 定義FLANN匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 使用KNN算法匹配
matches = flann.knnMatch(des1,des2,k=2)# 去除錯誤匹配
good = []
for m,n in matches:if m.distance < 0.7*n.distance:good.append(m)# 單應性
if len(good)>MIN_MATCH_COUNT:# 改變數組的表現形式,不改變數據內容,數據內容是每個關鍵點的坐標位置src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)# findHomography 函數是計算變換矩陣# 參數cv2.RANSAC是使用RANSAC算法尋找一個最佳單應性矩陣H,即返回值M# 返回值:M 為變換矩陣,mask是掩模M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)# ravel方法將數據降維處理,最后并轉換成列表格式matchesMask = mask.ravel().tolist()# 獲取img1的圖像尺寸h,w = img1.shape# pts是圖像img1的四個頂點pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)# 計算變換后的四個頂點坐標位置dst = cv2.perspectiveTransform(pts,M)# 根據四個頂點坐標位置在img2圖像畫出變換后的邊框img2 = cv2.polylines(img2,[np.int32(dst)],True,(255,0,0),3, cv2.LINE_AA)else:print("Not enough matches are found - %d/%d") % (len(good),MIN_MATCH_COUNT)matchesMask = None# 顯示匹配結果
draw_params = dict(matchColor = (0,255,0), # draw matches in green colorsinglePointColor = None,matchesMask = matchesMask, # draw only inliersflags = 2)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.imshow(img3, 'gray'),plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

運行結果如下所示:
這里寫圖片描述

單應性實際應用
從上述的例子可以看到,單應性是在兩圖片匹配的時候,其中某一圖片發生變換處理,變換后圖像會呈現一種立體空間的視覺效果,圖像發生變換程度稱為變換矩陣。以下例子將圖像中的書本替換成其他書本,例子中所使用圖片如下:

這里寫圖片描述
這里寫圖片描述
我們根據圖1和圖2計算變換矩陣,然后通過變換矩陣將圖3進行變換,最后將圖3加入到圖1中,實現圖片替換。實現代碼如下:

import numpy as np
import cv2
from matplotlib import pyplot as pltimg1 = cv2.imread('logo.jpg',0)
img2 = cv2.imread('book.jpg',0)# 使用SIFT檢測角點
sift = cv2.xfeatures2d.SIFT_create()
# 獲取關鍵點和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)# 定義FLANN匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 使用KNN算法匹配
matches = flann.knnMatch(des1,des2,k=2)# 去除錯誤匹配
good = []
for m,n in matches:if m.distance < 0.7*n.distance:good.append(m)# 單應性實際應用
# 改變數組的表現形式,不改變數據內容,數據內容是每個關鍵點的坐標位置
src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
# findHomography 函數是計算變換矩陣
# 參數cv2.RANSAC是使用RANSAC算法尋找一個最佳單應性矩陣H,即返回值M
# 返回值:M 為變換矩陣,mask是掩模
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
# 獲取img1的圖像尺寸
h,w = img1.shape
# pts是圖像img1的四個頂點
pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
# 計算變換后的四個頂點坐標位置
dst = cv2.perspectiveTransform(pts,M)# 圖片替換
img3 = cv2.imread('aa.png',0)
# 降維處理
b = np.int32(dst).reshape(4, 2)
x,y = img2.shape
# 根據變換矩陣將圖像img3進行變換處理
res = cv2.warpPerspective(img3, M, (y,x))
img_temp = img2.copy()
# 將圖像img2的替換區域進行填充處理
cv2.fillConvexPoly(img_temp, b, 0)
# 將變換后的img3圖像替換到圖像img2
cv2.imshow('bb',img_temp)
res = img_temp + res
cv2.imshow('aa',res)
plt.imshow(res),plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

運行結果如圖所示:
這里寫圖片描述
從結果可以看到,替換后的圖像周邊出現黑色線條,這是正常的現象。在上圖最左邊的圖bb可以看到,黑色區域是由圖1和圖2檢測匹配所得的結果,如果匹配結果會存在一定的誤差,這個誤差是由多個因素所導致的。


在實際中,我們根據一張圖片在眾多的圖片中查找匹配率最高的圖片。如果按照上面的例子,也可以實現,但每次匹配時都需要重新檢測圖片的特征數據,這樣會導致程序運行效率。因此,我們可以將圖片的特征數據進行保存,每次匹配時,只需讀取特征數據進行匹配即可。我們以下圖為例:
這里寫圖片描述
這里寫圖片描述
我們根據圖1在圖2中查找最佳匹配的圖片。首先獲取圖2的全部圖片的特征數據,將代碼保存在features.py:

import cv2
import numpy as np
from os import walk
from os.path import joindef create_descriptors(folder):files = []for (dirpath, dirnames, filenames) in walk(folder):files.extend(filenames)for f in files:if '.jpg' in f:save_descriptor(folder, f, cv2.xfeatures2d.SIFT_create())def save_descriptor(folder, image_path, feature_detector):# 判斷圖片是否為npy格式if image_path.endswith("npy"):return# 讀取圖片并檢查特征img = cv2.imread(join(folder,image_path), 0)keypoints, descriptors = feature_detector.detectAndCompute(img, None)# 設置文件名并將特征數據保存到npy文件descriptor_file = image_path.replace("jpg", "npy")np.save(join(folder, descriptor_file), descriptors)if __name__=='__main__':path = 'E:\\anchors'create_descriptors(path)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

運行代碼,結果如圖所示:
這里寫圖片描述
我們將圖片的特征數據保存在npy文件。下一步是根據圖1與這些特征數據文件進行匹配,從而找出最佳匹配的圖片。代碼存在matching.py:

from os.path import join
from os import walk
import numpy as np
import cv2query = cv2.imread('tattoo_seed.jpg', 0)
folder = 'E:\\anchors'
descriptors = []
# 獲取特征數據文件名
for (dirpath, dirnames, filenames) in walk(folder):for f in filenames:if f.endswith("npy"):descriptors.append(f)print(descriptors)# 使用SIFT算法檢查圖像的關鍵點和描述符
sift = cv2.xfeatures2d.SIFT_create()
query_kp, query_ds = sift.detectAndCompute(query, None)# 創建FLANN匹配器
index_params = dict(algorithm=0, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)potential_culprits = {}
for d in descriptors:# 將圖像query與特征數據文件的數據進行匹配matches = flann.knnMatch(query_ds, np.load(join(folder, d)), k=2)# 清除錯誤匹配good = []for m, n in matches:if m.distance < 0.7 * n.distance:good.append(m)# 輸出每張圖片與目標圖片的匹配數目print("img is %s ! matching rate is (%d)" % (d, len(good)))potential_culprits[d] = len(good)# 獲取最多匹配數目的圖片
max_matches = None
potential_suspect = None
for culprit, matches in potential_culprits.items():if max_matches == None or matches > max_matches:max_matches = matchespotential_suspect = culpritprint("potential suspect is %s" % potential_suspect.replace("npy", "").upper())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

代碼運行后,輸出結果如圖所示:
這里寫圖片描述
從輸出的結果可以看到,圖1與圖2的hush.jpg最為匹配,如圖所示:
這里寫圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251968.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251968.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

bzoj 1015 并查集

代碼&#xff1a; //這題可以反著想&#xff0c;把要去掉的點倒著處理變成往圖中一個一個的加點&#xff0c;然后用并查集處理聯通快就好了。 #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const in…

頁面中切換echarts主題

要做的效果是&#xff1a;點擊下拉框切換echarts主題 下面是效果圖&#xff1a; 項目環境&#xff1a; vue ts es6 echarts(4.2.1) 步驟 安裝依賴&#xff0c; npm install echarts -S / yarn add echarts -S引入主題 參考鏈接選擇下拉框中的主題時&#xff0c;拿到圖表主題…

畫極線

OpenCV學習日記5 2017-05-27 10:44:35 1000sprites 閱讀數 2339更多 分類專欄&#xff1a; 計算機視覺 版權聲明&#xff1a;本文為博主原創文章&#xff0c;遵循 CC 4.0 BY-SA 版權協議&#xff0c;轉載請附上原文出處鏈接和本聲明。 本文鏈接&#xff1a;https://blog.cs…

Win10開啟Administrator超級管理員賬戶

方法1 1、在系統的開始菜單上&#xff0c;我們單擊鼠標右鍵&#xff0c;然后選擇計算機管理打開進入 2、打開的計算機管理窗口&#xff0c;點擊本地用戶和組中的用戶打開&#xff0c;然后點擊右側的Administrator賬戶&#xff0c;雙擊鼠標打開進入 3、打開的屬性窗口中&#xf…

Mysql異常問題排查與處理——mysql的DNS反向解析和客戶端網卡重啟

中午剛想趴一會&#xff0c;不料鍋從天降&#xff01;&#xff01;&#xff01;Mysql連不上了。。。。。。。 現象如下&#xff1a; 現象1&#xff1a;登錄mysql所在服務器&#xff0c;連接MySQL 成功&#xff1b; 現象2&#xff1a;通過客戶端遠程連接MySQL&#xff0c;返回失…

最近很火的MySQL:拋開復雜的架構設計,MySQL優化思想基本都在這

優化一覽圖 優化 筆者將優化分為了兩大類&#xff1a;軟優化和硬優化。軟優化一般是操作數據庫即可&#xff1b;而硬優化則是操作服務器硬件及參數設置。 1、軟優化 1&#xff09;查詢語句優化 首先我們可以用EXPLAIN或DESCRIBE(簡寫:DESC)命令分析一條查詢語句的執行信息。 例…

【讀書筆記】《深入淺出Webpack》

Webpack版本 分析版本為3.6.0 4.0為最近升級的版本&#xff0c;與之前版本變化較大&#xff0c;編譯輸出的文件與3.0版本會不一致&#xff0c;目前項目中使用的版本3.0版本&#xff0c;所以基于3.0版本進行分析學習。 Webpack構建流程 初始化&#xff1a;啟動構建&#xff0c;讀…

《JAVA與模式》之橋梁模式

在閻宏博士的《JAVA與模式》一書中開頭是這樣描述橋梁&#xff08;Bridge&#xff09;模式的&#xff1a; 橋梁模式是對象的結構模式。又稱為柄體(Handle and Body)模式或接口(Interface)模式。橋梁模式的用意是“將抽象化(Abstraction)與實現化(Implementation)脫耦&#xff0…

LABLEME UPDATE DAMOD

Labelme的改進——海量圖片的自動標注 深度學習一般需要對大量的圖片進行標注&#xff0c;但是手動標注耗時耗力&#xff0c;所以模仿labelme軟件的功能&#xff0c;使用程序對大批量的圖片進行自動標注&#xff0c;大大減少手動操作。下面介紹如何實現對大批量的圖片進行標…

Java基礎教程:面向對象編程[2]

Java基礎教程&#xff1a;面向對象編程[2] 內容大綱 訪問修飾符 四種訪問修飾符 Java中&#xff0c;可以使用訪問控制符來保護對類、變量、方法和構造方法的訪問。Java 支持 4 種不同的訪問權限。 default (即缺省&#xff0c;什么也不寫&#xff09;: 在同一包內可見&#xff…

【javascript】異步編年史,從“純回調”到Promise

異步和分塊——程序的分塊執行 一開始學習javascript的時候&#xff0c; 我對異步的概念一臉懵逼&#xff0c; 因為當時百度了很多文章&#xff0c;但很多各種文章不負責任的把籠統的描述混雜在一起&#xff0c;讓我對這個 JS中的重要概念難以理解&#xff0c; “異步是非阻塞的…

Shell編程之if語法練習(LNMP)全過程

大家好&#xff0c;我是延凱&#xff0c;本人原來在CSDN寫作已經快一年了 都是相關Linux運維這方面的技術知識&#xff0c;現在搬到博客園也是我一直想的&#xff0c;本博客主要寫Python&#xff0c;docker&#xff0c;shell等偏向開發云計算等知識點&#xff0c;謝謝各位&…

基于UNet和camvid數據集的道路分割

基于UNet和camvid數據集的道路分割h(1.3.0)&#xff1a; 背景 語義分割是深度學習中的一個非常重要的研究方向&#xff0c;并且UNet是語義分割中一個非常經典的模型。在本次博客中&#xff0c;我嘗試用UNet對camvid dataset數據集進行道路分割&#xff0c;大致期望的效果如下&…

二分法查找和普通查找

一、普通查找 對于數組和一個需要查找的元素來說&#xff0c;普通查找的原理很簡單&#xff0c;即為從數組的第一個元素到最后一個元素進行遍歷&#xff0c;如果第i個元素的值等于我們需要查找的值&#xff0c;那么返回找到的角標i&#xff0c;否則返回-1表示沒有查找到。這里以…

Linux下安裝zookeeper集群(奇數個)

1、 解壓zookeeper壓縮包 2、 data里創建“myid”文件&#xff08;命令touch myid&#xff09;&#xff0c;內容是1&#xff08;命令 echo 1 >> myid&#xff09; 3、 zoo.cnf里配置dataDir、clientport、server.nIP:端口1&#xff08;2881&#xff09;&#xff1a;端…

立體標定

立體標定應用標定數據轉換成深度圖標定 由于攝像頭目前是我們手動進行定位的&#xff0c;我們現在還不知道兩張圖像與世界坐標之間的耦合關系&#xff0c;所以下一步要進行的是標定&#xff0c;用來確定分別獲取兩個攝像頭的內部參數&#xff0c;并且根據兩個攝像頭在同一個世…

if _name_ == _main_

1.作用 py文件有2種使用方法&#xff0c;第1是自己本腳本自己獨立執行&#xff1b;第2是被import到其他文件腳本中執行. if _name_ " _main_" 該語句控制其他下一步的腳本是否執行。如果是自己本腳本獨立執行&#xff0c;那就運行該if條件下的腳本&#xff1b;如果…

LLVM完整參考安裝

文章目錄 一、直接下載編譯好的,見圖片命令二、下載源代碼自己編譯安裝 下面提供下載并mv完全的文件包三、安裝LLVM編譯器一、直接下載編譯好的,見圖片命令 這里使用llvm官網編譯好的包, 直接解壓即可用LLVM下載官網點擊這里下載llvm-6.0.1 下載完成后解壓tar -vxf clangllv…

微軟正式釋出基于 Chromium 的 Edge 預覽版本

百度智能云域名服務&#xff0c;.com新用戶首購僅需25元 微軟基于 Chromium 的全新版本 Edge 一直吸引著開發者與用戶的目光&#xff0c;當地時間 8 日&#xff0c;官方終于釋出了第一個 Dev 和 Canary 頻道構建版本。 Dev 與 Canary build 都是開發者預覽版&#xff0c;同屬…

下載和安裝R、RStudio !

現如今&#xff0c;R語言是統計領域廣泛使用的工具&#xff0c;是屬于GNU系統的一個自由、免費、源代碼開放的軟件&#xff0c;是用于統計計算和統計繪圖的優秀工具。而RStudio是R的集成開發環境&#xff0c;用它進行R編程的學習和實踐會更加輕松和方便。下面就教大家如何下載并…