深入剖析 OpenCV:全面掌握基礎操作、圖像處理算法與特征匹配
- 一、引言
- 二、OpenCV 的安裝
- (一)使用 pip 安裝
- (二)使用 Anaconda 安裝
- 三、OpenCV 基礎操作
- (一)圖像的讀取、顯示與保存
- (二)圖像的基本屬性與操作
- (三)顏色空間轉換
- 四、OpenCV 的圖像處理算法
- (一)圖像濾波
- (二)邊緣檢測
- (三)形態學操作
- 五、OpenCV 的特征提取與匹配
- (一)ORB 特征提取
- (二)SIFT 特征提取
- (三)特征匹配
- 1. ORB 特征匹配
- 2. SIFT 特征匹配
一、引言
在當今數字化的時代,計算機視覺技術正以前所未有的速度改變著我們的生活。從智能手機的人臉識別解鎖到自動駕駛汽車的環境感知,從工業生產中的質量檢測到醫療領域的影像分析,計算機視覺無處不在。OpenCV(Open Source Computer Vision Library)作為計算機視覺領域最具影響力的開源庫之一,為開發者和研究人員提供了強大而便捷的工具。它擁有超過 2500 種優化算法,涵蓋了圖像和視頻處理、特征提取、目標檢測、機器學習等多個領域。本文將基于 Python 語言,全面深入地介紹 OpenCV 的各個方面,從基礎操作到高級應用,幫助讀者逐步掌握這一強大的工具。
二、OpenCV 的安裝
在 Python 環境中安裝 OpenCV 非常便捷,主要有兩種常見的安裝方式。
(一)使用 pip 安裝
通過 pip
包管理器,我們可以輕松地安裝 OpenCV。在命令行中輸入以下命令:
pip install opencv-python
如果需要安裝包含擴展功能的版本(如 SIFT、SURF 等算法,這些算法在非商業用途下可用),可以使用以下命令:
pip install opencv-contrib-python
(二)使用 Anaconda 安裝
如果你使用 Anaconda 作為 Python 環境管理工具,可以使用以下命令進行安裝:
conda install -c conda-forge opencv
安裝完成后,我們可以在 Python 代碼中導入 OpenCV 庫進行測試:
import cv2
print(cv2.__version__)
如果能夠正常輸出 OpenCV 的版本號,說明安裝成功。
如4.11.0
以下是去掉對圖像讀取檢查后的代碼內容,為你擴充了標題 3 - 5 的代碼和解釋:
三、OpenCV 基礎操作
(一)圖像的讀取、顯示與保存
- 讀取圖像
使用cv2.imread()
函數讀取圖像文件,支持常見的圖像格式如.jpg
、.png
等。函數第一個參數為圖像文件路徑,第二個參數指定讀取模式。常見的讀取模式有:cv2.IMREAD_COLOR
:以彩色模式讀取圖像,默認模式。cv2.IMREAD_GRAYSCALE
:以灰度模式讀取圖像。cv2.IMREAD_UNCHANGED
:讀取包含透明度通道的圖像。
import cv2# 以彩色模式讀取圖像
color_image = cv2.imread('example.jpg', cv2.IMREAD_COLOR)
# 以灰度模式讀取圖像
gray_image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 讀取包含透明度通道的圖像
alpha_image = cv2.imread('example.png', cv2.IMREAD_UNCHANGED)
解釋:cv2.imread()
是 OpenCV 中用于讀取圖像的核心函數。通過不同的讀取模式參數,可以靈活地獲取圖像的不同表示形式。彩色模式讀取的圖像包含三個通道(BGR),灰度模式將圖像轉換為單通道,而讀取帶透明度通道的圖像適用于處理 PNG 等支持透明度的圖像格式。
- 顯示圖像
通過cv2.imshow()
函數顯示圖像,第一個參數是窗口名稱,第二個參數是要顯示的圖像對象。使用cv2.waitKey()
等待用戶按鍵,cv2.destroyAllWindows()
關閉所有窗口。
# 顯示彩色圖像
cv2.imshow('Color Image', color_image)
# 顯示灰度圖像
cv2.imshow('Gray Image', gray_image)# 等待用戶按鍵(0 表示無限等待)
cv2.waitKey(0)
# 關閉所有窗口
cv2.destroyAllWindows()
解釋:cv2.imshow()
用于在一個新窗口中顯示圖像,窗口名稱用于區分不同的顯示窗口。cv2.waitKey()
函數會阻塞程序,直到用戶按下任意鍵,參數為 0 時表示無限等待。cv2.destroyAllWindows()
用于關閉所有由 OpenCV 創建的窗口,釋放資源。
- 保存圖像
利用cv2.imwrite()
函數保存圖像,第一個參數為保存路徑,第二個參數是要保存的圖像。
# 保存灰度圖像
cv2.imwrite('saved_gray_image.jpg', gray_image)
解釋:cv2.imwrite()
函數將指定的圖像保存到指定的文件路徑。保存的文件格式由文件擴展名決定,如 .jpg
、.png
等。
(二)圖像的基本屬性與操作
- 圖像的基本屬性
圖像在 OpenCV 中以 NumPy 數組形式存儲,我們可以獲取其高度、寬度和通道數等屬性。
import cv2image = cv2.imread('example.jpg')
height, width, channels = image.shape
print(f"圖像高度: {height}, 寬度: {width}, 通道數: {channels}")
# 額外獲取圖像的數據類型
print(f"圖像的數據類型: {image.dtype}")
解釋:圖像在 OpenCV 里被存儲為 NumPy 數組,通過 shape
屬性可以獲取圖像的基本尺寸信息,dtype
屬性則能查看圖像的數據類型,通常為 uint8
(8 位無符號整數)。
- 圖像的像素訪問
可以直接通過索引訪問和修改圖像的像素值。
import cv2image = cv2.imread('example.jpg')
# 獲取坐標(100, 100)處的像素值(BGR 格式)
pixel = image[100, 100]
print(f"坐標(100, 100)處的像素值(BGR 格式): {pixel}")
# 修改坐標(100, 100)處的像素值為白色
image[100, 100] = [255, 255, 255]
new_pixel = image[100, 100]
print(f"修改后坐標(100, 100)處的像素值(BGR 格式): {new_pixel}")
解釋:由于圖像是 NumPy 數組,所以可以像操作數組一樣通過索引來訪問和修改像素值。在 OpenCV 中,彩色圖像的像素值是按 BGR(藍、綠、紅)順序存儲的。
- 圖像的裁剪、縮放與旋轉
- 裁剪
通過指定行和列的范圍來裁剪圖像。
import cv2image = cv2.imread('example.jpg')
# 裁剪圖像,獲取坐標(100, 100)到(300, 300)的區域
cropped_image = image[100:300, 100:300]
cv2.imshow('Cropped Image', cropped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:裁剪圖像是通過指定數組的行和列范圍來實現的,即選取圖像中指定區域的像素值,形成新的圖像。
- 縮放
使用cv2.resize()
函數縮放圖像,可以指定縮放比例或目標尺寸。
import cv2image = cv2.imread('example.jpg')
# 按比例縮放,寬度和高度都變為原來的 0.5 倍
resized_image_1 = cv2.resize(image, None, fx=0.5, fy=0.5)
cv2.imshow('Resized Image by Scale', resized_image_1)# 指定目標尺寸進行縮放
resized_image_2 = cv2.resize(image, (300, 300))
cv2.imshow('Resized Image by Size', resized_image_2)cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:cv2.resize()
函數提供了靈活的縮放方式。fx
和 fy
參數用于指定水平和垂直方向的縮放比例,當第二個參數為 None
時使用這種方式。也可以直接指定目標尺寸,如 (300, 300)
來進行縮放。
- 旋轉
借助cv2.getRotationMatrix2D()
獲取旋轉矩陣,再用cv2.warpAffine()
進行旋轉操作。
import cv2
import numpy as npimage = cv2.imread('example.jpg')
height, width = image.shape[:2]
# 計算旋轉中心
center = (width / 2, height / 2)
# 定義旋轉角度和縮放因子
angle = 45
scale = 1.0
# 獲取旋轉矩陣
M = cv2.getRotationMatrix2D(center, angle, scale)
# 對圖像進行旋轉
rotated_image = cv2.warpAffine(image, M, (width, height))
cv2.imshow('Rotated Image', rotated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:cv2.getRotationMatrix2D()
用于計算旋轉矩陣,該矩陣包含了旋轉中心、旋轉角度和縮放因子等信息。cv2.warpAffine()
函數根據這個旋轉矩陣對圖像進行仿射變換,實現圖像的旋轉操作。
(三)顏色空間轉換
常見的顏色空間有 RGB、灰度、HSV、Lab 等,使用 cv2.cvtColor()
函數進行顏色空間轉換。
import cv2color_image = cv2.imread('example.jpg')
# 轉換為灰度圖像
gray_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2GRAY)
cv2.imshow('Gray Image', gray_image)# 轉換為 HSV 圖像
hsv_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2HSV)
cv2.imshow('HSV Image', hsv_image)# 轉換為 Lab 圖像
lab_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2Lab)
cv2.imshow('Lab Image', lab_image)cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:不同的顏色空間適用于不同的圖像處理任務。cv2.cvtColor()
函數可以在不同顏色空間之間進行轉換,例如將 BGR 彩色圖像轉換為灰度圖像、HSV 圖像或 Lab 圖像,方便后續的處理和分析。
四、OpenCV 的圖像處理算法
(一)圖像濾波
- 均值濾波
使用cv2.blur()
函數實現,通過計算局部區域像素平均值平滑圖像。
import cv2image = cv2.imread('example.jpg')
# 均值濾波,核大小為(5, 5)
blurred_image = cv2.blur(image, (5, 5))
cv2.imshow('Blurred Image (Mean Filter)', blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:均值濾波是一種簡單的線性濾波方法,它以一個固定大小的核(如 (5, 5)
)在圖像上滑動,計算每個核內像素的平均值,并將該平均值作為中心像素的新值,從而達到平滑圖像的效果。
- 高斯濾波
利用cv2.GaussianBlur()
函數,基于高斯函數對圖像進行濾波,抑制噪聲同時保留邊緣。
import cv2image = cv2.imread('example.jpg')
# 高斯濾波,核大小為(5, 5),標準差為 0
gaussian_blurred_image = cv2.GaussianBlur(image, (5, 5), 0)
cv2.imshow('Blurred Image (Gaussian Filter)', gaussian_blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:高斯濾波是一種非線性濾波方法,它根據高斯函數對核內的像素進行加權平均。相比于均值濾波,高斯濾波在抑制噪聲的同時能更好地保留圖像的邊緣信息,因為它對不同位置的像素賦予了不同的權重。
- 中值濾波
通過cv2.medianBlur()
函數,用局部區域的中值替換當前像素值,有效去除椒鹽噪聲。
import cv2image = cv2.imread('example.jpg')
# 中值濾波,核大小為 5
median_blurred_image = cv2.medianBlur(image, 5)
cv2.imshow('Blurred Image (Median Filter)', median_blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:中值濾波是一種非線性濾波方法,它將核內的像素值進行排序,然后用中值替換中心像素的值。這種方法對于去除椒鹽噪聲(圖像中出現的黑白孤立點)非常有效。
- 雙邊濾波
cv2.bilateralFilter()
函數可以在平滑圖像的同時保留邊緣信息,適用于需要保留圖像細節的場景。
import cv2image = cv2.imread('example.jpg')
# 雙邊濾波,直徑為 9,顏色標準差為 75,空間標準差為 75
bilateral_blurred_image = cv2.bilateralFilter(image, 9, 75, 75)
cv2.imshow('Blurred Image (Bilateral Filter)', bilateral_blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:雙邊濾波是一種保邊濾波方法,它結合了空間域和值域的信息。在平滑圖像時,它不僅考慮像素的空間距離,還考慮像素的顏色差異,因此能夠在平滑圖像的同時很好地保留邊緣和細節信息。
(二)邊緣檢測
- Canny 邊緣檢測
cv2.Canny()
函數是常用的邊緣檢測算法,通過計算圖像梯度和非極大值抑制等步驟檢測邊緣。
import cv2image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# Canny 邊緣檢測,設置高低閾值
edges = cv2.Canny(image, 100, 200)
cv2.imshow('Canny Edge Detection', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:Canny 邊緣檢測是一種多階段的邊緣檢測算法,主要包括高斯平滑、梯度計算、非極大值抑制和雙閾值處理等步驟。高低閾值參數用于控制邊緣的檢測范圍,只有當梯度值大于高閾值時才被確定為邊緣,介于高低閾值之間的像素如果與確定的邊緣相連也會被保留。
- Sobel 邊緣檢測
cv2.Sobel()
函數用于計算圖像在 x 和 y 方向上的梯度,從而檢測邊緣。
import cv2
import numpy as npimage = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 計算 x 方向的 Sobel 梯度
sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
# 計算 y 方向的 Sobel 梯度
sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
# 取絕對值并轉換為 8 位無符號整數
sobelx = np.uint8(np.absolute(sobelx))
sobely = np.uint8(np.absolute(sobely))
# 合并 x 和 y 方向的梯度
sobel_combined = cv2.bitwise_or(sobelx, sobely)
cv2.imshow('Sobel Edge Detection', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:Sobel 算子是一種一階導數算子,用于計算圖像在 x 和 y 方向上的梯度。通過分別計算兩個方向的梯度,可以檢測出圖像中的水平和垂直邊緣。最后將兩個方向的梯度合并,得到完整的邊緣信息。
- Laplacian 邊緣檢測
cv2.Laplacian()
函數通過計算圖像的二階導數來檢測邊緣。
import cv2image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# Laplacian 邊緣檢測
laplacian_edges = cv2.Laplacian(image, cv2.CV_64F)
laplacian_edges = np.uint8(np.absolute(laplacian_edges))
cv2.imshow('Laplacian Edge Detection', laplacian_edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:Laplacian 算子是一種二階導數算子,它對圖像的灰度變化非常敏感,能夠檢測出圖像中的邊緣。由于二階導數可能為負值,所以需要取絕對值并轉換為 8 位無符號整數才能正確顯示邊緣圖像。
(三)形態學操作
- 膨脹與腐蝕
膨脹操作可以擴大圖像中的前景區域,腐蝕操作則可以縮小前景區域。
import cv2
import numpy as npimage = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 定義結構元素
kernel = np.ones((5, 5), np.uint8)
# 膨脹操作
dilated_image = cv2.dilate(image, kernel, iterations=1)
# 腐蝕操作
eroded_image = cv2.erode(image, kernel, iterations=1)cv2.imshow('Dilated Image', dilated_image)
cv2.imshow('Eroded Image', eroded_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:膨脹和腐蝕是基本的形態學操作,它們基于結構元素(如 (5, 5)
的全 1 矩陣)對圖像進行處理。膨脹操作將結構元素在圖像上滑動,如果結構元素與前景區域有重疊,則將中心像素置為前景;腐蝕操作則相反,如果結構元素完全包含在前景區域內,才將中心像素置為前景。
- 開運算與閉運算
開運算先進行腐蝕操作,再進行膨脹操作,用于去除小的噪聲點;閉運算先進行膨脹操作,再進行腐蝕操作,用于填充小的空洞。
import cv2
import numpy as npimage = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
kernel = np.ones((5, 5), np.uint8)
# 開運算
opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
# 閉運算
closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)cv2.imshow('Opening Image', opening)
cv2.imshow('Closing Image', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:開運算和閉運算是基于膨脹和腐蝕操作的組合。開運算可以去除圖像中的小噪聲點,同時保持大的前景區域不變;閉運算則可以填充前景區域內的小空洞,使前景區域更加完整。
- 形態學梯度
形態學梯度是膨脹圖像與腐蝕圖像的差值,用于突出圖像的邊緣。形態學梯度能夠幫助我們檢測圖像中物體的邊界,在圖像分割、目標檢測等領域有著廣泛的應用。
import cv2
import numpy as npimage = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 定義結構元素,這里使用 5x5 的全 1 矩陣
kernel = np.ones((5, 5), np.uint8)
# 進行膨脹操作
dilated_image = cv2.dilate(image, kernel, iterations=1)
# 進行腐蝕操作
eroded_image = cv2.erode(image, kernel, iterations=1)
# 計算形態學梯度,即膨脹圖像減去腐蝕圖像
gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel)
# 也可以手動計算形態學梯度
manual_gradient = cv2.subtract(dilated_image, eroded_image)# 顯示原始圖像
cv2.imshow('Original Image', image)
# 顯示通過 cv2.morphologyEx 計算得到的形態學梯度圖像
cv2.imshow('Morphological Gradient (cv2.morphologyEx)', gradient)
# 顯示手動計算得到的形態學梯度圖像
cv2.imshow('Morphological Gradient (Manual)', manual_gradient)# 等待用戶按鍵
cv2.waitKey(0)
# 關閉所有窗口
cv2.destroyAllWindows()
解釋:
- 結構元素定義:我們使用
np.ones((5, 5), np.uint8)
定義了一個 5x5 的全 1 矩陣作為結構元素。結構元素的大小和形狀會影響形態學操作的效果,不同的任務可能需要不同的結構元素。 - 膨脹和腐蝕操作:通過
cv2.dilate()
和cv2.erode()
函數分別對圖像進行膨脹和腐蝕操作。膨脹操作會使圖像中的前景區域擴大,而腐蝕操作會使前景區域縮小。 - 形態學梯度計算:
- 使用
cv2.morphologyEx()
:這是 OpenCV 提供的用于進行復雜形態學操作的函數,cv2.MORPH_GRADIENT
表示計算形態學梯度。 - 手動計算:通過
cv2.subtract()
函數將膨脹后的圖像減去腐蝕后的圖像,也能得到形態學梯度。這兩種方法的結果是相同的,但使用cv2.morphologyEx()
更簡潔。
- 使用
- 圖像顯示:使用
cv2.imshow()
函數分別顯示原始圖像、通過cv2.morphologyEx
計算得到的形態學梯度圖像以及手動計算得到的形態學梯度圖像,方便我們對比和觀察形態學梯度的效果。
通過形態學梯度,我們可以清晰地看到圖像中物體的邊緣信息,這對于后續的圖像處理和分析非常有幫助。例如,在目標檢測中,我們可以利用形態學梯度來初步定位物體的邊界,然后再進行更精確的檢測和識別。
五、OpenCV 的特征提取與匹配
(一)ORB 特征提取
ORB(Oriented FAST and Rotated BRIEF)是一種快速的特征提取和描述算法。它結合了 FAST(Features from Accelerated Segment Test)特征點檢測和 BRIEF(Binary Robust Independent Elementary Features)描述符,并且對其進行了改進,使其具有旋轉不變性。
import cv2image = cv2.imread('example.jpg')
# 創建 ORB 對象
orb = cv2.ORB_create()
# 檢測特征點并計算描述符
keypoints, descriptors = orb.detectAndCompute(image, None)
# 在圖像上繪制特征點
image_with_keypoints = cv2.drawKeypoints(image, keypoints, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('ORB Keypoints', image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:首先使用 cv2.ORB_create()
創建一個 ORB 對象。detectAndCompute()
方法用于檢測圖像中的特征點并計算對應的描述符。特征點是圖像中具有獨特特征的點,描述符則是對這些特征點的一種量化表示,用于后續的特征匹配。cv2.drawKeypoints()
函數將檢測到的特征點繪制在原始圖像上,方便我們直觀地看到特征點的位置。
(二)SIFT 特征提取
SIFT(尺度不變特征變換)是一種具有尺度、旋轉和光照不變性的特征提取算法,但由于專利問題,在使用時需要安裝 opencv - contrib - python
庫。SIFT 算法通過在不同尺度空間上查找極值點來檢測特征點,并計算其主方向和描述符。
import cv2image = cv2.imread('example.jpg')
# 創建 SIFT 對象
sift = cv2.SIFT_create()
# 檢測特征點并計算描述符
keypoints, descriptors = sift.detectAndCompute(image, None)
# 在圖像上繪制特征點
image_with_keypoints = cv2.drawKeypoints(image, keypoints, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('SIFT Keypoints', image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:cv2.SIFT_create()
用于創建一個 SIFT 對象。與 ORB 類似,detectAndCompute()
方法檢測特征點并計算描述符。SIFT 算法對圖像的尺度、旋轉和光照變化具有較好的魯棒性,因此在很多場景下都能得到較好的特征提取效果。最后使用 cv2.drawKeypoints()
函數將特征點繪制在圖像上進行可視化。
(三)特征匹配
特征匹配是計算機視覺中一個重要的任務,用于在不同圖像中找到對應的特征點。這里將分別介紹使用 ORB 特征和 SIFT 特征進行匹配的方法。
1. ORB 特征匹配
使用 cv2.BFMatcher()
進行 ORB 特征匹配。
import cv2image1 = cv2.imread('image1.jpg')
image2 = cv2.imread('image2.jpg')orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(image1, None)
kp2, des2 = orb.detectAndCompute(image2, None)# 創建 Brute - Force 匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 匹配描述符
matches = bf.match(des1, des2)
# 按照距離排序
matches = sorted(matches, key=lambda x: x.distance)
# 繪制前 10 個匹配點
matching_result = cv2.drawMatches(image1, kp1, image2, kp2, matches[:10], None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('ORB Feature Matching', matching_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:首先分別對兩張圖像使用 ORB 算法檢測特征點并計算描述符。cv2.BFMatcher()
創建一個暴力匹配器,cv2.NORM_HAMMING
表示使用漢明距離來衡量描述符之間的相似度,crossCheck = True
表示只保留那些相互匹配的特征點對。bf.match()
方法進行特征匹配,返回匹配結果。將匹配結果按照距離排序,距離越小表示匹配度越高。最后使用 cv2.drawMatches()
函數繪制前 10 個匹配點,方便我們觀察匹配效果。
2. SIFT 特征匹配
對于 SIFT 特征,可以使用 FLANN(快速最近鄰近似庫)進行匹配。
import cv2
import numpy as npimage1 = cv2.imread('image1.jpg')
image2 = cv2.imread('image2.jpg')sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(image1, None)
kp2, des2 = sift.detectAndCompute(image2, None)# FLANN 參數設置
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)# 創建 FLANN 匹配器
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 匹配描述符
matches = flann.knnMatch(des1, des2, k=2)# 應用比率測試
good_matches = []
for m, n in matches:if m.distance < 0.7 * n.distance:good_matches.append(m)# 繪制匹配點
matching_result = cv2.drawMatches(image1, kp1, image2, kp2, good_matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('SIFT Feature Matching', matching_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
解釋:同樣先對兩張圖像使用 SIFT 算法檢測特征點并計算描述符。FLANN 是一種快速的近似最近鄰搜索算法,適合處理大規模的特征匹配問題。index_params
和 search_params
分別設置 FLANN 的索引參數和搜索參數。flann.knnMatch()
方法返回每個特征點的 k 個最近鄰匹配結果。為了提高匹配的準確性,使用比率測試,即當第一個匹配的距離小于第二個匹配距離的 0.7 倍時,才認為這個匹配是有效的。最后使用 cv2.drawMatches()
函數繪制有效的匹配點。
后面的區域~以后的文章再來探索吧