局部特徵匹配 Local Feature Matching
項目要求
- 實現興趣點檢測
- 實現類SIFT局部特徵描述
- 實現簡單匹配算法
項目原理
局部特徵
全局特徵(global features)指的是圖像的方差、顏色直方圖等等,描繪了圖像的整體信息,但是無法分辨出圖像中的前景和背景。
局部特徵(loacl features)指的是一些局部纔會出現的特徵,而且該部分需要滿足兩個條件:1. 能夠穩定出現; 2. 具有良好的可區分性。
當我們所關注的對象在圖像中受到部分遮擋,全局特徵可能會被破壞,但局部特徵依然能夠穩定存在,以代表這個物體。
圖像中的特徵點
一幅圖像中總存在着其獨特的像素點,這些點我們可以認爲就是這幅圖像的特徵,成爲特徵點。計算機視覺領域中的很重要的圖像特徵匹配就是一特徵點爲基礎而進行的,所以,如何定義和找出一幅圖像中的特徵點就非常重要。
在計算機視覺領域,興趣點(也稱關鍵點或特徵點)的概念已經得到了廣泛的應用, 包括目標識別、 圖像配準、 視覺跟蹤、 三維重建等。 這個概念的原理是, 從圖像中選取某些特徵點並對圖像進行局部分析,而非觀察整幅圖像。 只要圖像中有足夠多可檢測的興趣點,並且這些興趣點各不相同且特徵穩定, 能被精確地定位,上述方法就十分有效。
好的特徵應該有以下幾個特點:
- 重複性:不同圖像的相同區域應該能被重複檢測到,而且不受旋轉、模糊、光照等因素的影響。
- 可區分性:不同的檢測子應可通過檢測對應的描述子進行區分。
- 數量適宜:檢測子的數量過多或者過少都會降低識別精度。
- 高定位:檢測子的大小和位置均應固定。
- 有效性:具有較快的檢測速度。
Harris角點(Harris Corner Detector)
角點的基本原理:人眼對角點的識別通常是在一個局部的小區域或小窗口完成的。如果在各個方向上移動這個特徵的小窗口,窗口內區域的灰度發生了較大的變化,那麼就認爲在窗口內遇到了角點。如果這個特定的窗口在圖像各個方向上移動時,窗口內圖像的灰度沒有發生變化,那麼窗口內就不存在角點;如果窗口在某一個方向移動時,窗口內圖像的灰度發生了較大的變化,而在另一些方向上沒有發生變化,那麼,窗口內的圖像可能就是一條直線的線段。
角點具有一些良好的特徵:視角變化時也仍然可以很好的辨識;和周圍點在任何方向上變化都很大。角點經常被檢測在邊緣的交界處、被遮擋的邊緣、紋理性很強的部分。滿足這些條件一般都是穩定的、重複性比較高的點,所以實際上他們是不是角點並不重要(因爲我們的目標就是找一些穩定、重複性高的點以作爲特徵點)。
Harris Corner是最典型的角點檢測子,具有的優點是平移不變、旋轉不變,能克服一定光照變化。
NMS(非最大值抑制)
NMS(Non-Maximum Supression)非最大抑制,就是抑制除最大值(局部最優)外的其他元素。比如在下圖中要確認人行道上的車輛,需要找到區域內識別概率最大的框,所以將右邊0.9的框和左邊0.8的框高亮,之後遍歷其他邊框,如果和高亮的框交併比大於0.5,則將框進行淡化(抑制)。
SIFT(尺度不變特徵變換)
SIFT(Scale-Invariant Feature Transform)尺度不變特徵變換,是計算機視覺領域對圖像局部特徵進行描述的常用方法,有以下四個關鍵步驟
1. 尺度空間極值檢測(Scale-space extrema detection)
建立高斯差分金字塔,採用不同(尺度)的高斯覈對原圖像進行卷積操作,得到一組不同層的圖片,而不同組之間的圖片通過降採樣(隔點取點)得到。通過不斷的變化高斯核和進行降採樣,便可以得到高斯金字塔。再通過同一組不同兩層之間的圖片相減,就得到高斯差分金字塔(又叫尺度空間),如下圖所示。
其中,
組數,其中M和N是圖片的長和寬。
層數 ,其中n是希望提取從中特徵的圖片數目,因爲做差分的過程中有一張圖片無法使用,同時尺度空間上最上面一張和最下面一張圖片無法求導,所以S-3=n。
取法請見參考資料中原論文,不在此贅述。
理解:因爲SIFT要解決尺度不變性問題,它的理念是不僅在任何尺度下拍攝的物體都能檢測到一致的關鍵點,而且每個被檢測的特徵點都對應一個尺度因子。 在高斯金字塔中,其實降採樣就是模擬了近大遠小的尺寸變化,高斯核進行卷積模擬的是近處清晰,遠處模糊。(PS:值得注意的是,高斯核是唯一一個可以模擬近處清晰,遠處模糊的線性核)
2. 關鍵點定位(Keypoint Localization)
關鍵點需要滿足:包含很多信息,穩定不易變化。關鍵點通常是極值位置。
-> 1. 閾值化
,其中T=0.04,因爲如果太小了可能是噪聲,不進行保留。
-> 2. 在高斯差分金字塔中找極值
在考慮了尺度空間後,如果一個像素點的值比周圍26個像素點都大(小),那麼就認爲這個點是一個極值。
-> 3. 調整極值點的位置
因爲像素空間和尺度空間均是離散的,所有需要找到亞像素位置的精確極值點,具體操作是在檢測到的極值點處做三元二階泰勒展開,再對函數進行求導並令導數爲零。
-> 4. 捨去低對比度的點
若則認爲該像素點事噪聲,捨去點X
-> 5. 邊緣效應的去除
3. 方向賦值(Orientation assignment)
在最接近關鍵點尺度值的高斯圖像上,統計以特徵點爲圓心,以該特徵點所在的高斯圖像的尺度的1.5倍爲半徑的圓內所有像素的梯度方向以及其梯度幅值,並做的高斯濾波。
4. 關鍵點描述(Keypoint descriptor)
關鍵點的描述符是一個128維的向量,用k近臨算法進行向量匹配兩個圖片當中所有關鍵點的描述符中距離最近的兩個描述符,並進行連接。
在每一個子區域內統計八個方向上的梯度的經過高斯加權的長度,將每個子區域內的各個方向上的長度依次寫出,便得到描述符。
Soble算子
索貝爾算子是計算機視覺領域的一種重要處理方法。主要用於獲得數字圖像的一階梯度,常見的應用和物理意義是邊緣檢測。索貝爾算子是把圖像中每個像素的上下左右四領域的灰度值加權差,在邊緣處達到極值從而檢測邊緣。
Soble算子模版:
Gx:
Gy:
實驗步驟
(一) 讀取圖像,並對圖像進行預處理
簡介
讀取圖像,將圖片的長和寬放縮爲原來的1/2,再轉化爲灰度圖。
sepup_image()
def setup_image(img_name):
image = load_image('../data/'+img_name+'/'+img_name+'.jpg')#載入圖像
eval_file = '../data/'+img_name+'/'+img_name+'Eval.mat'#載入標準匹配矩陣
scale_factor = 0.5 #設置縮放係數
image = cv2.resize(image, (0, 0), fx=scale_factor, fy=scale_factor)#將圖片進行縮放
image_bw = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) #進行灰度處理
return image_bw
(二)使用Harris Corner Detector查找圖像中的角點
簡介
首先需要對圖片進行興趣點檢測,我使用Harris Corner Detector來檢查圖像中的角點,通過用矩陣的行列式減去矩陣的平方來確定特定像素得分,得分越高的像素越具有角的特徵,具體評判標準由閾值人爲設定。如果像素的角點得分高於閾值,便認爲它是一個角點,否則就忽略它。帶有角點標記的圖像如下面兩張圖所示。可見,檢測到大量的角點,且角點在圖像上的分佈不均勻。爲了保證角點分佈的均勻性,我採用了自適應的MNS來抑制多餘的角點。
get_interest_points()
- 獲得圖片的尺寸(長和寬)
ImageRows = image.shape[0]
ImageColumns = image.shape[1]
- 利用Sobel算子進行邊緣檢測,第二個參數cv2.CV_64F表示64位浮點數即64float,第三和第四個參數分別是對X和Y方向的導數(即dx,dy),對於圖像來說就是差分,這裏1表示對X求偏導(差分),0表示不對Y求導(差分),第五個參數ksize是指核的大小。
imX = cv2.Sobel(image, cv2.CV_64F,1,0,ksize=5)
imY = cv2.Sobel(image, cv2.CV_64F,0,1,ksize=5)
- 計算Harris矩陣分量(包括矩陣特徵值和跡,以及角點相應函數R)
Ixx = (Xderivative)*(Xderivative)
Iyy = (Yderivative)*(Yderivative)
Ixy = (Xderivative)*(Yderivative)
for i in range(16, ImageRows - 16):
for j in range(16, ImageColumns - 16):
Ixx1 = Ixx[i-1:i+1, j-1:j+1]
Iyy1 = Iyy[i-1:i+1, j-1:j+1]
Ixy1 = Ixy[i-1:i+1, j-1:j+1]
Ixxsum = Ixx1.sum()
Iyysum = Iyy1.sum()
Ixysum = Ixy1.sum()
Determinant = Ixxsum*Iyysum - Ixysum**2 #計算矩陣的特徵值
Trace = Ixxsum + Iyysum #計算矩陣的跡
R = Determinant - alpha*(Trace**2) #角點相應函數R
#判斷每個像素相應函數是否大於閾值R,如果大於閾值則合格。
if R > threshold:
XCorners.append(j)
YCorners.append(i)
RValues.append(R)
XCorners = np.asarray(XCorners)
YCorners = np.asarray(YCorners)
RValues = np.asarray(RValues)
- 使用非最大抑制算法(ANMS)進行角點過濾,返回滿足條件的角點座標和得分。ANMS函數在下面給出。
NewCorners = ANMS(XCorners, YCorners, RValues, 3025)
NewCorners = np.asarray(NewCorners)
x = NewCorners[:,0]
y = NewCorners[:,1]
scales = NewCorners[:,2]
return x,y, scales
輸出
下圖爲Harris Corner Detector對NotreDame圖像的角點檢測結果。
(三)使用ANMS進行角點篩選以獲得高分特徵點
簡介
使用Harris Corner Detector生成的角點不是均勻分佈的。在許多情況下角點可能集中在圖像的特定區域,從而導致準確性的下降。NMS算法通過在特徵函數中尋找局部最大值並丟棄剩餘的次大值(即圖像中的臨近角點)。通過使用該算法,可以提高特徵匹配的準確性,但是傳統的NMS具有某些侷限性,例如圖像中特徵點在處理後可能會不均勻分佈。爲了避免這種情況,所以使用ANMS算法(自適應非最大值抑制),基本思想是僅保留r個像素附近最大的那些點。下面兩張圖顯示了使用Harris角點檢測器生成的特徵點與抑制後剩餘的特徵點之間的比較。可見,圖像中的特徵點已從數7000個左右抑制到1500個,且均勻分佈。
ANMS()
def ANMS (x , y, r, maximum):
i = 0
j = 0
NewList = []
while i < len(x):
minimum = 1000000000000
#獲得一個harris角點的橫縱座標,稱爲基礎點
X, Y = x[i], y[i]
while j < len(x):#遍歷除該角點外每一個得分(R值)更高的角點,稱爲比較點,找到離基礎點最近的一個比較點,記錄下基礎點的橫縱座標和與最近比較點之間的距離
CX, CY = x[j], y[j]
if (X != CX and Y != CY) and r[i] < r[j]:
distance = math.sqrt((CX - X)**2 + (CY - Y)**2)
if distance < minimum:
minimum = distance
j = j + 1
NewList.append([X, Y, minimum])
i = i + 1
j = 0
#根據距離大小對基礎點進行排序,很顯然,距離越小的點說明在該角點周圍有更好的角點,所以可以適當捨棄。在捨棄一定數目的得分較小的角點後,就得到了非最大抑制後的harris角點座標。
NewList.sort(key = lambda t: t[2])
NewList = NewList[len(NewList)-maximum:len(NewList)]
return NewList
輸出
下圖顯示了NotreDame圖像使用ANMS進行角點篩選後的特徵點。
(四)構建SIFT功能描述符
簡介
爲每個特徵點創建的特徵向量,用於將第一幅圖像的關鍵點與第二幅圖像的關鍵點進行匹配。爲此,計算第一圖像中每個關鍵點的每個特徵向量到第二圖像中每個特徵向量的距離。然後對距離進行排序,並獲取和比較兩個最小距離。爲了使關鍵點與第二個圖像中的另一個關鍵點精確匹配,計算並檢查兩個最小距離的比率是否大於指定的閾值,之後將其視爲關鍵點。
get_features()
功能
獲得給定興趣點集的一組特徵描述符。
參數
image:灰度圖
x:興趣點的x座標(np array)
y:興趣點的y座標(np array)
feature_width:局部特徵寬度(以像素爲單位)
返回值
fv:規範化特徵向量
具體步驟
- 初始化高斯濾波器,使用高斯模糊降低圖像中的噪點,並獲得圖像的尺寸。
filter1 = cv2.getGaussianKernel(ksize=4,sigma=10)
filter1 = np.dot(filter1, filter1.T)
image = cv2.filter2D(image, -1, filter1)
ImageRows = image.shape[0]
ImageColumns = image.shape[1]
xlen = len(x)
ylen = len(y)
FeatureVectorIn = np.ones((xlen,128))
NormalizedFeature = np.zeros((ylen,128))
- 遍歷Harris算法得到的每一個角點座標,提取以該角點座標爲中心的16x16像素的一個局部圖像,對於每一個局部圖像,拆分成16個4x4像素的窗口,計算窗口內每個像素的大小和方向。
for i in range(xlen):
temp1 = int(x[i])
temp2 = int(y[i])
Window = image[temp2-8:temp2 + 8, temp1-8:temp1 + 8]
WindowRows = Window.shape[0]
WindowColumns = Window.shape[1]
for p in range(4):
for q in range(4):
WindowCut = Window[p*4:p*4 +4,q*4: q*4+4]
NewWindowCut = cv2.copyMakeBorder(WindowCut, 1, 1, 1, 1, cv2.BORDER_REFLECT)
Magnitude = np.zeros((4,4))
Orientation = np.zeros((4,4))
for r in range(WindowCut.shape[0]):
for s in range(WindowCut.shape[1]):
Magnitude[r,s] = math.sqrt((NewWindowCut[r+1,s] - NewWindowCut[r-1,s])**2 + (NewWindowCut[r,s+1] - NewWindowCut[r,s-1])**2)
Orientation[r,s] = np.arctan2((NewWindowCut[r+1,s] - NewWindowCut[r-1,s]),(NewWindowCut[r,s+1] - NewWindowCut[r,s-1]))
- 對於每一個窗口,以方向爲橫座標建立直方圖(共8個方向),窗口內所有像素在方向上的加權和爲直方的幅度值,這樣就得到了每一個角點的局部圖像中每個窗口表示大小和方向的特徵向量。
Magnitude = Magnitude
OrientationNew = Orientation*(180/(math.pi))
hist, edges = np.histogram(OrientationNew, bins = 8, range = (-180,180), weights = Magnitude)
for t in range(8):
l = t+p*32+q*8
FeatureVectorIn[i,l] = hist[t]
- 正則化特徵向量,並返回值。
for a in range(FeatureVectorIn.shape[0]):
sum1 = 0
for b in range(FeatureVectorIn.shape[1]):
sum1 = sum1 + (FeatureVectorIn[a][b])*(FeatureVectorIn[a][b])
sum1 = math.sqrt(sum1)
for c in range(FeatureVectorIn.shape[1]):
NormalizedFeature[a][c] = FeatureVectorIn[a][c]/sum1
fv = NormalizedFeature
return fv
輸出
下圖顯示了NotreDame圖像對中前100個關鍵點匹配項。
(五)特徵匹配
簡介
在得到兩個圖像的SIFT特徵描述符和Harries算法得到的角點座標後,即可通過計算特徵向量之間的距離,進行圖像的特徵匹配。
match_features()
- 對於圖片1的每一個SIFT特徵描述符遍歷圖片2的每一個SIFT特徵描述符,分別計算它們和圖一特徵向量之間的歐式距離。
for x in range(features1.shape[0]):
for y in range(features2.shape[0]):
ExtractedRow1 = features1[[x],:]
ExtractedRow2 = features2[[y],:]
SubtractedRow = ExtractedRow1 - ExtractedRow2
Square = SubtractedRow*SubtractedRow
Sum = Square.sum()
Sum = math.sqrt(Sum)
Distance[x,y] = Sum
- 按照距離大小對圖片2的特徵向量進行升序排序,取與圖一特徵向量距離最小的兩個,若兩者的距離只比小於閾值,則說明最佳的匹配效果較好,記錄下圖一和圖二兩個特徵向量的座標。若大於閾值則不操作。在對圖一所有特徵向量遍歷完後,返回每一對需匹配的特徵向量的座標,和兩者之間的距離。
IndexPosition = np.argsort(Distance[x,:])
d1 = IndexPosition[0]
d2 = IndexPosition[1]
Position1 = Distance[x,d1]
Position2 = Distance[x,d2]
ratio = Position1/Position2
if ratio<0.8:
Hitx.append(x)
Hity.append(d1)
Value.append(Position1)
Xposition = np.asarray(Hitx)
Yposition = np.asarray(Hity)
matches = np.stack((Xposition,Yposition), axis = -1)
confidences = np.asarray(Value)
return matches, confidences
效果
實驗結果
load 標準配對數據文件和SIFT功能描述符的匹配結果進行比較,結果如下:
- NotreDame的配對準確率爲79%,如下圖所示
- MountRushmore的配對準確率爲32%,如下圖所示。
其他: - LaddObservatory
參考鏈接
Project 2: Local Feature Matching
CSCI 1430: Introduction to Computer Vision
特徵檢測和特徵匹配方法
局部特徵(1)——入門篇
Harris角點
C4W3L07 Nonmax Suppression
Distinctive Image Features from Scale-Invariant Keypoints-David G. Lowe