【问题标题】:OpenCV fails to match template with image(matchTemplate)OpenCV 无法将模板与图像匹配(matchTemplate)
【发布时间】:2018-06-15 02:02:08
【问题描述】:

所以我有一张图片

还有一个模板

我想在图像中找到模板图像,但我的代码没有找到任何东西。我尝试缩小尺寸,但仍然没有检测到。请帮我举个例子:

import cv2
import imutils
import glob, os
import numpy as np

image = cv2.imread("mainimage.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
h, w = gray.shape[:2]
for file in glob.glob("template.png"):
    template = cv2.imread(file)
    template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
    found = None
    (tH, tW) = template.shape[:2]
    cv2.imshow("Template", template)

    for scale in np.linspace(1, 0.2, 20)[::-1]:
        resized = imutils.resize(gray, width=int(gray.shape[1] * scale))
        r = gray.shape[1] / float(resized.shape[1])

        if resized.shape[0] < tH or resized.shape[1] < tW:
            break
        edged = cv2.Canny(resized, 50, 200)
        result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
        (_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)

        if found is None or maxVal > found[0]:
            found = (maxVal, maxLoc, r)

    (_, maxLoc, r) = found
    (startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
    (endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))
    cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)
    cv2.imshow("Image", image)
    cv2.waitKey(0)

【问题讨论】:

  • 可能是您的模板太大(在您加载的文件中太大)。对于模板匹配,模板的大小和旋转必须非常接近图像中的内容。 Keypoint matching 适用于您的模板可能具有不同大小和旋转的情况。
  • 我尝试了关键点匹配但我遇到了一些问题,首先我需要检测到的对象的 x,y 无法在关键点匹配中获得,并且在很多情况下它有很多错误检测.@bfris
  • @AliSH 看看 bfris 的回答。我不知道你是怎么觉得关键点匹配不好定位模板的(x,y)的。查看 bfris 提供的代码。该代码展示了如何在图像中获取模板的位置。

标签: python-3.x opencv computer-vision matchtemplate


【解决方案1】:

您的代码大部分都很好。在您发布的代码中,您以错误的方式进行缩放。您正在缩小主图像而不是增长它。此外,您需要对模板和图像进行 Canny。

在您发布的图像中,模板 (160x160) 大于主图像中的区域 (88x88)。如果你缩放主图像,那么比例因子应该是 1.818。缩放模板可能会快得多。

import cv2
# import imutils
import glob, os
import numpy as np

image = cv2.imread("mainimage.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
h, w = gray.shape[:2]
for file in glob.glob("template.png"):
    template = cv2.imread(file)
    template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
    found = None
    (tH, tW) = template.shape[:2]
    # cv2.imshow("Template", template)

    tEdged = cv2.Canny(template, 50, 200)

    for scale in np.linspace(1, 2, 20):
        # resized = imutils.resize(gray, width=int(gray.shape[1] * scale))
        resized = cv2.resize(gray, dsize = (0,0), fx = scale, fy = scale)

        r = gray.shape[1] / float(resized.shape[1])

        if resized.shape[0] < tH or resized.shape[1] < tW:
            break
        edged = cv2.Canny(resized, 50, 200)
        result = cv2.matchTemplate(edged, tEdged, cv2.TM_CCOEFF)
        (_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)

        if found is None or maxVal > found[0]:
            found = (maxVal, maxLoc, r)

    (_, maxLoc, r) = found
    (startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
    (endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))
    cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)

    # cv2.imshow("Image", image)
    cv2.imwrite('output.jpg', image)
    # ~ cv2.waitKey(0)

在我的电脑上,这段代码需要 6 秒才能运行。

关键点匹配 + 单应性

作为替代方案,关键点匹配 + 单应性对比例不敏感。在以下代码中,dst 保存包含找到模板的边界框的点。对我来说,以下代码在 0.06 秒内执行:

import cv2
# import imutils
import glob, os
import numpy as np
import time

image = cv2.imread("mainimage.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
h, w = gray.shape[:2]

MIN_MATCH_COUNT = 3

start_time = time.time()

for file in glob.glob("template.png"):
    template = cv2.imread(file, 0)

    patchSize = 16

    orb = cv2.ORB_create(edgeThreshold = patchSize, 
                            patchSize = patchSize)
    kp1, des1 = orb.detectAndCompute(template, None)
    kp2, des2 = orb.detectAndCompute(gray, None)

    FLANN_INDEX_LSH = 6
    index_params= dict(algorithm = FLANN_INDEX_LSH,
               table_number = 6,
               key_size = 12,    
               multi_probe_level = 1)
    search_params = dict(checks = 50)

    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1,des2,k=2)
    # store all the good matches as per Lowe's ratio test.
    good = []

    for pair in matches:
        if len(pair) == 2:
            if pair[0].distance < 0.7*pair[1].distance:
                good.append(pair[0])

    print('len(good) ', len(good))
    print('match %03d, min_match %03d, kp %03d' % (len(good), MIN_MATCH_COUNT, len(kp1)))
    if len(good)>MIN_MATCH_COUNT:
        src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
        dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
        matchesMask = mask.ravel().tolist()
        h,w = template.shape
        pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
        dst = cv2.perspectiveTransform(pts,M)

        # dst contains points of bounding box of template in image. 
        # draw a close polyline around the found template:
        image = cv2.polylines(image,[np.int32(dst)], 
                              isClosed = True,
                              color = (0,255,0),
                              thickness = 3, 
                              linetype = cv2.LINE_AA)                    
    else:
        print( "Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT) )
        matchesMask = None

    draw_params = dict(matchColor = (0,255,0), # draw matches in green color
               singlePointColor = None,
               matchesMask = matchesMask, # draw only inliers
               flags = 2)

    if len(good)>MIN_MATCH_COUNT:
        output2 = cv2.drawMatches(template,kp1,gray,kp2,good,None,**draw_params)

    print('elapsed time ', time.time()-start_time)
    # cv2.imshow("Image", image)
    cv2.imwrite('output_homography.jpg', image)
    cv2.imwrite('output2.jpg', output2)

来自 cv2.drawMatches 函数的输出 2

关键点检测的一个重要参数是patchSize。在代码中,我们将patchSize = 16 用于图像和模板。随着您使 patchSize 更小,您将获得更多关键点。你可以去的最小的是2。但是当你变得太小时,你开始得到不好的匹配。我不确定如何找到最佳位置。

【讨论】:

  • 因为 OP 认为关键点匹配不好找到模板的位置,我想在你的代码中添加,dst 是图像中的模板位置。请在您的回答中提及这一点
  • @KadiSoheib,感谢您的反馈。我更新了答案和代码示例以包含更多解释。
  • @bfris 哇,你的代码很好用。但我想说三件事。1:主图像中有一些其他徽标。总共 21 个,关键点匹配不适用于其他 20 个图像。根本找不到任何匹配的关键点..该模板是唯一适用于关键点匹配的模板。如果我提供其他徽标。你能帮我进行关键点匹配吗?2:在 cv2.polylines() 我收到错误@987654326 @(opencv3,python3).3:无论如何提高模板匹配速度?另外,我可以给你更多的帮助而不是简单地投票吗?
  • @AliSH 我已经更新了答案以对 patchSize 参数进行更多讨论。当我尝试从您的示例图像中进行关键点匹配时,我也遇到了一些困难。示例图像是 JPG,并且有许多影响该过程的压缩伪影。如果你有一个干净的PNG屏幕帽,你可能会得到更好的结果。同样在 OP 中,您的模板是干净的 PNG,没有压缩伪影。
猜你喜欢
  • 2014-02-26
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
  • 2017-10-19
  • 1970-01-01
  • 2014-12-18
  • 2016-08-29
相关资源
最近更新 更多