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