Like Share Discussion Bookmark Smile

J.J. Huang   2026-02-07   Python OpenCV 05.特徵與進階篇   瀏覽次數:次   DMCA.com Protection Status

Python | OpenCV 特徵點偵測與匹配

📚 前言

在前一篇我們學會了 直方圖均衡化與圖片增強
這一篇要介紹 特徵點偵測 (Feature Detection)特徵匹配 (Feature Matching),包含常見的 SIFT、ORB 演算法,以及 BFMatcher、FLANN 匹配方法,這些技巧在圖片比對、物件辨識、拼接 (Stitching) 等應用中非常重要。

🎨 範例圖片

在進行特徵匹配之前,我們需要兩張圖片:

  • test1.png:原始圖片(這裡使用部落格頭像 test.png
  • test2.png:經過縮小或旋轉的版本,用來模擬真實場景中的角度或大小差異。

💻 範例程式 — 產生 test1.png 與 test2.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import cv2
import numpy as np

# 讀取原始圖片 (部落格頭像)
img = cv2.imread("test.png")

# 儲存原始圖片為 test1.png
cv2.imwrite("test1.png", img)

# 縮小
small = cv2.resize(img, None, fx=0.7, fy=0.7)

# 旋轉
(h, w) = img.shape[:2]
M = cv2.getRotationMatrix2D((w//2, h//2), 30, 1.0)
rotated = cv2.warpAffine(img, M, (w, h))

# 透視變換 (模擬角度改變)
pts1 = np.float32([[0,0],[w,0],[0,h],[w,h]])
pts2 = np.float32([[50,50],[w-50,30],[30,h-50],[w-30,h-30]])
M = cv2.getPerspectiveTransform(pts1, pts2)
warped = cv2.warpPerspective(img, M, (w, h))

# 儲存其中一個版本作為 test2.png
cv2.imwrite("test2.png", rotated)


圖:原始圖片 test1.png (部落格頭像)


圖:旋轉後的圖片 test2.png,用於特徵匹配測試

🔎 SIFT (Scale-Invariant Feature Transform)

原理說明

  • SIFT 能偵測圖片中的 關鍵點 (Keypoints),並計算其 描述子 (Descriptors)
  • 特點是對 縮放、旋轉、亮度變化 具有不變性。
  • 適合用於精準的圖片匹配。

參數說明

1
cv2.SIFT_create(nfeatures=0, nOctaveLayers=3, contrastThreshold=0.04, edgeThreshold=10, sigma=1.6)
  • nfeatures:最多保留的特徵點數量,0 表示不限制。
  • nOctaveLayers:金字塔層數,預設 3。
  • contrastThreshold:對比度閾值,過低的特徵點會被忽略。
  • edgeThreshold:邊緣閾值,過強的邊緣點會被忽略。
  • sigma:高斯模糊的標準差。

💻 範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2

img = cv2.imread("test1.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(gray, None)

sift_img = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

cv2.imshow("SIFT Keypoints", sift_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


圖:程式碼執行結果 — SIFT 偵測到的特徵點

🔎 ORB (Oriented FAST and Rotated BRIEF)

原理說明

  • ORB 是 FAST + BRIEF 的改良版,速度快且效果好。
  • 特點是 免費、輕量,適合即時應用。
  • 對旋轉與縮放有一定不變性。

參數說明

1
cv2.ORB_create(nfeatures=500)
  • nfeatures:最多保留的特徵點數量。

💻 範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2

img = cv2.imread("test1.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

orb = cv2.ORB_create(nfeatures=500)
keypoints, descriptors = orb.detectAndCompute(gray, None)

orb_img = cv2.drawKeypoints(img, keypoints, None, color=(0,255,0), flags=0)

cv2.imshow("ORB Keypoints", orb_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


圖:程式碼執行結果 — ORB 偵測到的特徵點

🔎 特徵匹配 — BFMatcher

原理說明

  • BFMatcher (Brute-Force Matcher) 逐一比較描述子,找出最佳匹配。
  • 適合小型資料集,簡單直接。

參數說明

1
cv2.BFMatcher(normType=cv2.NORM_L2, crossCheck=False)
  • normType:距離度量方式,SIFT 用 cv2.NORM_L2,ORB 用 cv2.NORM_HAMMING
  • crossCheck:是否雙向檢查匹配,預設 False。

💻 範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import cv2

img1 = cv2.imread("test1.png", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("test2.png", cv2.IMREAD_GRAYSCALE)

sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x:x.distance)

match_img = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, flags=2)

cv2.imshow("BFMatcher", match_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


圖:程式碼執行結果 — BFMatcher 匹配結果

🔎 特徵匹配 — FLANN

原理說明

  • FLANN (Fast Library for Approximate Nearest Neighbors) 適合大型資料集。
  • 使用近似最近鄰演算法,比 BFMatcher 更快。
  • 常用於圖片拼接、場景比對等需要大量匹配的應用。

參數說明

1
cv2.FlannBasedMatcher(indexParams, searchParams)
  • indexParams:索引參數,例如 dict(algorithm=1, trees=5)
  • searchParams:搜尋參數,例如 dict(checks=50)

💻 範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import cv2

img1 = cv2.imread("test1.png", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("test2.png", cv2.IMREAD_GRAYSCALE)

sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

index_params = dict(algorithm=1, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)

matches = flann.knnMatch(des1, des2, k=2)

good = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good.append(m)

match_img = cv2.drawMatches(img1, kp1, img2, kp2, good, None, flags=2)

cv2.imshow("FLANN Matcher", match_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


圖:程式碼執行結果 — FLANN 匹配結果

📊 效果比較

方法 特點 適用情境
SIFT 精準、對縮放旋轉不變 高精度圖片比對
ORB 快速、免費、輕量 即時應用、嵌入式系統
BFMatcher 暴力匹配,簡單直接 小型資料集
FLANN 近似最近鄰,速度快 大型資料集

🚀 應用場景

特徵點偵測與匹配雖然看起來抽象,但在電腦視覺中非常常見,以下是幾個實際用途:

  • 圖片拼接 (Image Stitching):把多張照片自動拼接成全景圖,常見於手機相機的「全景模式」。
  • 物件辨識 (Object Recognition):偵測並辨識特定物件,例如商標、書籍封面、地標建築。
  • 場景比對 (Scene Matching):在不同角度或光線下拍攝的照片中,找出相同的場景,常用於 AR 或機器人定位。
  • 文件比對 (Document Matching):比對掃描文件或照片,確認是否為同一份文件,即使有縮放或旋轉。
  • 追蹤與定位 (Tracking & Localization):在影片中追蹤某個物件,或在地圖上定位相機位置,常用於無人機或機器人導航。
  • 3D 重建 (3D Reconstruction):從多張不同角度的照片中,找出共同特徵點,進而重建三維模型。

⚠️ 注意事項

  • SIFT 在部分 OpenCV 版本需額外安裝 opencv-contrib-python
  • ORB 適合快速應用,但精度略低於 SIFT。
  • BFMatcher 適合小型資料集,FLANN 適合大型資料集。
  • 特徵匹配常搭配 RANSAC 過濾錯誤匹配,提升準確度。

🎯 結語

本篇我們學會了 SIFT、ORB 特徵點偵測,以及 BFMatcher、FLANN 特徵匹配,能找出圖片中的關鍵點並進行比對。
這些技巧在 圖片拼接、物件辨識、場景比對、AR、導航、3D 重建 等領域都有廣泛應用。

📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀,掌握完整的章節目錄,方便快速找到你需要的內容。

註:以上參考了
OpenCV Tutorials
OpenCV-Python Tutorials