理論
在上一章中,我們看到角是圖像中各個方向上強度變化較大的區域。早在1988年,克里斯·哈里斯和邁克·斯蒂芬斯就在他們的論文《一種結合了角和邊緣的探測器》中試圖找到這些角,所以現在它被稱為「哈里斯角探測器」。他把這個簡單的想法轉化為數學模型。它基本上可以求出(u,v)在所有方向上的位移的強度差。這表示如下:

窗口函數可以是矩形窗口,也可以是高斯窗口(它為下面的像素賦予權重)。
我們需要最大化這個函數E(u,v)來檢測拐角。這意味着,我們要使第二項最大化。將泰勒展開應用於上述方程,並使用一些數學步驟(如需完整推導,請參考您喜歡的任何標準課本),得到最終方程為:

這裡的 Ix 和 Iy 分別是圖像在 x 和 y 上的導數。(可以很容易的通過函數 cv.Sobel()得到)。
接下來是主要部分。在這之後,他們創建了一個分數,基本上是一個方程,它將決定一個窗口是否可以包含一個角。

其中:
- det(M)=λ1λ2
- trace(M)=λ1+λ2
- λ1 和 λ2 是M的特徵值
因此,這些特徵值決定了該區域是角,邊沿還是平台區。
- 當 |R| 較小時(當 λ1 和 λ2 都小時出現),則該區域就是平台區。
- 當 R<0 時(一般當 λ1>>λ2 遠大於或相反時出現),則該區域是邊沿。
- 當 R 較大時(一般 λ1 和 λ2 都較大且 λ1∼λ2趨近),則該區域是角。
可以用下圖 λ1 和 λ2 坐標圖來表示:

因此,Harris角檢測的結果是一個帶評分的灰度圖像。適當的閾值設置會得到圖像中的角。我們將用一個簡單的圖像來做測試。
OpenCV的Harris角點檢測實現
OpenCV 有一個函數 cv.cornerHarris() 就是用於此目的,包括一下參數:
- img – 輸入圖像,該圖像必須是float32 類型的灰度圖。
- blockSize – 角點檢測的鄰近域大小
- ksize – 用於Sobel導數的孔徑參數。
- k – 方程中Harris 檢測自由參數。
舉例說明該函數的使用:
import numpy as np
import cv2 as cv
filename = 'chessboard.png'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
#result is dilated for marking the corners, not important
dst = cv.dilate(dst,None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.01*dst.max()]=[0,0,255]
cv.imshow('dst',img)
if cv.waitKey(0) & 0xff == 27:
cv.destroyAllWindows()
以下就是檢測結果:

亞像素精度的角點檢測
有時候,你可能需要找到最精確的角。OpenCV附帶一個函數cv.cornersubpix(),它進一步細化了以亞像素精度檢測到的角。下面是一個例子。像往常一樣,我們需要先找到哈里斯角。然後我們通過這些角的質心(可能在一個角上有一堆像素,我們取它們的質心)來細化它們。Harris角用紅色像素標記,精製角用綠色像素標記。對於這個函數,我們必須定義何時停止迭代的條件。我們在指定的迭代次數或達到一定的精度後停止它,無論先發生什麼。我們還需要定義搜索拐角的鄰域的大小。
import numpy as np
import cv2 as cv
filename = 'chessboard2.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# find Harris corners
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)
# find centroids
ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)
# define the criteria to stop and refine the corners
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)
# Now draw them
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.imwrite('subpixel5.png',img)
以下是結果,每個角經過縮放後顯示紅綠不同位置標識,該函數明顯提升了精度:

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/220852.html
微信掃一掃
支付寶掃一掃