特征檢測
哈裡斯角檢測
cv.cornerHarris()
輸入:
• img - 資料類型為 float32 的輸入圖像。
• blockSize - 角點檢測中要考慮的領域大小。
• ksize - Sobel 求導中使用的視窗大小
• k - Harris 角點檢測方程中的自由參數,取值參數為 [0,04,0.06].
傳回:
是具有特征分數的灰階圖像。
import numpy as np
import cv2 as cv
filename = 'C:\\Users\\Administrator\\Desktop\\pic\\jiao.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
#result用于标記角點,并不重要
dst = cv.dilate(dst,None) #最佳值的門檻值,它可能因圖像而異。
img[dst>0.01*dst.max()]=[0,0,255]
cv.imshow('dst',img)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()

SubPixel精度的轉角
有時可能需要找到最精确的角落。即細化了以亞像素精度檢測到的角落。
cv.connectedComponentsWithStats()
connectedComponentsWithStats()建立了一個标記圖(圖中不同連通域使用不同的标記,和原圖寬高一緻),可以完成上面任務,除此之外,還可以傳回每個連通區域的重要資訊。
輸入:
img-8位單通道二值圖像;
輸出:
ret:連通區域的數量
abel:輸出和原圖image一樣大的标記圖,label對應于表示是目前像素是第幾個輪廓,背景置0;
centroids:對應的是輪廓的中心點。nccomps×2的矩陣 表示每個連通區域的質心
stats:輸出nccomps×5的矩陣 ,表示每個連通區域的外接矩形和面積
cv.cornerSubPix()
該函數可以為檢測到的角點作進一步的優化計算,可使角點的精度達到亞像素級别。
輸入:
第一個參數是輸入圖像
第二個參數是檢測到的角點,一般是提前檢測到的哈裡斯角的質心。
第三個參數是計算亞像素角點時考慮的區域的大小,大小為NXN; N=(winSize*2+1)。
第四個參數作用類似于winSize,但是總是具有較小的範圍,通常忽略(Size(-1, -1))。
第五個參數用于表示計算亞像素時停止疊代的标準,可選的值有cv::TermCriteria::MAX_ITER 、cv::TermCriteria::EPS(可以是兩者其一,或兩者均選),前者表示疊代次數達到了最大次數時停止,後者表示角點位置變化的最小值已經達到最小時停止疊代。二者均使用cv::TermCriteria()構造函數進行指定。
import numpy as np
import cv2 as cv
filename = 'C:\\Users\\Administrator\\Desktop\\pic\\djiao.png'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 尋找哈裡斯角
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
dst = cv.dilate(dst,None)
ret, dst = cv.threshold(dst,0.01*dst.max(),255,0)
dst = np.uint8(dst)
# 尋找質心
ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)
# 定義停止和完善拐角的條件
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)
# 繪制
res = np.hstack((centroids,corners))
res = np.int0(res)
img[res[:,1],res[:,0]]=[0,0,255]
img[res[:,3],res[:,2]] = [0,255,0]
cv.imshow('dst',img)
cv.waitKey(1000000)
Shi-tomas拐角檢測器
OpenCV有一個函數cv.goodFeaturesToTrack()。它通過Shi-Tomasi方法(或哈裡斯角檢測,可以找到圖像中的拐角。低于平均品質的所有拐角點均被拒絕。後,它會根據品質以降序對剩餘的角進行排序。然後函數首先擷取最佳拐角,然後丢棄最小距離範圍内的所有附近拐角,然後傳回N個最佳拐角。
輸入:
image: 輸入圖像,是八位的或者32位浮點型,單通道圖像,是以有時候用灰階圖
maxCorners: 傳回最大的角點數,是最有可能的角點數,如果這個參數不大于0,那麼表示沒有角點數的限制。
qualityLevel: 圖像角點的最小可接受參數,品質測量值乘以這個參數就是最小特征值,小于這個數的會被抛棄。
minDistance: 傳回的角點之間最小的歐式距離。
mask: 檢測區域。如果圖像不是空的(它需要具有CV_8UC1類型和與圖像相同的大小),它指定檢測角的區域。
blockSize: 用于計算每個像素鄰域上的導數協變矩陣的平均塊的大小。
useHarrisDetector:選擇是否采用Harris角點檢測,預設是false.
k: Harris檢測的自由參數。
傳回
是一個數組n12的數組,n是檢測到的角的數量。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\rentou.png')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(gray,25,0.01,10)
corners = np.int0(corners)
print(corners)
for i in corners:
x,y = i.ravel()
cv.circle(img,(x,y),3,255,-1)
plt.imshow(img),plt.show()
SIFT尺度不變特征變換
前面部分的一些像Harris這樣的拐角檢測器。它們是旋轉不變的,這意味着即使圖像旋轉了,我們也可以找到相同的角。很明顯,因為轉角在旋轉的圖像中也仍然是轉角。但是如果縮放圖像,則拐角可能不是角。因為某些角度在被放大後角度會變平坦如下圖。是以,Harris拐角不是尺度不變的。接下來會介紹尺度不變的拐角檢測器。
該算法分為五個步驟:
- 尺度空間極值檢測
- 關鍵點定位
- 方向配置設定
- 關鍵點描述
- 關鍵點比對
sift.detect()
輸出
des為 128 為向量組成的清單
kp 為關鍵點清單,每個元素為一個 KeyPoint,其包含資訊有:
- angle:角度,表示關鍵點的方向. 為了保證方向不變形,SIFT算法通過對關鍵點周圍鄰域進行梯度運算,求得該點方向. -1為初值.
- class_id:當要對圖檔進行分類時,可以用 class_id 對每個特征點進行區分. 未設定時為-1,需要自己設定.
- .octave:代表是從金字塔哪一層提取的得到的資料.
- pt:關鍵點的坐标x,y.
- response:響應程度,代表該點強壯大小,更确切的說,是該點角點的程度.
- size:該點直徑的大小
cv.drawKeyPoints()
cv.drawKeyPoints()函數,該函數在關鍵點的位置繪制小圓圈。 如果将标志
cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS傳遞給它,它将繪制一個具有關鍵點大小的圓,甚至會顯示其方向。
計算描述符
要計算描述符,OpenCV提供了兩種方法。
- 由于已經找到關鍵點,是以可以調用sift.compute(),該函數根據我們找到的關鍵點來計算描述符。例如: kp,des = sift.compute(gray,kp)
-
如果找不到關鍵點,則可以使用sift.detectAndCompute()函數在單
步驟中直接找到關鍵點和描述符。
import numpy as np
import cv2 as cv
img = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\rentou.png')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
#方法一
kp = sift.detect(gray,None)
kp,des = sift.compute(gray,kp)
#方法二
kp, des = sift.detectAndCompute(gray,None)
img=cv.drawKeypoints(gray,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv.imshow('dst',img)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
SURF
SIFT用于關鍵點檢測和描述符,SURF是一個加速版本的SIFT。使用方法和SIFT類似。
import numpy as np
import cv2 as cv
img = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\rentou.png')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 這裡設定海森矩陣的門檻值為400
surf = cv.xfeatures2d.SURF_create(400)
# 我們将其設定為50000。記住,它僅用于表示圖檔。
# 在實際情況下,最好将值設為300-500
surf.setHessianThreshold(50000)
kp, des = surf.detectAndCompute(img,None)
img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4)
cv.imshow('dst',img2)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
角點檢測FAST算法
FAST算法比其他現有的拐角檢測器快幾倍。但是它對高水準的噪聲并不魯棒。
使用FAST進行特征檢測:
1.選擇圖像中是否要識别為興趣點的像素p,使其強度為I_p
2.選擇适當的門檻值t
3.考慮被測像素周圍有16個像素的圓圈。
4.現在,如果圓中存在一組(共16個像素)n個連續的像素,它們均比I_p + t亮,或者比I_p-t都暗,則像素p是一個角。(在上圖中顯示為白色虛線)。n被選12。
5.建議使用高速測試以排除大量的非角區域。此測試僅檢查1、9、5和13處的四個像素(如果第一個1和9太亮或太暗,則對其進行測試。如果是,則檢查5和13)。如果p是一個角,則其中至少三個必須全部比I_p + t亮或比I_p-t暗。如果以上兩種情況都不是,則p不能為角。然後,可以通過檢查圓中的所有像素,将完整的分段測試标準應用于通過的候選項。該檢測器本身具有很高的性能,但有幾個缺點:
(1)它不會拒絕n <12的候選對象。
(2)像素的選擇不是最佳的,因為其效率取決于問題的順序和角落外觀的分布。
(3)高速測試的結果被丢棄了。
(4)彼此相鄰地檢測到多個特征。
機器學習一個角檢測器
1.選擇一組圖像進行訓練(最好從目标應用程式域中進行訓練)
2.在每個圖像中運作FAST算法以查找特征點。
3.對于每個特征點,将其周圍的16個像素存儲為矢量。對所有圖像執行此操作以獲得特征向量P。
4.這16個像素中的每個像素(例如x)可以具有以下三種狀态之一:
1.取決于這些狀态,特征矢量P被細分為3個子集,P_d, P_s, P_b。
2.定義一個新的布爾變量K_p,如果p是一個角,則為true,否則為false。
3.使用ID3算法(決策樹分類器)使用變量K_p查詢每個子集,以擷取有關真實類的知識。它選擇x,該x通過K_p的熵測得的有關候選像素是否為角的資訊最多。
遞歸地将其應用于所有子集,直到其熵為零為止。
5.這樣建立的決策樹用于其他圖像的快速檢測。
非最大抑制
在相鄰位置檢測多個興趣點是另一個問題。通過使用非極大抑制來解決。
1.計算所有檢測到的特征點的得分函數V。V是p與16個周圍像素值之間的絕對差之和。
2.考慮兩個相鄰的關鍵點并計算它們的V值。
3.丢棄較低V值的那個。
代碼例子
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\mei.png',0)
# 用預設值初始化FAST對象
fast = cv.FastFeatureDetector_create()
# 尋找并繪制關鍵點
kp = fast.detect(img,None)
img2 = cv.drawKeypoints(img, kp, None, color=(255,0,0))
# 列印所有預設參數
print( "Threshold: {}".format(fast.getThreshold()) )
print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) )
print( "neighborhood: {}".format(fast.getType()) )
print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) )
cv.imshow('dst',img2)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
# 關閉非極大抑制
fast.setNonmaxSuppression(0)
kp = fast.detect(img,None)
print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) )
img3 = cv.drawKeypoints(img, kp, None, color=(255,0,0))
cv.imshow('dst2',img3)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
BRIEF
BRIEF是一種更快的方法特征描述符計算和比對。除了平面内旋轉較大的情況,它将提供很高的識别率。
它提供了一種直接查找二進制字元串而無需查找描述符的快捷方式。它需要平滑
的圖像更新檔,并以獨特的方式(在紙上展示)選擇一組n_d(x,y)位置對。然後,在這些位置對上進行一些像素強度比較。例如,令第一位置對為p和q。如果I§<I(q),則結果為1,否則為0。将其應用于所有n_d個位置對以獲得n_d維位串。
該n_d可以是128、256或512。OpenCV支援所有這些,但預設情況下将256(OpenCV以位元組為機關表示,是以值将為16、32和64)。是以,一旦獲得此資訊,就可以使用漢明距離來比對這些描述符。重要的一點是,BRIEF是特征描述符,它不提供任何查找特征的方法。是以,您将不得不使用任何其他特征檢測器,例如SIFT,SURF等。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\rentou.png',0)
# 初始化FAST檢測器
star = cv.xfeatures2d.StarDetector_create()
# 初始化BRIEF提取器
brief = cv.xfeatures2d.BriefDescriptorExtractor_create()
# 找到STAR的關鍵點
kp = star.detect(img,None)
# 計算BRIEF的描述符
kp, des = brief.compute(img, kp)
img2 = cv.drawKeypoints(img, kp, None, color=(0,255,0), flags=0)
cv.imshow('dst',img2)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
ORB(面向快速和旋轉的BRIEF)
ORB計算中SIFT和SURF的良好替代方案成本,比對性能以及主要是專利。SIFT和SURF已獲得專利,使用其需要付費,但是ORB不是。
ORB基本上是FAST關鍵點檢測器和Brief描述符的融合,首先,它使用FAST查找關鍵點,然後應用Harris角測度在其中找到前N個點。它還使用金字塔生成多尺度特征。但是一個問題是,FAST無法計算方向。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\rentou.png',0)
# 初始化ORB檢測器
orb = cv.ORB_create()
# 用ORB尋找關鍵點
kp = orb.detect(img,None)
# 用ORB計算描述符
kp, des = orb.compute(img, kp)
# 僅繪制關鍵點的位置,而不繪制大小和方向
img2 = cv.drawKeypoints(img, kp, None, color=(0,255,0), flags=0)
plt.imshow(img2), plt.show()