天天看點

2021-07-30特征檢測

特征檢測

哈裡斯角檢測

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()
           
2021-07-30特征檢測

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拐角不是尺度不變的。接下來會介紹尺度不變的拐角檢測器。

2021-07-30特征檢測

該算法分為五個步驟:

  1. 尺度空間極值檢測
  2. 關鍵點定位
  3. 方向配置設定
  4. 關鍵點描述
  5. 關鍵點比對
sift.detect()

輸出

des為 128 為向量組成的清單

kp 為關鍵點清單,每個元素為一個 KeyPoint,其包含資訊有:

  1. angle:角度,表示關鍵點的方向. 為了保證方向不變形,SIFT算法通過對關鍵點周圍鄰域進行梯度運算,求得該點方向. -1為初值.
  2. class_id:當要對圖檔進行分類時,可以用 class_id 對每個特征點進行區分. 未設定時為-1,需要自己設定.
  3. .octave:代表是從金字塔哪一層提取的得到的資料.
  4. pt:關鍵點的坐标x,y.
  5. response:響應程度,代表該點強壯大小,更确切的說,是該點角點的程度.
  6. size:該點直徑的大小
cv.drawKeyPoints()

cv.drawKeyPoints()函數,該函數在關鍵點的位置繪制小圓圈。 如果将标志

cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS傳遞給它,它将繪制一個具有關鍵點大小的圓,甚至會顯示其方向。

計算描述符

要計算描述符,OpenCV提供了兩種方法。

  1. 由于已經找到關鍵點,是以可以調用sift.compute(),該函數根據我們找到的關鍵點來計算描述符。例如: kp,des = sift.compute(gray,kp)
  2. 如果找不到關鍵點,則可以使用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個像素的圓圈。

2021-07-30特征檢測

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)可以具有以下三種狀态之一:

2021-07-30特征檢測

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