SIFT(Scale - Invariant Feature Transform,尺度不變特征變換)是一種計算機視覺領域的特征提取算法,具有重要的地位和廣泛的應用。
算法原理
-
構建高斯金字塔 :
為了實現多尺度檢測,SIFT 算法會構建高斯金字塔。首先將原始圖像進行高斯模糊,然后依次對模糊后的圖像進行降采樣,每次降采樣后圖像尺寸減半,從而得到一系列不同尺度的圖像,構成一個八度。通常會構建多個八度,每個八度包含若干層,以覆蓋不同的尺度范圍。
-
差分高斯金字塔與關鍵點檢測 :
基于高斯金字塔構建差分高斯金字塔,即將同一八度中相鄰兩層高斯圖像相減得到。關鍵點檢測就是在這個差分高斯金字塔中,通過尋找每個樣本點在周圍鄰域中的極值點來確定。具體來說,對于每個圖像點,會將其與同層相鄰的 8 個點以及上下層相鄰的 9 個點(共 26 個點)進行比較,如果該點的差分高斯響應值是這 26 個點中的最大值或最小值,則認為該點是一個極值點,即候選關鍵點。
-
關鍵點定位與篩選 :
為了提高關鍵點的定位精度,并去除一些低對比度的關鍵點和不穩定的邊緣響應點,需要對初步檢測到的關鍵點進行定位和篩選。通過擬合三維二次函數到鄰域像素來對關鍵點的位置和尺度進行迭代精修,確定其精確位置和對應的尺度。同時,計算關鍵點的對比度,去除對比度過低的點,以確保關鍵點的穩定性。
-
關鍵點方向賦值 :
為了使關鍵點具有旋轉不變性,需要為每個關鍵點分配一個方向。在關鍵點的鄰域內,利用高斯加權函數計算圖像梯度的方向直方圖。直方圖的峰值方向即為該關鍵點的主方向,關鍵點的方向由其鄰域內梯度的方向分布情況來確定,從而使得關鍵點描述子具有旋轉不變性。
-
關鍵點描述子生成 :
在關鍵點周圍選取一個鄰域,將該鄰域分成多個子區域,例如將 16×16 的鄰域分成 16 個 4×4 的子區域。在每個子區域內計算梯度的方向直方圖,通常使用 8 個方向作為直方圖的柱,從而得到每個子區域的 8 維向量。將所有子區域的向量連接起來,就形成了一個 128 維的向量作為該關鍵點的描述子。
特點
-
尺度不變性 :能夠在不同尺度的圖像中檢測到相同的特征點,對圖像的縮放具有很強的魯棒性。
-
旋轉不變性 :通過為關鍵點賦予方向,使得描述子與關鍵點的方向相關,從而在圖像旋轉時仍能保持匹配的準確性。
-
局部性與鮮明性 :提取的特征是圖像中的局部特征,具有鮮明的局部信息,能夠很好地抵抗遮擋、光照變化等問題,且在圖像中具有較高的獨特性,便于區分不同的物體或場景。
-
可重復性與穩定性 :對于同一場景或物體的不同圖像,能夠穩定地提取出相似的關鍵點,減少了特征點的丟失和誤檢,具有較高的可重復性。
應用
-
圖像匹配 :在全景圖拼接、圖像搜索、目標識別等需要對兩幅或多幅圖像進行匹配的場景中,SIFT 算法被廣泛應用。通過提取并匹配兩幅圖像中的 SIFT 特征,可以確定圖像之間的對應關系,進而實現圖像的拼接、查詢或識別。
-
目標識別與定位 :在機器人導航、自動駕駛、工業自動化等領域,SIFT 特征可用于識別和定位目標物體。例如,在自動駕駛中,通過對道路標志或車輛的 SIFT 特征進行匹配和識別,幫助車輛實現自主導航和目標檢測。
-
三維重建 :在基于圖像的三維重建中,SIFT 特征用于確定多幅圖像之間的特征對應關系,從而計算出相機的內外參數以及場景的三維結構信息。
優點與缺點
-
優點 :能夠自動檢測出大量的特征點,且具有良好的重復性和穩定性,對尺度、旋轉、光照變化以及一定程度的仿射變換具有魯棒性,特征的區分能力較強,適合于大規模的圖像匹配和目標識別任務。
-
缺點 :計算復雜度較高,尤其是在處理高分辨率圖像或多幅圖像進行匹配時,計算速度可能會較慢。此外,SIFT 算法在面對視角變化較大、特征重復性較高或者存在大量相似特征的場景時,可能會出現一定的匹配錯誤或特征點匹配不足的問題。
環境準備
-
Python :確保已安裝 Python 環境,推薦 3.6 及以上版本。
-
OpenCV :通過
pip install opencv-python
命令安裝 OpenCV 庫,它提供了豐富的計算機視覺功能,包括 SIFT 算法。
使用示例代碼
import cv2
import numpy as np# 讀取圖像
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)# 初始化 SIFT 檢測器
sift = cv2.SIFT_create()# 檢測關鍵點和計算描述符
keypoints1, descriptors1 = sift.detectAndCompute(img1, None)
keypoints2, descriptors2 = sift.detectAndCompute(img2, None)# 使用 FLANN 進行特征匹配
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(descriptors1, descriptors2, k=2)# 應用比率測試篩選匹配項
good_matches = []
for m, n in matches:if m.distance < 0.7 * n.distance:good_matches.append(m)# 獲取匹配點的坐標
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)# 計算單應性矩陣
if len(good_matches) > 4:M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)matches_mask = mask.ravel().tolist()
else:matches_mask = None# 繪制匹配結果
draw_params = dict(matchColor=(0, 255, 0),singlePointColor=None,matchesMask=matches_mask,flags=2)result_img = cv2.drawMatches(img1, keypoints1, img2, keypoints2, good_matches, None, **draw_params)
-
關鍵點檢測與描述符計算 :
sift.detectAndCompute()
函數用于檢測圖像中的關鍵點并計算對應的描述符。 -
特征匹配 :使用 FLANN(快速最近鄰搜索)匹配算法進行特征匹配,
knnMatch()
方法返回每個特征點的兩個最近鄰匹配。 -
比率測試 :通過比較兩個最近鄰匹配的距離,篩選出高質量的匹配項,以減少誤匹配。
-
單應性計算 :如果匹配項數量足夠(大于 4 個),使用 RANSAC 算法計算單應性矩陣,用于確定圖像之間的幾何變換關系。
-
結果繪制 :
cv2.drawMatches()
函數用于繪制匹配結果,顯示在圖像上。
注意事項
-
專利問題 :SIFT 是專利算法,雖專利已過期,但商業使用時仍需考慮許可問題。
-
計算復雜度 :SIFT 算法計算復雜度較高,處理大圖像時可能耗時較長。