簡介
計算機視覺第一課opencv(四)保姆級教學
之前說過模糊匹配只是對于單個目標進行匹配,今天我們就來學習一下如何對多個目標進行匹配
一、多目標匹配
????????對于這個圖片我們要匹配下面那個箭頭,我們可以發現圖中是有兩個位置相同的箭頭,之前我們說的模糊匹配是尋找匹配值最大的,那兩個怎么尋找呢?
1.基本步驟
1.圖像準備
????????模板圖像:需要被匹配的目標圖像,通常是一個較小的圖像塊。
????????輸入圖像:在其中進行搜索以找到與模板圖像相似的多個區域的圖像。
2.圖像預處理
????????轉換為灰度圖像:在進行模板匹配之前,通常需要將輸入圖像和模板圖像轉換為灰度圖像,因為灰度圖像中的像素值僅表示亮度,不受顏色影響,更適合進行匹配。
????????降噪和增強:根據需要,可以對圖像進行降噪處理以提高匹配準確性,或進行增強處理以突出目標特征。
3.執行模板匹配
????????使用模板匹配算法(如OpenCV中的cv2.matchTemplate()函數)在輸入圖像中搜索與模板圖像相似的區域。
模板匹配算法會生成一個結果圖像,其中每個像素的值表示該位置與模板圖像的匹配程度。
4.定位匹配區域
????????使用cv2.minMaxLoc()等函數在結果圖像中找到匹配度最高的區域(或多個區域,如果設置了適當的閾值)。
根據匹配位置在原圖中繪制矩形框或其他標記,以指示匹配到的目標。
5.處理多個匹配
????????如果需要匹配多個目標,并且這些目標在圖像中可能以不同的尺寸、方向或旋轉角度出現,則可能需要使用更復雜的算法,如尺度不變特征變換(SIFT)、加速穩健特征(SURF)或ORB等。
????????對于簡單的多目標匹配,可以通過設置較低的匹配閾值來找到多個匹配區域,并分別處理它們。
6.優化和驗證
????????根據需要調整模板匹配算法的參數(如匹配方法、閾值等),以優化匹配結果。
????????對匹配結果進行驗證,確保它們確實是所需的目標,并排除誤匹配。
# 導入必要的庫:cv2用于圖像處理,numpy用于數值計算
import cv2
import numpy as np# 讀取原始彩色圖像(默認讀取為BGR格式,而非RGB)
img_rgb = cv2.imread('beijing.jpg')
# 將彩色圖像轉為灰度圖:模板匹配通常在單通道灰度圖上進行,減少計算量和干擾
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
# 讀取模板圖像:flags=0表示以灰度模式讀取(直接得到單通道圖像)
template = cv2.imread('jiantou.jpg', flags=0)# 獲取模板的高和寬:shape返回(高, 寬, 通道數),[:2]取前兩個值(高h和寬w)
h, w = template.shape[:2]# 執行模板匹配:在灰度圖上滑動模板,計算每個位置的匹配度
# 參數說明:
# - img_gray:待匹配的灰度圖像(大圖像)
# - template:模板圖像(小圖像)
# - cv2.TM_CCOEFF_NORMED:匹配方法(歸一化相關系數匹配)
# 返回值res:是一個矩陣,每個元素表示模板在對應位置的匹配度(范圍[-1,1],1為完美匹配)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)# 設定匹配閾值:只有匹配度≥0.9的區域才被認為是有效匹配(過濾低匹配度的干擾)
threshold = 0.9# 獲取所有符合閾值的匹配點坐標:
# np.where(res >= threshold)返回滿足條件的索引,格式為(行坐標數組, 列坐標數組)
# 例如:(array([5, 10]), array([3, 7]))表示有兩個匹配點,坐標為(5,3)和(10,7)
loc = np.where(res >= threshold)# 遍歷所有匹配點,在原圖上繪制矩形框標記
# zip(*loc[::-1])的作用:將坐標從(行,列)轉為(列,行)(OpenCV中坐標是(x,y)即列在前,行在后)
for pt in zip(*loc[::-1]):# 繪制矩形:# - img_rgb:要繪制的圖像(原始彩色圖,方便直觀查看)# - pt:矩形左上角坐標(x,y)# - (pt[0]+w, pt[1]+h):矩形右下角坐標(左上角x+模板寬,左上角y+模板高)# - color=(0,0,255):矩形顏色(BGR格式,這里是紅色)# - thickness=1:矩形線寬cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), color=(0, 0, 255), thickness=1)# 顯示標記后的圖像:第一個參數是窗口名稱(空字符串表示默認窗口),第二個參數是圖像
cv2.imshow('', img_rgb)
# 等待用戶按鍵輸入:0表示無限等待(直到按下任意鍵關閉窗口)
cv2.waitKey(0)
局限性:
????????只能匹配與模板方向、大小完全一致的目標。如果目標在圖像中旋轉了(比如箭頭方向變了),則無法檢測到。那我們就繼續探索一下如何去匹配旋轉的目標
二、圖像旋轉
????????為了解決上述局限性,需要先掌握如何旋轉圖像。這部分提供了兩種旋轉方法,用于后續生成不同角度的模板。
import cv2
import numpy as np# 方法一:使用numpy的rot90函數旋轉(按90度倍數旋轉)
img = cv2.imread('../kele.png') # 讀取圖像(以彩色模式)
# np.rot90參數說明:
# - 第一個參數:要旋轉的圖像
# - k:旋轉次數(每次90度),k=1表示逆時針轉90度,k=-1(或3)表示順時針轉90度
rotated_image1 = np.rot90(img, k=-1) # 順時針旋轉90度
rotated_image2 = np.rot90(img, k=1) # 逆時針旋轉90度# 顯示原圖和旋轉后的圖像
cv2.imshow('yuantu', img) # 原圖窗口
cv2.imshow('rotated_image1', rotated_image1) # 順時針90度窗口
cv2.imshow('rotated_image2', rotated_image2) # 逆時針90度窗口
cv2.waitKey(0) # 等待按鍵
cv2.destroyAllWindows() # 關閉所有窗口,釋放資源# 方法二:使用OpenCV的rotate函數旋轉(更直觀,支持固定角度)
rotated_image = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # 順時針90度
rotated_image1 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) # 逆時針90度
rotated_image2 = cv2.rotate(img, cv2.ROTATE_180) # 旋轉180度# 顯示旋轉結果
cv2.imshow('shun90', rotated_image) # 順時針90度窗口
cv2.imshow('ni90', rotated_image1) # 逆時針90度窗口
cv2.imshow('180', rotated_image2) # 180度窗口
cv2.waitKey(0) # 等待按鍵
兩種方法對比:
np.rot90
:通過旋轉次數控制(k=1/2/3/-1),適合 90 度倍數的旋轉,但不夠直觀。cv2.rotate
:直接通過枚舉值指定旋轉方向(如ROTATE_90_CLOCKWISE
),可讀性更強,推薦使用。
三、支持旋轉角度的模板匹配
結合多目標匹配與旋轉的知識,我們就可以結合一下實現對旋轉角度的模板匹配
import cv2
import numpy as np# 讀取原始圖像和模板
img_rgb = cv2.imread('beijing.jpg') # 原始彩色圖像
template = cv2.imread('jiantou.jpg', 0) # 模板圖像(以灰度模式讀取)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) # 原始圖像轉灰度# 方法二(cv2.rotate)生成不同角度的模板(方法一被注釋,原理相同)
template_rot90_clockwise_cv = cv2.rotate(template, cv2.ROTATE_90_CLOCKWISE) # 順時針90度
template_rot90_counterclockwise_cv = cv2.rotate(template, cv2.ROTATE_90_COUNTERCLOCKWISE) # 逆時針90度
template_rot180_cv = cv2.rotate(template, cv2.ROTATE_180) # 180度# 定義模板列表:包含原始模板和所有旋轉后的模板(需要檢測的角度)
templates = [template, # 原始模板(0度)template_rot90_clockwise_cv, # 順時針90度template_rot90_counterclockwise_cv, # 逆時針90度template_rot180_cv # 180度
]# 設定匹配閾值:從0.9降低到0.8
# 原因:旋轉后的模板與目標的匹配度可能略低(邊緣、細節可能有偏差),降低閾值避免漏檢
threshold = 0.8# 遍歷每個模板,分別進行匹配
for temp in templates:h, w = temp.shape[:2] # 獲取當前模板的高和寬(不同旋轉角度的模板尺寸可能變化)# 對當前模板執行匹配res = cv2.matchTemplate(img_gray, temp, cv2.TM_CCOEFF_NORMED)# 獲取符合閾值的匹配點坐標loc = np.where(res >= threshold)# 遍歷匹配點,繪制矩形框for pt in zip(*loc[::-1]):cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 1)# 顯示最終匹配結果
cv2.imshow('Result', img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows() # 關閉窗口,釋放資源
核心邏輯:
通過生成模板的多個旋轉版本(0°、90° 順時針、90° 逆時針、180°),分別與原始圖像匹配,從而覆蓋目標可能的旋轉角度。這樣即使目標在圖像中旋轉了,也能被檢測到。