局部图像描述子——Harris角点检测器
文章目錄
- Harris角點(diǎn)檢測器
- 1 Harris角點(diǎn)檢測算法
- 2 Harris角點(diǎn)檢測代碼
- 3 在圖像間尋找對應(yīng)點(diǎn)
- 4 總結(jié)
Harris角點(diǎn)檢測器
1 Harris角點(diǎn)檢測算法
Harris角點(diǎn)檢測算法(也稱Harris & Stephens角點(diǎn)檢測器)是一個極為簡單的角點(diǎn)檢測算法。該算法的主要思想是,如果像素周圍顯示存在多于一個方向的邊,則認(rèn)為該點(diǎn)為興趣點(diǎn),該點(diǎn)也就是稱為角點(diǎn)。角點(diǎn)就是極值點(diǎn),即在某方面屬性特別突出的點(diǎn),是在某些屬性上強(qiáng)度最大或者最小的孤立點(diǎn)、線段的終點(diǎn)。
在圖像域中點(diǎn)x上的對稱半正定矩陣可以定義為:
其中▽I為包含導(dǎo)數(shù)Ix和Iy的圖像梯度。
選擇權(quán)重矩陣W(通常為高斯濾波器G),可以得到卷積:
該卷積的目的是得到M1在周圍像素上的局部平均。計算出的矩陣稱為Harris矩陣。W的寬度決定了在像素x周圍的感興趣區(qū)域。像這樣在區(qū)域附近對Harris矩陣取平均的原因是特征值會依賴于局部圖像特性而變化。如果圖像的梯度在該區(qū)域變化,那么Harris的第二個特征值將不再是0。如果圖像的梯度沒有變化,Harris的特征值也不會變化。
取決于該區(qū)域▽I的值,Harris矩陣的特征值有三種情況:
在不需要實(shí)際計算特征值的情況下,引入指示函數(shù):
為了去除加權(quán)常數(shù)k,通常使用商數(shù):
作為指示器。
算法的核心是利用局部窗口在圖像上進(jìn)行移動,判斷灰度是否發(fā)生較大的變化。如果窗口內(nèi)的灰度值(在梯度圖上)都有較大的變化,那么這個窗口所在區(qū)域就存在角點(diǎn)。
這樣就可以將 Harris 角點(diǎn)檢測算法分為以下三步:
- 當(dāng)窗口(局部區(qū)域)同時向 xx (水平)和 yy(垂直) 兩個方向移動時計算窗口內(nèi)部的像素值變化量 E(x,y)E(x,y) ;
- 對于每個窗口,都計算其對應(yīng)的一個角點(diǎn)響應(yīng)函數(shù)R;
- 然后對該函數(shù)進(jìn)行閾值處理,如果 R>threshold,表示該窗口對應(yīng)一個角點(diǎn)特征。
2 Harris角點(diǎn)檢測代碼
在這里需要使用到scipy.ndimage.filters模塊中的高斯導(dǎo)數(shù)濾波器來計算導(dǎo)數(shù),因?yàn)樾枰诮屈c(diǎn)檢測過程中抑制噪聲強(qiáng)度。
首先將角點(diǎn)響應(yīng)函數(shù)添加到harris.py文件中,該函數(shù)使用高斯導(dǎo)數(shù)實(shí)現(xiàn)。同樣地,參數(shù)σ定義了使用的高斯濾波器的尺度大小。
from scipy.ndimage import filtersdef compute_harris_response(im, sigma = 3):imx = zeros(im.shape)filters.gaussian_filter(im, (sigma, sigma), (0, 1), imx)imy = zeros(im.shape)filters.gaussian_filter(im, (sigma, sigma), (1, 0), imy)Wxx = filters.gaussian_filter(imx * imx, sigma)Wxy = filters.gaussian_filter(imx * imy, sigma)Wyy = filters.gaussian_filter(imy * imy, sigma)Wdet = Wxx * Wyy - Wxy ** 2Wtr = Wxx + Wyyreturn Wdet / Wtr上面的函數(shù)返回像素值為Harris響應(yīng)函數(shù)值的一幅圖像。然后需要從中挑選出像素值高于閾值的所有圖像點(diǎn),再加上額外的限制,即角點(diǎn)之間的間隔必須大于設(shè)定的最小距離。這種方法會產(chǎn)生很好的角點(diǎn)檢測結(jié)果。
為了實(shí)現(xiàn)該算法,我們獲取所有的候選像素點(diǎn),以角點(diǎn)響應(yīng)值遞減的順序排序,然后將距離已標(biāo)記為角點(diǎn)位置過近的區(qū)域從候選像素點(diǎn)中刪除。將下面的函數(shù)添加到harris.py中:
def get_harris_points(harrisim, min_dist = 10, threshold = 0.1):corner_threshold = harrisim.max() * thresholdharrisim_t = (harrisim > corner_threshold) * 1coords = array(harrisim_t.nonzero()).Tcandidate_values = [harrisim[c[0], c[1]] for c in coords]index = argsort(candidate_values)allowed_locations = zeros(harrisim.shape)allowed_locations[min_dist: -min_dist, min_dist: -min_dist] = 1filtered_coords = []for i in index:if allowed_locations[coords[i, 0], coords[i, 1]] == 1:filtered_coords.append(coords[i])allowed_locations[(coords[i, 0] - min_dist) : (coords[i, 0] + min_dist), (coords[i, 1] - min_dist) : (coords[i, 1] + min_dist)] = 0return filtered_coords為了顯示圖像中的角點(diǎn),可以使用Matplotlib模塊繪制函數(shù),并將其添加到harris.py文件中:
def plot_harris_points(image, filtered_coords):figure()gray()imshow(image)plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')axis('off')show()這樣準(zhǔn)備工作就已經(jīng)完成,接下來運(yùn)行下邊這段代碼,打開灰度圖,計算響應(yīng)函數(shù)并基于響應(yīng)值選擇角點(diǎn),最后在原始圖像中覆蓋繪制檢測出的角點(diǎn)。
from PIL import Image from numpy import * from pylab import * from scipy.ndimage import filters import harrisim = array(Image.open('jimei_grey.jpg'))harrisim = harris.compute_harris_response(im)filtered_coords = harris.get_harris_points(harrisim, 6)harris.plot_harris_points(im, filtered_coords) 圖1 使用Harris角點(diǎn)檢測器檢測角點(diǎn)從上圖可以明顯看出,隨著閾值從0.01增到0.05再到0.1,檢測出的角點(diǎn)越來越少,并且角點(diǎn)檢測算子對亮度的變化更敏感,在亮區(qū)域角點(diǎn)更多。可以看出,Harris角點(diǎn)檢測獲取的角點(diǎn)在圖像中分布不均勻(對比度高的區(qū)域角點(diǎn)多)。
3 在圖像間尋找對應(yīng)點(diǎn)
Harris角點(diǎn)檢測器僅僅能夠檢測出圖像中的興趣點(diǎn),但是沒有給出通過比較圖像間的興趣點(diǎn)來尋找匹配角點(diǎn)的方法。所以就需要在每個點(diǎn)添加一個描述子并給出一個比較這些描述子的方法。
興趣點(diǎn)描述子是分配給興趣點(diǎn)的一個向量,描述該點(diǎn)附近的圖像的表觀信息。描述子越好,尋找到的對應(yīng)點(diǎn)越好。我們用對應(yīng)點(diǎn)或者點(diǎn)的對應(yīng)來描述相同物體和場景點(diǎn)在不同圖像上形成的像素點(diǎn)。
Harris角點(diǎn)的描述子通常是由周圍圖像像素塊的灰度值,以及用于比較的歸一化互相關(guān)矩陣構(gòu)成的。圖像的像素塊由以該像素點(diǎn)為中心的周圍矩形部分圖像構(gòu)成。
為了獲取圖像像素塊,并使用歸一化的互相關(guān)矩陣來比較它們,需要將以下兩個函數(shù)添加到harris.py中:
def get_descriptors(image,filtered_coords,wid=5):desc = []for coords in filtered_coords:patch = image[coords[0]-wid:coords[0]+wid+1,coords[1]-wid:coords[1]+wid+1].flatten()desc.append(patch)return desc def match(desc1,desc2,threshold=0.5):n=len(desc1[0])d = -ones((len(desc1),len(desc2)))for i in range(len(desc1)):for j in range(len(desc2)):d1 = (desc1[i] - mean(desc1[i])) / std(desc1[i])d2 = (desc2[j] - mean(desc2[j])) / std(desc2[j])ncc_value = sum(d1*d2)/(n-1)if ncc_value>threshold:d[i,j] = ncc_valuendx = argsort(-d)matchscores = ndx[:,0]return matchscores第一個函數(shù)的參數(shù)為奇數(shù)大小長度的方形灰度圖像塊,該圖像塊的中心為處理的像素點(diǎn)。該函數(shù)將圖像塊像素值壓平成一個向量,然后添加到描述子列表中。第二個函數(shù)使用歸一化的互相關(guān)矩陣,將每個描述子匹配到另一個圖像中的最優(yōu)的候選點(diǎn)。由于數(shù)值較高的距離代表兩個點(diǎn)能夠更好地匹配,所以在排序之前,對距離取相反數(shù)。為了獲得更穩(wěn)定的匹配,我們從第二幅圖像向第一幅圖像匹配,然后過濾掉在兩種方法中不都是最好的匹配。用下邊的函數(shù)實(shí)現(xiàn):
def match_twosided(desc1,desc2,threshold=0.5):matches_12 = match(desc1,desc2,threshold)matches_21 = match(desc2,desc1,threshold)ndx_12 = where(matches_12 >= 0)[0]for n in ndx_12:if matches_21[matches_12[n]] != n:matches_12[n] = -1return matches_12這些匹配可以通過在兩邊分別繪制出圖像,使用線段連接匹配的像素點(diǎn)來直觀地可視化。可視化過程由以下代碼實(shí)現(xiàn):
def appendimages(im1,im2):rows1 = im1.shape[0]rows2 = im2.shape[0]if rows1 < rows2:im1 = concatenate((im1,zeros((rows2-rows1,im1,shape[1]))),axis=0)elif rows1>rows2:im2 = concatenate((im2,zeros((rows1-rows2,im2.shape[1]))),axis=0)return concatenate((im1,im2),axis=1)def plot_matches(im1,im2,locs1,locs2,matchscores,show_below=True):im3 = appendimages(im1,im2)if show_below:im3 = vstack((im3,im3))imshow(im3)cols1 = im1.shape[1]for i,m in enumerate(matchscores):if m>0:plot([locs1[i][1],locs2[m][1]+cols1],[locs1[i][0],locs2[m][0]],'c')axis('off')使用歸一化互相關(guān)矩陣尋找對應(yīng)點(diǎn)的實(shí)例:
from PIL import Image from numpy import * from pylab import * from scipy.ndimage import filters import harrisim1 = array(Image.open('jimei.jpg').convert('L')) im2 = array(Image.open('jimei2.jpg').convert('L'))wid = 5 harrisim = harris.compute_harris_response(im1, 5) filtered_coords1 = harris.get_harris_points(harrisim,wid+1) d1 = harris.get_descriptors(im1,filtered_coords1,wid)harrisim = harris.compute_harris_response(im2,5) filtered_coords2 = harris.get_harris_points(harrisim,wid+1) d2 = harris.get_descriptors(im2,filtered_coords2,wid)print('staring matching') matches = harris.match_twosided(d1,d2)figure() gray() harris.plot_matches(im1,im2,filtered_coords1,filtered_coords2,matches) show() 圖2 使用歸一化的互相關(guān)矩陣應(yīng)用于Harris角點(diǎn)周圍的圖像塊從上圖可以看出,算法的結(jié)果存在一些不正確匹配,因?yàn)閳D像像素塊的互相關(guān)矩陣具有較弱的描述性,而且描述符不具有尺度不變性和旋轉(zhuǎn)不變性,算法中像素塊的大小也會影響匹配的結(jié)果。
4 總結(jié)
角點(diǎn)檢測是計算機(jī)視覺系統(tǒng)中用來獲得圖像特征的一種重要方法,也稱為特征點(diǎn)檢測。如果某一點(diǎn)在任意方向的一個微小變動都會引起灰度很大的變化,那么我們就把這個點(diǎn)稱為圖像的一個角點(diǎn)。更形象一點(diǎn)的話,我們可以把角點(diǎn)理解為平面的交匯處或者邊的交點(diǎn),導(dǎo)致交點(diǎn)的局部區(qū)域具有多個不同區(qū)域的不同方向的邊界。角點(diǎn)在保留圖像圖形重要特征的同時,可以有效地減少信息的數(shù)據(jù)量,有效地提高了計算的速度,有利于圖像的可靠匹配,該方法也是特征檢測與匹配的基礎(chǔ)。harris角點(diǎn)檢測是一種直接基于灰度圖像的角點(diǎn)提取算法。
總結(jié)來說,harris角點(diǎn)檢測就是:像素點(diǎn)梯度坐標(biāo)分布較散、梯度變化程度較大、對應(yīng)矩陣M 的特征值都較大時,窗口中含有角點(diǎn);像素點(diǎn)的梯度在某一個方向上變化較大、另一個方向上變化較小,相應(yīng)M 的特征值一個較大一個較小時,窗口中含有邊緣;像素點(diǎn)的梯度坐標(biāo)分布集中在原點(diǎn)附近、梯度變化幅度非常小、對應(yīng)M 的特征值都比較小時,窗口處于平坦區(qū)域。且具有旋轉(zhuǎn)不變性、對亮度和對比度的變化不靈敏以及不具有尺度不變性等性質(zhì)。
從實(shí)驗(yàn)可以看出,對亮度和對比度的仿射變換并不改變Harris響應(yīng)的極值點(diǎn)出現(xiàn)的位置,但是,由于閾值的選擇,可能會影響角點(diǎn)檢測的數(shù)量。特征點(diǎn)的提取過程可以減少噪聲的影響,對灰度變化、圖像形變以及遮擋等都有較好的適應(yīng)能力。位置也會影響角點(diǎn)數(shù)量,特征點(diǎn)的匹配度量值相對位置變化比較敏感,可以提高匹配的精度。最后閥值對角點(diǎn)數(shù)量的影響也很大,閥值越大,角點(diǎn)數(shù)量就會越少。
總結(jié)
以上是生活随笔為你收集整理的局部图像描述子——Harris角点检测器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数字图像处理——形态学图像处理及图像分割
- 下一篇: 局部图像描述子——SIFT(尺度不变特征