harris角點響應函數 harris角點檢測原理


harris角點響應函數 harris角點檢測原理


理論
在上一章中 , 我們看到角是圖像中各個方向上強度變化較大的區域 。早在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 npimport cv2 as cvfilename = '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 importantdst = 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 npimport cv2 as cvfilename = 'chessboard2.jpg'img = cv.imread(filename)gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)# find Harris cornersgray = 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 centroidsret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)# define the criteria to stop and refine the cornerscriteria = (cv.TERM_CRITERIA_EPScv.TERM_CRITERIA_MAX_ITER, 100, 0.001)corners = cv.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)# Now draw themres = 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)

推薦閱讀