Posted on

使用模板匹配查找圖像中的對象

模板匹配

參考此篇教學: https://docs.opencv.org/4.x/d4/dc6/tutorial_py_template_matching.html
使用範例如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
img2 = img.copy()
template = cv.imread('template.jpg',0)
w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
            'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
for meth in methods:
    img = img2.copy()
    method = eval(meth)
    # Apply template Matching
    res = cv.matchTemplate(img,template,method)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv.rectangle(img,top_left, bottom_right, 255, 2)
    plt.subplot(121),plt.imshow(res,cmap = 'gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img,cmap = 'gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

使用cv.matchTemplate(), cv.minMaxLoc()與方式,當模板在圖片中被縮放或旋轉後,匹配成效不佳。
但實際應用中,物件在3D範圍內很常會被縮放或旋轉,就無法使用上述模板匹配方式

改良方法

嘗試Features2DFramework 中的 openCV 函數。例如SIFT或SURF描述符,以及FLANN匹配器。另外,您將需要findHomography方法。
這是在場景中查找旋轉對象的一個很好的例子。

簡而言之,算法是這樣的:

  • 尋找目標圖像的關鍵點(Keypoints)
  • 從這些關鍵點(Keypoints)中提取描述符(des)
  • 尋找場景圖像的關鍵點
  • 從關鍵點提取描述符
  • 通過匹配器匹配描述符
  • 分析圖片內容尋找目標圖像

有不同類別的 FeatureDetectors、DescriptorExtractors 和 DescriptorMatches,選擇適合的任務的那些。
以下為提取關鍵點的一個範例

from __future__ import print_function
import cv2
import numpy as np
import argparse
print(cv2.__version__)
img = cv2.imread('./D10.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

sift = cv2.SIFT_create()

kp = sift.detect(gray, None)


ret = cv2.drawKeypoints(gray, kp, img)
cv2.imshow('ret', ret)
cv2.waitKey(0)
cv2.destroyAllWindows()

kp, des = sift.compute(gray, kp)

print(np.shape(kp))
print(np.shape(des))

print(des[0])

更多資訊