深入剖析 OpenCV:全面掌握基礎操作、圖像處理算法與特征匹配

深入剖析 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 基礎操作

(一)圖像的讀取、顯示與保存

  1. 讀取圖像
    使用 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 等支持透明度的圖像格式。

  1. 顯示圖像
    通過 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 創建的窗口,釋放資源。

  1. 保存圖像
    利用 cv2.imwrite() 函數保存圖像,第一個參數為保存路徑,第二個參數是要保存的圖像。
# 保存灰度圖像
cv2.imwrite('saved_gray_image.jpg', gray_image)

解釋:cv2.imwrite() 函數將指定的圖像保存到指定的文件路徑。保存的文件格式由文件擴展名決定,如 .jpg.png 等。

(二)圖像的基本屬性與操作

  1. 圖像的基本屬性
    圖像在 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 位無符號整數)。

  1. 圖像的像素訪問
    可以直接通過索引訪問和修改圖像的像素值。
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(藍、綠、紅)順序存儲的。

  1. 圖像的裁剪、縮放與旋轉
  • 裁剪
    通過指定行和列的范圍來裁剪圖像。
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() 函數提供了靈活的縮放方式。fxfy 參數用于指定水平和垂直方向的縮放比例,當第二個參數為 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 的圖像處理算法

(一)圖像濾波

  1. 均值濾波
    使用 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))在圖像上滑動,計算每個核內像素的平均值,并將該平均值作為中心像素的新值,從而達到平滑圖像的效果。

  1. 高斯濾波
    利用 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()

解釋:高斯濾波是一種非線性濾波方法,它根據高斯函數對核內的像素進行加權平均。相比于均值濾波,高斯濾波在抑制噪聲的同時能更好地保留圖像的邊緣信息,因為它對不同位置的像素賦予了不同的權重。

  1. 中值濾波
    通過 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()

解釋:中值濾波是一種非線性濾波方法,它將核內的像素值進行排序,然后用中值替換中心像素的值。這種方法對于去除椒鹽噪聲(圖像中出現的黑白孤立點)非常有效。

  1. 雙邊濾波
    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()

解釋:雙邊濾波是一種保邊濾波方法,它結合了空間域和值域的信息。在平滑圖像時,它不僅考慮像素的空間距離,還考慮像素的顏色差異,因此能夠在平滑圖像的同時很好地保留邊緣和細節信息。

(二)邊緣檢測

  1. 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 邊緣檢測是一種多階段的邊緣檢測算法,主要包括高斯平滑、梯度計算、非極大值抑制和雙閾值處理等步驟。高低閾值參數用于控制邊緣的檢測范圍,只有當梯度值大于高閾值時才被確定為邊緣,介于高低閾值之間的像素如果與確定的邊緣相連也會被保留。

  1. 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 方向上的梯度。通過分別計算兩個方向的梯度,可以檢測出圖像中的水平和垂直邊緣。最后將兩個方向的梯度合并,得到完整的邊緣信息。

  1. 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 位無符號整數才能正確顯示邊緣圖像。

(三)形態學操作

  1. 膨脹與腐蝕
    膨脹操作可以擴大圖像中的前景區域,腐蝕操作則可以縮小前景區域。
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 矩陣)對圖像進行處理。膨脹操作將結構元素在圖像上滑動,如果結構元素與前景區域有重疊,則將中心像素置為前景;腐蝕操作則相反,如果結構元素完全包含在前景區域內,才將中心像素置為前景。

  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()

解釋:開運算和閉運算是基于膨脹和腐蝕操作的組合。開運算可以去除圖像中的小噪聲點,同時保持大的前景區域不變;閉運算則可以填充前景區域內的小空洞,使前景區域更加完整。

  1. 形態學梯度
    形態學梯度是膨脹圖像與腐蝕圖像的差值,用于突出圖像的邊緣。形態學梯度能夠幫助我們檢測圖像中物體的邊界,在圖像分割、目標檢測等領域有著廣泛的應用。
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_paramssearch_params 分別設置 FLANN 的索引參數和搜索參數。flann.knnMatch() 方法返回每個特征點的 k 個最近鄰匹配結果。為了提高匹配的準確性,使用比率測試,即當第一個匹配的距離小于第二個匹配距離的 0.7 倍時,才認為這個匹配是有效的。最后使用 cv2.drawMatches() 函數繪制有效的匹配點。

后面的區域~以后的文章再來探索吧

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/72245.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/72245.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/72245.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DOM HTML:深入理解與高效運用

DOM HTML:深入理解與高效運用 引言 隨著互聯網的飛速發展,前端技術逐漸成為軟件開發中的關鍵部分。DOM(文檔對象模型)和HTML(超文本標記語言)是前端開發中的基石。本文將深入探討DOM和HTML的概念、特性以及在實際開發中的應用,幫助讀者更好地理解和使用這兩項技術。 …

【數據挖掘】Matplotlib

Matplotlib 是 Python 最常用的 數據可視化 庫之一&#xff0c;在數據挖掘過程中&#xff0c;主要用于 數據探索 (EDA)、趨勢分析、模式識別 和 結果展示。 &#x1f4cc; 1. Matplotlib 基礎 1.1 安裝 & 導入 # 如果未安裝 Matplotlib&#xff0c;請先安裝 # pip instal…

DHCP配置實驗

實驗拓撲圖 首先配置server的IP地址和網關 接下來配置R1 undo info-center enable dhcp enable //開啟DHCP服務 ip pool dhcp-pool1 //開始配置dhcp地址池 gateway-list 192.168.1.254 //配置網關 network 192.168.1.0 mask 255.255.255.0 //配置網段和子網掩碼 dns-list …

Linux:ELF文件-靜動態庫原理

??所屬專欄&#xff1a;Linux?? ??作者主頁&#xff1a;嶔某?? ELF文件 什么是編譯&#xff1f;編譯就是將程序源代碼編譯成能讓CPU直接執行的機器代碼 如果我們要編譯一個 .c文件&#xff0c;使用gcc -c將.c文件編譯為二進制文件.o &#xff0c;如果一個項目有多個.…

C++性能優化常用技巧

一. 選擇合適的數據結構 1.1 map與unordered_map的選擇 如果僅僅只需要使用到快速查找的特性&#xff0c;那么unordered_map更加合適&#xff0c;他的復雜度是O(1)。如果還需要排序以及范圍查找的能力&#xff0c;那么就選擇map。 1.2 vector與list的選擇 通常情況下&#…

Towards Graph Foundation Models: A Survey and Beyond

Towards Graph Foundation Models: A Survey and Beyond WWW24 ?#paper/???#? #paper/&#x1f4a1;#? 背景和動機 背景與意義 隨著基礎模型&#xff08;如大語言模型&#xff09;在NLP等領域的突破&#xff0c;圖機器學習正經歷從淺層方法向深度學習的范式轉變。GFM…

基于 Python 深度學習的電影評論情感分析可視化系統(2.0 全新升級)

基于 Python 深度學習的電影評論情感分析可視化系統&#xff0c;基于 Flask 深度學習&#xff0c;構建了一個 影評情感分析系統&#xff0c;能夠 自動分析影評、計算情感趨勢 并 可視化展示&#xff0c;對于電影行業具有重要參考價值&#xff01; 基于 Python 深度學習的電影評…

Cargo, the Rust package manager, is not installed or is not on PATH.

今天在Windows操作系統上通過pip 安裝jupyter的時候遇到這個報錯&#xff0c;Cargo, the Rust package manager, is not installed or is not on PATH.。 解決辦法 官網&#xff1a;https://rustup.rs/# 下載&#xff1a;https://win.rustup.rs/x86_64 安裝完成之后&#xff0c…

CSS—text文本、font字體、列表list、表格table、表單input、下拉菜單select

目錄 1.文本 2.字體 3.列表list a.無序列表 b.有序列表 c.定義列表 4.表格table a.內容 b.合并單元格 3.表單input a.input標簽 b.單選框 c.上傳文件 4.下拉菜單 1.文本 屬性描述color設置文本顏色。direction指定文本的方向 / 書寫方向。letter-spacing設置字符…

開啟AI短劇新紀元!SkyReels-V1/A1雙劍合璧!昆侖萬維開源首個面向AI短劇的視頻生成模型

論文鏈接&#xff1a;https://arxiv.org/abs/2502.10841 項目鏈接&#xff1a;https://skyworkai.github.io/skyreels-a1.github.io/ Demo鏈接&#xff1a;https://www.skyreels.ai/ 開源地址&#xff1a;https://github.com/SkyworkAI/SkyReels-A1 https://github.com/Skywork…

數學建模:MATLAB極限學習機解決回歸問題

一、簡述 極限學習機是一種用于訓練單隱層前饋神經網絡的算法&#xff0c;由輸入層、隱藏層、輸出層組成。 基本原理&#xff1a; 輸入層接受傳入的樣本數據。 在訓練過程中隨機生成從輸入層到隱藏層的所有連接權重以及每個隱藏層神經元的偏置值&#xff0c;這些參數在整個…

Android15音頻進階之定位混音線程丟幀問題(一百零八)

簡介: CSDN博客專家、《Android系統多媒體進階實戰》一書作者 新書發布:《Android系統多媒體進階實戰》?? 優質專欄: Audio工程師進階系列【原創干貨持續更新中……】?? 優質專欄: 多媒體系統工程師系列【原創干貨持續更新中……】?? 優質視頻課程:AAOS車載系統+…

_ 為什么在python中可以當變量名

在 Python 中&#xff0c;_&#xff08;下劃線&#xff09;是一個有效的變量名&#xff0c;這主要源于 Python 的命名規則和一些特殊的使用場景。以下是為什么 _ 可以作為變量名的原因和常見用途&#xff1a; --- ### 1. **Python 的命名規則** Python 允許使用字母&#xff…

Electron+Vite+React+TypeScript開發問題手冊

ElectronViteReactTypeScript跨平臺開發全問題手冊 一、開發環境配置類問題 1.1 依賴安裝卡頓&#xff08;國內網絡環境&#xff09; 問題現象&#xff1a;執行npm install時卡在node-gyp編譯或Electron二進制包下載階段 解決方案&#xff1a; # 配置國內鏡像源 npm config …

【計算機網絡入門】初學計算機網絡(七)

目錄 1. 滑動窗口機制 2. 停止等待協議&#xff08;S-W&#xff09; 2.1 滑動窗口機制 2.2 確認機制 2.3 重傳機制 2.4 為什么要給幀編號 3. 后退N幀協議&#xff08;GBN&#xff09; 3.1 滑動窗口機制 3.2 確認機制 3.3 重傳機制 4. 選擇重傳協議&#xff08;SR&a…

《Python實戰進階》No 8:部署 Flask/Django 應用到云平臺(以Aliyun為例)

第8集&#xff1a;部署 Flask/Django 應用到云平臺&#xff08;以Aliyun為例&#xff09; 2025年3月1日更新 增加了 Ubuntu服務器安裝Python詳細教程鏈接。 引言 在現代 Web 開發中&#xff0c;開發一個功能強大的應用只是第一步。為了讓用戶能夠訪問你的應用&#xff0c;你需…

GitLab Pages 托管靜態網站

文章目錄 新建項目配置博客添加 .gitlab-ci.yml其他配置 曾經用 Github Pages 來托管博客內容&#xff0c;但是有一些不足&#xff1a; 在不科學上網的情況下&#xff0c;是沒法訪問的&#xff0c;或者訪問速度非常慢代碼倉庫必須是公開的&#xff0c;如果設置為私有&#xff0…

TVbox蜂蜜影視:智能電視觀影新選擇,簡潔界面與強大功能兼具

蜂蜜影視是一款基于貓影視開源項目 CatVodTVJarLoader 開發的智能電視軟件&#xff0c;專為追求簡潔與高效觀影體驗的用戶設計。該軟件從零開始編寫&#xff0c;界面清爽&#xff0c;操作流暢&#xff0c;特別適合在智能電視上使用。其最大的亮點在于能夠自動跳過失效的播放地址…

形象生動講解Linux 虛擬化 I/O

用現實生活的比喻和簡單例子來解釋 Linux 虛擬化 I/O&#xff0c;就像給朋友講故事一樣。 虛擬化 I/O 要解決什么問題&#xff1f; 想象你有一棟大房子&#xff08;物理服務器&#xff09;&#xff0c;想把它分割成多個小公寓&#xff08;虛擬機&#xff09;出租。每個租客&…

Java內存管理與性能優化實踐

Java內存管理與性能優化實踐 Java作為一種廣泛使用的編程語言&#xff0c;其內存管理和性能優化是開發者在日常工作中需要深入了解的重要內容。Java的內存管理機制借助于垃圾回收&#xff08;GC&#xff09;來自動處理內存的分配和釋放&#xff0c;但要實現高效的內存管理和優…