[OpenCV-Python] OpenCV 中圖像特征提取與描述 部分 V (二)


部分 V
圖像特征提取與描述

 OpenCV-Python 中文教程(搬運)目錄

 

34 角點檢測的 FAST 算法


目標
  • 理解 FAST 算法的基礎
  • 使用 OpenCV 中的 FAST 算法相關函數進行角點檢測
原理
  我們前面學習了幾個特征檢測器,它們大多數效果都很好。但是從實時處理的角度來看,這些算法都不夠快。一個最好例子就是 SLAM(同步定位與地圖構建),移動機器人,它們的計算資源非常有限。
為了解決這個問題,Edward_Rosten 和 Tom_Drummond 在 2006 年提出里 FAST 算法。我們下面將會對此算法進行一個簡單的介紹。你可以參考原始文獻獲得更多細節(本節中的所有圖像都是曲子原始文章)。

34.1 使用 FAST 算法進行特征提取
  1. 在圖像中選取一個像素點 p,來判斷它是不是關鍵點。I p 等於像素點 p的灰度值。
  2. 選擇適當的閾值 t。
  3. 如下圖所示在像素點 p 的周圍選擇 16 個像素點進行測試。

    A corner in the image
  4. 如果在這 16 個像素點中存在 n 個連續像素點的灰度值都高於 I p + t,或者低於 I p −t,那么像素點 p 就被認為是一個角點。如上圖中的虛線所示,n 選取的值為 12。
  5. 為了獲得更快的效果,還采用了而外的加速辦法。首先對候選點的周圍每個 90 度的點:1,9,5,13 進行測試(先測試 1 和 19, 如果它們符合閾值要求再測試 5 和 13)。如果 p 是角點,那么這四個點中至少有 3 個要符合閾值要求。如果不是的話肯定不是角點,就放棄。對通過這步測試的點再繼續進行測試(是否有 12 的點符合閾值要求)。這個檢測器的效率很高,但是它有如下幾條缺點:
  • 當 n<12 時它不會丟棄很多候選點 (獲得的候選點比較多)。
  • 像素的選取不是最優的,因為它的效果取決與要解決的問題和角點的分布情況。
  • 高速測試的結果被拋棄
  • 檢測到的很多特征點都是連在一起的。
前 3 個問題可以通過機器學習的方法解決,最后一個問題可以使用非最大值抑制的方法解決。

34.2 機器學習的角點檢測器
  1. 選擇一組訓練圖片(最好是跟最后應用相關的圖片)
  2. 使用 FAST 算法找出每幅圖像的特征點
  3. 對每一個特征點,將其周圍的 16 個像素存儲構成一個向量。對所有圖像都這樣做構建一個特征向量 P
  4. 每一個特征點的 16 像素點都屬於下列三類中的一種。

    FAST equation
  5. 根據這些像素點的分類,特征向量 P 也被分為 3 個子集:P d ,P s ,P b
  6. 定義一個新的布爾變量 K p ,如果 p 是角點就設置為 Ture,如果不是就設置為 False。
  7. 使用 ID3 算法(決策樹分類器)Use the ID3 algorithm (decision tree classifier) to query each subset using the variable K p for the knowledge about the true class. It selects the x which yields the most information about whether the candidate pixel is a corner, measured by the entropy of K p .
  8. This is recursively applied to all the subsets until its entropy iszero.
  9. 將構建好的決策樹運用於其他圖像的快速的檢測。

34.3 非極大值抑制

 使用極大值抑制的方法可以解決檢測到的特征點相連的問題
  1. 對所有檢測到到特征點構建一個打分函數 V。V 就是像素點 p 與周圍 16個像素點差值的絕對值之和。
  2. 計算臨近兩個特征點的打分函數 V。
  3. 忽略 V 值最低的特征點
34.4 總結
  FAST 算法比其它角點檢測算法都快。但是在噪聲很高時不夠穩定,這是由閾值決定的。

 


34.5 OpenCV 中 中 FAST 特征檢測器


  很其他特征點檢測一樣我們可以在 OpenCV 中直接使用 FAST 特征檢測器。如果你願意的話,你還可以設置閾值,是否進行非最大值抑制,要使用的鄰域大小()等。
鄰域設置為下列 3 中之一:cv2.FAST_FEATURE_DETECTOR_TYPE_5_8,cv2.FAST_FEATURE_DETECTOR_TYPE_7_12和 cv2.FAST_FEATURE_DETECTOR_TYPE_9_16。下面是使用 FAST 算法進行特征點檢測的簡單代碼。

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

img = cv2.imread('simple.jpg',0)

# Initiate FAST object with default values
fast = cv2.FastFeatureDetector()

# find and draw the keypoints
kp = fast.detect(img,None)
img2 = cv2.drawKeypoints(img, kp, color=(255,0,0))

# Print all default params
print "Threshold: ", fast.getInt('threshold')
print "nonmaxSuppression: ", fast.getBool('nonmaxSuppression')
print "neighborhood: ", fast.getInt('type')
print "Total Keypoints with nonmaxSuppression: ", len(kp)

cv2.imwrite('fast_true.png',img2)

# Disable nonmaxSuppression
fast.setBool('nonmaxSuppression',0)
kp = fast.detect(img,None)

print "Total Keypoints without nonmaxSuppression: ", len(kp)

img3 = cv2.drawKeypoints(img, kp, color=(255,0,0))

cv2.imwrite('fast_false.png',img3)

結果如下。第一幅圖是使用了非最大值抑制的結果,第二幅沒有使用非最大值抑制。
    FAST Keypoints


35 BRIEF(Binary Robust Independent Elementary Features)


目標
  • 我們學習 BRIEF 算法的基礎
原理
  我們知道 SIFT 算法使用的是 128 維的描述符。由於它是使用的浮點數,所以要使用 512 個字節。同樣 SURF 算法最少使用 256 個字節(64 為維描述符)。創建一個包含上千個特征的向量需要消耗大量的內存,在嵌入式等資源有限的設備上這樣是合適的。匹配時還會消耗更多的內存和時間。
但是在實際的匹配過程中如此多的維度是沒有必要的。我們可以使用 PCA,LDA 等方法來進行降維。甚至可以使用 LSH(局部敏感哈希)將 SIFT 浮點數的描述符轉換成二進制字符串。對這些字符串再使用漢明距離進行匹配。漢明距離的計算只需要進行 XOR 位運算以及位計數,這種計算很適合在現代的CPU 上進行。但我們還是要先找到描述符才能使用哈希,這不能解決最初的內存消耗問題。
BRIEF 應運而生。它不去計算描述符而是直接找到一個二進制字符串。這種算法使用的是已經平滑后的圖像,它會按照一種特定的方式選取一組像素點對 n d (x,y),然后在這些像素點對之間進行灰度值對比。例如,第一個點對的灰度值分別為 p 和 q。如果 p 小於 q,結果就是 1,否則就是 0。就這樣對 n d個點對進行對比得到一個 n d 維的二進制字符串。
n d 可以是 128,256,512。OpenCV 對這些都提供了支持,但在默認情況下是 256(OpenC 是使用字節表示它們的,所以這些值分別對應與 16,32,64)。當我們獲得這些二進制字符串之后就可以使用漢明距離對它們進行匹配了。
非常重要的一點是:BRIEF 是一種特征描述符,它不提供查找特征的方法。所以我們不得不使用其他特征檢測器,比如 SIFT 和 SURF 等。原始文獻推薦使用 CenSurE 特征檢測器,這種算法很快。而且 BRIEF 算法對 CenSurE關鍵點的描述效果要比 SURF 關鍵點的描述更好。
簡單來說 BRIEF 是一種對特征點描述符計算和匹配的快速方法。這種算法可以實現很高的識別率,除非出現平面內的大旋轉。
35.1 OpenCV 中的 BRIEF
下面的代碼使用了 CenSurE 特征檢測器和 BRIEF 描述符。(在 OpenCV中 CenSurE 檢測器被叫做 STAR 檢測器)。

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

img = cv2.imread('simple.jpg',0)

# Initiate STAR detector
star = cv2.FeatureDetector_create("STAR")

# Initiate BRIEF extractor
brief = cv2.DescriptorExtractor_create("BRIEF")

# find the keypoints with STAR
kp = star.detect(img,None)

# compute the descriptors with BRIEF
kp, des = brief.compute(img, kp)

print brief.getInt('bytes')
print des.shape

函數 brief.getInt( ′ bytes ′ ) 會以字節格式給出 n d 的大小,默認值為 32。下面就是匹配了,我們會在其他章節中介紹。


36 ORB (Oriented FAST and Rotated BRIEF)

目標
  • 我們要學習 ORB 算法的基礎
原理
  對於一個 OpenCV 的狂熱愛好者來說 ORB 最重要的一點就是:它來自“OpenCV_Labs''。這個算法是在 2011 年提出的。在計算開支,匹配效率以及更主要的是專利問題方面 ORB 算法是是 SIFT 和 SURF 算法的一個很好的替代品。SIFT 和 SURF 算法是有專利保護的,如果你要使用它們,就可能要花錢。但是 ORB 不需要!!!
ORB 基本是 FAST 關鍵點檢測和 BRIEF 關鍵點描述器的結合體,並通過很多修改增強了性能。首先它使用 FAST 找到關鍵點,然后再使用 Harris角點檢測對這些關鍵點進行排序找到其中的前 N 個點。它也使用金字塔從而產生尺度不變性特征。但是有一個問題,FAST 算法步計算方向。那旋轉不變性怎樣解決呢?作者進行了如下修改。
它使用灰度矩的算法計算出角點的方向。以角點到角點所在(小塊)區域質心的方向為向量的方向。為了進一步提高旋轉不變性,要計算以角點為中心半徑為 r 的圓形區域的矩,再根據矩計算除方向。
對於描述符,ORB 使用的是 BRIEF 描述符。但是我們已經知道 BRIEF對與旋轉是不穩定的。所以我們在生成特征前,要把關鍵點領域的這個 patch的坐標軸旋轉到關鍵點的方向。

For any feature set of n binary tests at location (x i , y i ), define a 2×n matrix, S which contains the coordinates of these pixels. Then using the orientation of patch,θ, its rotation matrix is found and rotates the S to get steered(rotated) version S θ . ORB discretize the angle to increments of2π/30(12 degrees), and construct a lookup table of precomputed BRIEF patterns. As long as the keypoint orientation \theta is consistent across views, the correct set of points S θ will be used to compute its descriptor.
BRIEF has an important property that each bit feature has a large variance and a mean near 0.5. But once it is oriented along keypoint direction, it loses this property and become more distributed. High variance makes a feature more discriminative, since it responds differentially to inputs. Another desirable property is to have the tests uncorrelated, since then each test will contribute to the result. To resolve all these, ORB runs a greedy search among all possible binary tests to find the ones that have both high variance and means close to 0.5, as well as being uncorrelated. The result is calledrBRIEF.
For descriptor matching, multi-probe LSH which improves on the traditional LSH, is used. The paper says ORB is much faster than SURF and SIFT and ORB descriptor works better than SURF. ORB isa good choice in low-power devices for panorama stitching etc.
實驗證明,BRIEF 算法的每一位的均值接近 0.5,並且方差很大。steered_BRIEF算法的每一位的均值比較分散(均值為 0.5,0.45,0.35... 等值的關鍵點數相當),這導致方差減小。數據的方差大的一個好處是:使得特征更容易分辨。為了對 steered_BRIEF 算法使得特征的方差減小的彌補和減小數據間的相關性,用一個學習算法(learning method)選擇二進制測試的一個子集。在描述符匹配中使用了對傳統 LSH 改善后的多探針 LSH。文章中說 ORB算法比 SURF 和 SIFT 算法快的多,ORB 描述符也比 SURF 好很多。ORB是低功耗設備的最佳選擇。


36.1 OpenCV 中的 ORB 算法
  和前面一樣我們首先要使用函數 cv3.ORB() 或者 feature2d 通用接口創建一個 ORB 對象。它有幾個可選參數。最有用的應該是 nfeature,默認值為 500,它表示了要保留特征的最大數目。scoreType 設置使用 Harris打分還是使用 FAST 打分對特征進行排序(默認是使用 Harris 打分)等。參數 WTA_K 決定了產生每個 oriented_BRIEF 描述符要使用的像素點的數目。默認值是 2,也就是一次選擇兩個點。在這種情況下進行匹配,要使用NORM_HAMMING 距離。如果 WTA_K 被設置成 3 或 4,那匹配距離就要設置為 NORM_HAMMING2。
下面是一個使用 ORB 的簡單代碼。

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

img = cv2.imread('simple.jpg',0)

# Initiate STAR detector
orb = cv2.ORB()

# find the keypoints with ORB
kp = orb.detect(img,None)

# compute the descriptors with ORB
kp, des = orb.compute(img, kp)

# draw only keypoints location,not size and orientation
img2 = cv2.drawKeypoints(img,kp,color=(0,255,0), flags=0)
plt.imshow(img2),plt.show()

 

    ORB Keypoints
練習

 


37 特征匹配


目標
  • 我們將要學習在圖像間進行特征匹配
  • 使用 OpenCV 中的蠻力(Brute-Force)匹配和 FLANN 匹配


37.1 Brute-Force 匹配的基礎
  蠻力匹配器是很簡單的。首先在第一幅圖像中選取一個關鍵點然后依次與第二幅圖像的每個關鍵點進行(描述符)距離測試,最后返回距離最近的關鍵點。
對於 BF 匹配器,我們首先要使用 cv2.BFMatcher() 創建一個 BFMatcher 對象。它有兩個可選參數。第一個是 normType。它是用來指定要使用的距離測試類型。默認值為 cv2.Norm_L2。這很適合 SIFT 和 SURF 等(c2.NORM_L1 也可以)。對於使用二進制描述符的 ORB,BRIEF,BRISK算法等,要使用 cv2.NORM_HAMMING,這樣就會返回兩個測試對象之間的漢明距離。如果 ORB 算法的參數設置為 V TA_K==3 或 4,normType就應該設置成 cv2.NORM_HAMMING2。
第二個參數是布爾變量 crossCheck,默認值為 False。如果設置為True,匹配條件就會更加嚴格,只有到 A 中的第 i 個特征點與 B 中的第 j 個特征點距離最近,並且 B 中的第 j 個特征點到 A 中的第 i 個特征點也是最近(A 中沒有其他點到 j 的距離更近)時才會返回最佳匹配(i,j)。也就是這兩個特征點要互相匹配才行。這樣就能提供統一的結果,這可以用來替代 D.Lowe在 SIFT 文章中提出的比值測試方法。
BFMatcher 對象具有兩個方法,BFMatcher.match() 和 BFMatcher.knnMatch()。
第一個方法會返回最佳匹配。第二個方法為每個關鍵點返回 k 個最佳匹配(降序排列之后取前 k 個),其中 k 是由用戶設定的。如果除了匹配之外還要做其他事情的話可能會用上(比如進行比值測試)。
就像使用 cv2.drawKeypoints() 繪制關鍵點一樣,我們可以使用cv2.drawMatches() 來繪制匹配的點。它會將這兩幅圖像先水平排列,然后在最佳匹配的點之間繪制直線(從原圖像到目標圖像)。如果前面使用的是 BFMatcher.knnMatch(),現在我們可以使用函數 cv2.drawMatchsKnn為每個關鍵點和它的 k 個最佳匹配點繪制匹配線。如果 k 等於 2,就會為每個關鍵點繪制兩條最佳匹配直線。如果我們要選擇性繪制話就要給函數傳入一個掩模。
讓我們分別看一個 ORB 和一個 SURF 的例子吧。(使用不同距離計算方法)。

37.2 對 對 ORB 描述符進行蠻力匹配
  現在我們看一個在兩幅圖像之間進行特征匹配的簡單例子。在本例中我們有一個查詢圖像和一個目標圖像。我們要使用特征匹配的方法在目標圖像中尋找查詢圖像的位置。(這兩幅圖像分別是/sample/c/box.png,和/sample/c/box_in_scene.png)
我們使用 ORB 描述符來進行特征匹配。首先我們需要加載圖像計算描述符。

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

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
orb = cv2.ORB()

# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

下面我們要創建一個 BFMatcher 對象,並將距離計算設置為 cv2.NORM_HAMMING(因為我們使用的是 ORB),並將 crossCheck 設置為 True。然后使用 Matcher.match()方法獲得兩幅圖像的最佳匹配。然后將匹配結果按特征點之間的距離進行降序排列,這樣最佳匹配就會排在前面了。最后我們只將前 10 個匹配繪制出來(太多了看不清,如果願意的話你可以多畫幾條)。

# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Match descriptors.
matches = bf.match(des1,des2)

# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)

# Draw first 10 matches.
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)

plt.imshow(img3),plt.show()

下面就是我得到的結果。

    ORB Feature Matching with Brute-Force


37.3 匹配器對象是什么?
 matches = bf.match(des1,des2) 返回值是一個 DMatch 對象列表。這個DMatch 對象具有下列屬性:
  • DMatch.distance - 描述符之間的距離。越小越好。
  • DMatch.trainIdx - 目標圖像中描述符的索引。
  • DMatch.queryIdx - 查詢圖像中描述符的索引。
  • DMatch.imgIdx - 目標圖像的索引。


37.4 對 對 SIFT 描述符進行蠻力匹配和比值測試
  現在我們使用 BFMatcher.knnMatch() 來獲得 k 對最佳匹配。在本例中我們設置 k = 2,這樣我們就可以使用 D.Lowe 文章中的比值測試了。

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

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

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

# BFMatcher with default params
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)

# Apply ratio test
good = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
        good.append([m])

# cv2.drawMatchesKnn expects list of lists as matches.
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2)

plt.imshow(img3),plt.show()

結果如下:

    SIFT Descriptor with ratio test

 


37.5 FLANN 匹配器
  FLANN 是快速最近鄰搜索包(Fast_Library_for_Approximate_Nearest_Neighbors)的簡稱。它是一個對大數據集和高維特征進行最近鄰搜索的算法的集合,而且這些算法都已經被優化過了。在面對大數據集時它的效果要好於 BFMatcher。
我們來對第二個例子使用 FLANN 匹配看看它的效果。

使用 FLANN 匹配,我們需要傳入兩個字典作為參數。這兩個用來確定要使用的算法和其他相關參數等。第一個是 IndexParams。各種不同算法的信息可以在 FLANN 文檔中找到。這里我們總結一下,對於 SIFT 和 SURF 等,我們可以傳入的參數是:

index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)

但使用 ORB 時,我們要傳入的參數如下。注釋掉的值是文獻中推薦使用的,但是它們並不適合所有情況,其他值的效果可能會更好。

index_params= dict(algorithm = FLANN_INDEX_LSH,
                   table_number = 6, # 12
                   key_size = 12,     # 20
                   multi_probe_level = 1) #2

第二個字典是 SearchParams。用它來指定遞歸遍歷的次數。值越高結果越准確,但是消耗的時間也越多。如果你想修改這個值,傳入參數:
search p arams = dict(checks = 100)。
有了這些信息我們就可以開始了。

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

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

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

# FLANN parameters
FLANN_INDEX_KDTREE = 0
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 xrange(len(matches))]

# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
    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(img1,kp1,img2,kp2,matches,None,**draw_params)

plt.imshow(img3,),plt.show()

結果如下:

    FLANN based matching


38 使用特征匹配和單應性查找對象


目標
  • 聯合使用特征提取和 calib3d 模塊中的 findHomography 在復雜圖像中查找已知對象。


38.1 基礎
  還記得上一節我們做了什么嗎?我們使用一個查詢圖像,在其中找到一些特征點(關鍵點),我們又在另一幅圖像中也找到了一些特征點,最后對這兩幅圖像之間的特征點進行匹配。簡單來說就是:我們在一張雜亂的圖像中找到了一個對象(的某些部分)的位置。這些信息足以幫助我們在目標圖像中准確的找到(查詢圖像)對象。
為了達到這個目的我們可以使用 calib3d 模塊中的 cv2.findHomography()函數。如果將這兩幅圖像中的特征點集傳給這個函數,他就會找到這個對象的透視圖變換。然后我們就可以使用函數 cv2.perspectiveTransform() 找到這個對象了。至少要 4 個正確的點才能找到這種變換。
我們已經知道在匹配過程可能會有一些錯誤,而這些錯誤會影響最終結果。為了解決這個問題,算法使用 RANSAC 和 LEAST_MEDIAN(可以通過參數來設定)。所以好的匹配提供的正確的估計被稱為 inliers,剩下的被稱為outliers。cv2.findHomography() 返回一個掩模,這個掩模確定了 inlier 和outlier 點。
讓我們來搞定它吧!!!
38.2 代碼
  和通常一樣我們先在圖像中來找到 SIFT 特征點,然后再使用比值測試找到最佳匹配。

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

MIN_MATCH_COUNT = 10

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

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

FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

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

# store all the good matches as per Lowe's ratio test.
good = []
for m,n in matches:
    if m.distance < 0.7*n.distance:
        good.append(m)

現在我們設置只有存在 10 個以上匹配時才去查找目標(MIN_MATCH_COUNT=10),
否則顯示警告消息:“現在匹配不足!”
如果找到了足夠的匹配,我們要提取兩幅圖像中匹配點的坐標。把它們傳入到函數中計算透視變換。一旦我們找到 3x3 的變換矩陣,就可以使用它將查詢圖像的四個頂點(四個角)變換到目標圖像中去了。然后再繪制出來。

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)

    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
    matchesMask = mask.ravel().tolist()

    h,w = img1.shape
    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 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)

else:
    print "Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT)
    matchesMask = None

# Finally we draw our inliers (if successfully found the object) or matching keypoints (if failed).

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()

結果如下。復雜圖像中被找到的目標圖像被標記成白色。
    Finding object with feature homography


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM