在 DAY22 中我們學會了 Harris 與 Shi-Tomasi,能找出影像中的角點。
但這些方法雖然能找到角點,卻沒有提供每個角點的描述方式,因此無法直接用於影像比對。
本章將介紹經典的 SIFT(Scale-Invariant Feature Transform),它不僅能偵測關鍵點,還能提供特徵描述子(Feature Descriptors),用來做影像匹配、物件辨識等進階應用。
SIFT 的這些特性使其在物件辨識、場景重建、影像拼接等領域廣泛應用。
準備兩張圖片(同一場景但縮放或旋轉不同),例如 box.jpg
與 box_in_scene.jpg
。
import cv2
import numpy as np
# 讀取兩張圖片
img1 = cv2.imread("box.jpg")
img2 = cv2.imread("box_in_scene.jpg")
img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
cv2.imshow("Original img1", img1_gray)
cv2.imshow("Original img2", img2_gray)
# 將以下程式碼放在所有顯示語句的最後面
cv2.waitKey()
cv2.destroyAllWindows()
說明:
灰階影像能簡化計算,並保留角點偵測所需的亮度資訊。
在特徵點檢測前,通常會先進行去雜訊(如高斯模糊),以提升檢測品質。
# 建立 SIFT 物件
sift = cv2.SIFT_create()
# 偵測關鍵點與描述子
keypoints, descriptors = sift.detectAndCompute(img1_gray, None)
# 畫出關鍵點
img_sift = cv2.drawKeypoints(img1, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("SIFT Keypoints", img_sift)
程式說明:
detectAndCompute()
:同時偵測關鍵點 (keypoints)與計算描述子 (descriptors)。drawKeypoints()
:將關鍵點畫在影像上,圓圈大小代表關鍵點的尺度。# 建立 SIFT 物件
sift = cv2.SIFT_create()
# 偵測與計算特徵
kp1, des1 = sift.detectAndCompute(img1_gray, None)
kp2, des2 = sift.detectAndCompute(img2_gray, None)
# 建立 BFMatcher(暴力比對器)
bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
# 匹配特徵
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)
# 繪製前 20 個最佳匹配
img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, flags=2)
cv2.imshow("SIFT Matching", img_matches)
程式說明:
BFMatcher
:暴力比對器,使用 L2 距離計算描述子相似度。drawMatches()
:將兩張影像的匹配結果可視化,便於觀察匹配效果。方法 | 是否有描述子 | 尺度/旋轉不變性 | 適用場景 | 優點 | 缺點 |
---|---|---|---|---|---|
Harris | 無 | 無 | 角點偵測 | 計算簡單、速度快 | 無法做影像比對 |
Shi-Tomasi | 無 | 無 | 角點偵測、追蹤 | 角點品質高 | 無法做影像比對 |
SIFT | 有 | 有 | 影像比對、辨識 | 穩定性高、描述能力強 | 計算較慢、專利限制 |
補充說明: