溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

發(fā)布時(shí)間:2020-09-15 19:31:35 來源:腳本之家 閱讀:325 作者:Xy-Huang 欄目:開發(fā)技術(shù)

特征檢測是計(jì)算機(jī)對一張圖像中最為明顯的特征進(jìn)行識別檢測并將其勾畫出來。大多數(shù)特征檢測都會(huì)涉及圖像的角點(diǎn)、邊和斑點(diǎn)的識別、或者是物體的對稱軸。

角點(diǎn)檢測 是由Opencv的cornerHarris函數(shù)實(shí)現(xiàn),其他函數(shù)參數(shù)說明如下:

cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04)
# cornerHarris參數(shù):
# src - 數(shù)據(jù)類型為 float32 的輸入圖像。
# blockSize - 角點(diǎn)檢測中要考慮的領(lǐng)域大小。
# ksize - Sobel 求導(dǎo)中使用的窗口大小
# k - Harris 角點(diǎn)檢測方程中的自由參數(shù),取值參數(shù)為 [0,04,0.06].

以國際象棋為例,這是計(jì)算機(jī)視覺最為常見的分析對象,如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

角點(diǎn)檢測代碼如下:

import cv2
import numpy as np

img = cv2.imread('chess_board.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cornerHarris函數(shù)圖像格式為 float32 ,因此需要將圖像轉(zhuǎn)換 float32 類型
gray = np.float32(gray)
# cornerHarris參數(shù):
# src - 數(shù)據(jù)類型為 float32 的輸入圖像。
# blockSize - 角點(diǎn)檢測中要考慮的領(lǐng)域大小。
# ksize - Sobel 求導(dǎo)中使用的窗口大小
# k - Harris 角點(diǎn)檢測方程中的自由參數(shù),取值參數(shù)為 [0,04,0.06].
dst = cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04)
# 變量a的閾值為0.01 * dst.max(),如果dst的圖像值大于閾值,那么該圖像的像素點(diǎn)設(shè)為True,否則為False
# 將圖片每個(gè)像素點(diǎn)根據(jù)變量a的True和False進(jìn)行賦值處理,賦值處理是將圖像角點(diǎn)勾畫出來
a = dst>0.01 * dst.max()
img[a] = [0, 0, 255]
# 顯示圖像
while (True):
 cv2.imshow('corners', img)
 if cv2.waitKey(120) & 0xff == ord("q"):
  break
 cv2.destroyAllWindows()

運(yùn)行代碼,結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

但有時(shí)候,圖像的像素大小對角點(diǎn)存在一定的影響。比如圖像越小,角點(diǎn)看上去趨向近似一條直線,這樣很容易造成角點(diǎn)的丟失。如果按照上述的檢測方法,會(huì)造成角點(diǎn)檢測結(jié)果不相符,因此引入DoG和SIFT算法進(jìn)行檢測Opencv的SIFT類是DoG和SIFT算法組合。

DoG是對同一圖像使用不同高斯濾波器所得的結(jié)果。

SIFT是通過一個(gè)特征向量來描述關(guān)鍵點(diǎn)周圍區(qū)域的情況。

我們以下圖為例:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

import cv2
# 讀取圖片并灰度處理
imgpath = 'varese.jpg'
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 創(chuàng)建SIFT對象
sift = cv2.xfeatures2d.SIFT_create()
# 將圖片進(jìn)行SURF計(jì)算,并找出角點(diǎn)keypoints,keypoints是檢測關(guān)鍵點(diǎn)
# descriptor是描述符,這是圖像一種表示方式,可以比較兩個(gè)圖像的關(guān)鍵點(diǎn)描述符,可作為特征匹配的一種方法。
keypoints, descriptor = sift.detectAndCompute(gray, None)

# cv2.drawKeypoints() 函數(shù)主要包含五個(gè)參數(shù):
# image: 原始圖片
# keypoints:從原圖中獲得的關(guān)鍵點(diǎn),這也是畫圖時(shí)所用到的數(shù)據(jù)
# outputimage:輸出
# color:顏色設(shè)置,通過修改(b,g,r)的值,更改畫筆的顏色,b=藍(lán)色,g=綠色,r=紅色。
# flags:繪圖功能的標(biāo)識設(shè)置,標(biāo)識如下:
# cv2.DRAW_MATCHES_FLAGS_DEFAULT 默認(rèn)值
# 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()

運(yùn)行代碼,結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

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

import cv2
# 讀取圖片并灰度處理
imgpath = 'varese.jpg'
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 創(chuàng)建SURF對象,對象參數(shù)float(4000)為閾值,閾值越高,識別的特征越小。
sift = cv2.xfeatures2d.SURF_create(float(4000))
# 將圖片進(jìn)行SURF計(jì)算,并找出角點(diǎn)keypoints,keypoints是檢測關(guān)鍵點(diǎn)
# descriptor是描述符,這是圖像一種表示方式,可以比較兩個(gè)圖像的關(guān)鍵點(diǎn)描述符,可作為特征匹配的一種方法。
keypoints, descriptor = sift.detectAndCompute(gray, None)

# cv2.drawKeypoints() 函數(shù)主要包含五個(gè)參數(shù):
# image: 原始圖片
# keypoints:從原圖中獲得的關(guān)鍵點(diǎn),這也是畫圖時(shí)所用到的數(shù)據(jù)
# outputimage:輸出
# color:顏色設(shè)置,通過修改(b,g,r)的值,更改畫筆的顏色,b=藍(lán)色,g=綠色,r=紅色。
# flags:繪圖功能的標(biāo)識設(shè)置,標(biāo)識如下:
# cv2.DRAW_MATCHES_FLAGS_DEFAULT 默認(rèn)值
# 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()

上述代碼我們只修改sift = cv2.xfeatures2d.SURF_create(float(4000))即可實(shí)現(xiàn)SURF特征檢測算法。運(yùn)行結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

對比SURF和SIFT算法,ORB算法更處于起步階段,在2011年才首次發(fā)布。但比前兩者的速度更快。ORB基于FAST關(guān)鍵點(diǎn)檢測和BRIEF的描述符技術(shù)相結(jié)合,因此我們先了解FAST和BRIEF。

FAST:特征檢測算法。

BRIEF:只是一個(gè)描述符,這是圖像一種表示方式,可以比較兩個(gè)圖像的關(guān)鍵點(diǎn)描述符,可作為特征匹配的一種方法。

暴力匹配:比較兩個(gè)描述符并產(chǎn)生匹配結(jié)果。

在上述的例子中,我們只是將檢測的關(guān)鍵點(diǎn)進(jìn)行勾畫,在這例子中,將使用ORB檢測關(guān)鍵點(diǎn)之外,還將兩圖進(jìn)行匹配,匹配的圖像如下:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

實(shí)現(xiàn)方法:首先分別對兩圖進(jìn)行ORB處理,然后將兩圖的關(guān)鍵點(diǎn)進(jìn)行暴力匹配。具體代碼如下:

# ORB算法實(shí)現(xiàn)特征檢測+暴力匹配

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

# 讀取圖片內(nèi)容
img1 = cv2.imread('aa.jpg',0)
img2 = cv2.imread('bb.png',0)

# 使用ORB特征檢測器和描述符,計(jì)算關(guān)鍵點(diǎn)和描述符
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)


# 暴力匹配BFMatcher,遍歷描述符,確定描述符是否匹配,然后計(jì)算匹配距離并排序
# BFMatcher函數(shù)參數(shù):
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的優(yōu)先選擇,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 - 訓(xùn)練描述符中描述符的索引
# DMatch.queryIdx - 查詢描述符中描述符的索引
# DMatch.imgIdx - 訓(xùn)練圖像的索引。

# 使用plt將兩個(gè)圖像的匹配結(jié)果顯示出來
img3 = cv2.drawMatches(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches, outImg=img2, flags=2)
plt.imshow(img3),plt.show()

運(yùn)行結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

# SURF和SIFT算法+暴力匹配

暴力匹配BFMatcher是一種匹配方法,只要提供兩個(gè)關(guān)鍵點(diǎn)即可實(shí)現(xiàn)匹配。若將上述例子改為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)

# 獲取匹配關(guān)鍵點(diǎn)的坐標(biāo)位置

在上述例子中,matches是DMatch對象,DMatch是以列表的形式表示,每個(gè)元素代表兩圖能匹配得上的點(diǎn)。如果想獲取某個(gè)點(diǎn)的坐標(biāo)位置,在上述例子添加以下代碼:

# 由于匹配順序是:matches = bf.match(des1,des2),先des1后des2。
# 因此,kp1的索引由DMatch對象屬性為queryIdx決定,kp2的索引由DMatch對象屬性為trainIdx決定

# 獲取aa.jpg的關(guān)鍵點(diǎn)位置
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的關(guān)鍵點(diǎn)位置
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將兩個(gè)圖像的第一個(gè)匹配結(jié)果顯示出來
img3 = cv2.drawMatches(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches[:1], outImg=img2, flags=2)
plt.imshow(img3),plt.show()

運(yùn)行結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

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

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

# 讀取圖片內(nèi)容
img1 = cv2.imread('aa.jpg',0)
img2 = cv2.imread('bb.png',0)

# 使用ORB特征檢測器和描述符,計(jì)算關(guān)鍵點(diǎn)和描述符
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# 暴力匹配BFMatcher,遍歷描述符,確定描述符是否匹配,然后計(jì)算匹配距離并排序
# BFMatcher函數(shù)參數(shù):
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的優(yōu)先選擇,NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
# knnMatch 函數(shù)參數(shù)k是返回符合匹配的個(gè)數(shù),暴力匹配match只返回最佳匹配結(jié)果。
matches = bf.knnMatch(des1,des2,k=1)

# 使用plt將兩個(gè)圖像的第一個(gè)匹配結(jié)果顯示出來
# 若使用knnMatch進(jìn)行匹配,則需要使用drawMatchesKnn函數(shù)將結(jié)果顯示
img3 = cv2.drawMatchesKnn(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches, outImg=img2, flags=2)
plt.imshow(img3),plt.show()

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

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

queryImage = cv2.imread('aa.jpg',0)
trainingImage = cv2.imread('bb.png',0)

# 只使用SIFT 或 SURF 檢測角點(diǎn)
sift = cv2.xfeatures2d.SIFT_create()
# sift = cv2.xfeatures2d.SURF_create(float(4000))
kp1, des1 = sift.detectAndCompute(queryImage,None)
kp2, des2 = sift.detectAndCompute(trainingImage,None)

# 設(shè)置FLANN匹配器參數(shù)
# algorithm設(shè)置可參考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 算法實(shí)現(xiàn)匹配
matches = flann.knnMatch(des1,des2,k=2)

# 根據(jù)matches生成相同長度的matchesMask列表,列表元素為[0,0]
matchesMask = [[0,0] for i in range(len(matches))]

# 去除錯(cuò)誤匹配
for i,(m,n) in enumerate(matches):
  if m.distance < 0.7*n.distance:
    matchesMask[i] = [1,0]

# 將圖像顯示
# matchColor是兩圖的匹配連接線,連接線與matchesMask相關(guān)
# singlePointColor是勾畫關(guān)鍵點(diǎn)
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()

運(yùn)行結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

FLANN的單應(yīng)性匹配,單應(yīng)性是一個(gè)條件,該條件表面當(dāng)兩幅圖像中的一副出像投影畸變時(shí),他們還能匹配。FLANN的單應(yīng)性實(shí)現(xiàn)代碼如下:

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

MIN_MATCH_COUNT = 10

img1 = cv2.imread('tattoo_seed.jpg',0)
img2 = cv2.imread('hush.jpg',0)

# 使用SIFT檢測角點(diǎn)
sift = cv2.xfeatures2d.SIFT_create()
# 獲取關(guān)鍵點(diǎn)和描述符
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)

# 去除錯(cuò)誤匹配
good = []
for m,n in matches:
  if m.distance < 0.7*n.distance:
    good.append(m)

# 單應(yīng)性
if len(good)>MIN_MATCH_COUNT:
  # 改變數(shù)組的表現(xiàn)形式,不改變數(shù)據(jù)內(nèi)容,數(shù)據(jù)內(nèi)容是每個(gè)關(guān)鍵點(diǎn)的坐標(biāo)位置
  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 函數(shù)是計(jì)算變換矩陣
  # 參數(shù)cv2.RANSAC是使用RANSAC算法尋找一個(gè)最佳單應(yīng)性矩陣H,即返回值M
  # 返回值:M 為變換矩陣,mask是掩模
  M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
  # ravel方法將數(shù)據(jù)降維處理,最后并轉(zhuǎn)換成列表格式
  matchesMask = mask.ravel().tolist()
  # 獲取img1的圖像尺寸
  h,w = img1.shape
  # pts是圖像img1的四個(gè)頂點(diǎn)
  pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
  # 計(jì)算變換后的四個(gè)頂點(diǎn)坐標(biāo)位置
  dst = cv2.perspectiveTransform(pts,M)

  # 根據(jù)四個(gè)頂點(diǎn)坐標(biāo)位置在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

# 顯示匹配結(jié)果
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
          singlePointColor = None,
          matchesMask = matchesMask, # draw only inliers
          flags = 2)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.imshow(img3, 'gray'),plt.show()

運(yùn)行結(jié)果如下所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

單應(yīng)性實(shí)際應(yīng)用

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

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

我們根據(jù)圖1和圖2計(jì)算變換矩陣,然后通過變換矩陣將圖3進(jìn)行變換,最后將圖3加入到圖1中,實(shí)現(xiàn)圖片替換。實(shí)現(xiàn)代碼如下:

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

img1 = cv2.imread('logo.jpg',0)
img2 = cv2.imread('book.jpg',0)

# 使用SIFT檢測角點(diǎn)
sift = cv2.xfeatures2d.SIFT_create()
# 獲取關(guān)鍵點(diǎn)和描述符
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)

# 去除錯(cuò)誤匹配
good = []
for m,n in matches:
  if m.distance < 0.7*n.distance:
    good.append(m)

# 單應(yīng)性實(shí)際應(yīng)用
# 改變數(shù)組的表現(xiàn)形式,不改變數(shù)據(jù)內(nèi)容,數(shù)據(jù)內(nèi)容是每個(gè)關(guān)鍵點(diǎn)的坐標(biāo)位置
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 函數(shù)是計(jì)算變換矩陣
# 參數(shù)cv2.RANSAC是使用RANSAC算法尋找一個(gè)最佳單應(yīng)性矩陣H,即返回值M
# 返回值:M 為變換矩陣,mask是掩模
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
# 獲取img1的圖像尺寸
h,w = img1.shape
# pts是圖像img1的四個(gè)頂點(diǎn)
pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
# 計(jì)算變換后的四個(gè)頂點(diǎn)坐標(biāo)位置
dst = cv2.perspectiveTransform(pts,M)

# 圖片替換
img3 = cv2.imread('aa.png',0)
# 降維處理
b = np.int32(dst).reshape(4, 2)
x,y = img2.shape
# 根據(jù)變換矩陣將圖像img3進(jìn)行變換處理
res = cv2.warpPerspective(img3, M, (y,x))
img_temp = img2.copy()
# 將圖像img2的替換區(qū)域進(jìn)行填充處理
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()

運(yùn)行結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

從結(jié)果可以看到,替換后的圖像周邊出現(xiàn)黑色線條,這是正常的現(xiàn)象。在上圖最左邊的圖bb可以看到,黑色區(qū)域是由圖1和圖2檢測匹配所得的結(jié)果,如果匹配結(jié)果會(huì)存在一定的誤差,這個(gè)誤差是由多個(gè)因素所導(dǎo)致的。

在實(shí)際中,我們根據(jù)一張圖片在眾多的圖片中查找匹配率最高的圖片。如果按照上面的例子,也可以實(shí)現(xiàn),但每次匹配時(shí)都需要重新檢測圖片的特征數(shù)據(jù),這樣會(huì)導(dǎo)致程序運(yùn)行效率。因此,我們可以將圖片的特征數(shù)據(jù)進(jìn)行保存,每次匹配時(shí),只需讀取特征數(shù)據(jù)進(jìn)行匹配即可。我們以下圖為例:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

我們根據(jù)圖1在圖2中查找最佳匹配的圖片。首先獲取圖2的全部圖片的特征數(shù)據(jù),將代碼保存在features.py:

import cv2
import numpy as np
from os import walk
from os.path import join

def 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)
  # 設(shè)置文件名并將特征數(shù)據(jù)保存到npy文件
  descriptor_file = image_path.replace("jpg", "npy")
  np.save(join(folder, descriptor_file), descriptors)

if __name__=='__main__':
  path = 'E:\\anchors'
  create_descriptors(path)

運(yùn)行代碼,結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

我們將圖片的特征數(shù)據(jù)保存在npy文件。下一步是根據(jù)圖1與這些特征數(shù)據(jù)文件進(jìn)行匹配,從而找出最佳匹配的圖片。代碼存在matching.py:

from os.path import join
from os import walk
import numpy as np
import cv2

query = cv2.imread('tattoo_seed.jpg', 0)
folder = 'E:\\anchors'
descriptors = []
# 獲取特征數(shù)據(jù)文件名
for (dirpath, dirnames, filenames) in walk(folder):
  for f in filenames:
    if f.endswith("npy"):
      descriptors.append(f)
  print(descriptors)

# 使用SIFT算法檢查圖像的關(guān)鍵點(diǎn)和描述符
sift = cv2.xfeatures2d.SIFT_create()
query_kp, query_ds = sift.detectAndCompute(query, None)

# 創(chuàng)建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與特征數(shù)據(jù)文件的數(shù)據(jù)進(jìn)行匹配
  matches = flann.knnMatch(query_ds, np.load(join(folder, d)), k=2)
  # 清除錯(cuò)誤匹配
  good = []
  for m, n in matches:
    if m.distance < 0.7 * n.distance:
      good.append(m)
  # 輸出每張圖片與目標(biāo)圖片的匹配數(shù)目
  print("img is %s ! matching rate is (%d)" % (d, len(good)))
  potential_culprits[d] = len(good)

# 獲取最多匹配數(shù)目的圖片
max_matches = None
potential_suspect = None
for culprit, matches in potential_culprits.items():
  if max_matches == None or matches > max_matches:
    max_matches = matches
    potential_suspect = culprit

print("potential suspect is %s" % potential_suspect.replace("npy", "").upper())

代碼運(yùn)行后,輸出結(jié)果如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

從輸出的結(jié)果可以看到,圖1與圖2的hush.jpg最為匹配,如圖所示:

Python使用Opencv實(shí)現(xiàn)圖像特征檢測與匹配的方法

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI