【问题标题】:OpenCV match multiple frames on imageOpenCV 匹配图像上的多个帧
【发布时间】:2020-07-23 06:34:59
【问题描述】:

我是 OpenCV 的新手,我想找到一种解决方案,在某个图像上找到多个带有文本的图像。将来我需要那些物品来获得认可。

首先,我有一帧图像用于搜索模板。它看起来像带有透明中心的框架。 我尝试了很多样本​​来匹配模板,但它们只给出一个搜索结果:只找到第一个或第二个项目,但我需要所有这些。

请帮助我找到解决问题的方法。

框架模板:

场景:

代码:

import cv2
import numpy as np

method = cv2.TM_CCOEFF_NORMED
threshold = 0.90

img_main = cv2.imread('images/garden.jpg')
template = cv2.imread('images/frame_trans.png', cv2.IMREAD_GRAYSCALE)
template_gray = template

img_main_gray = cv2.cvtColor(img_main, cv2.COLOR_BGR2GRAY)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_main_gray, template_gray, method)

cv2.normalize(res, res, 0., 1., cv2.NORM_MINMAX)
cv2.threshold(res, threshold, 1, cv2.THRESH_TOZERO)

i = 0
while i < 100:
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc

    if max_val > threshold:
        print(top_left)
        bottom_right = (top_left[0] + w, top_left[1] + h)
        cv2.rectangle(img_main, top_left, bottom_right, (0, 0, 255), 2)
        cv2.floodFill(img_main_gray, None, top_left, 0, 0.1, 1.0)
    else:
        break
    i += 1

cv2.imwrite('sample6_output.png', img_main)
cv2.imshow('sample6', img_main)
cv2.waitKey()

脚本的结果在这里...

PyDev console: starting.
Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32
runfile('D:/MyProjects/PyHeroRecognition/sample6.py', wdir='D:/MyProjects/PyHeroRecognition')
(71, 45)
(71, 45)
(71, 45)
(71, 45)
(71, 45)
(71, 45)
(71, 45)
(71, 45)
(71, 45)
(71, 45)

结果图片:

【问题讨论】:

  • 我看过这个例子,但它也没有帮助我。它匹配填充的模板,并且它们按照描述的方式工作。但我不能将透明框架作为模板运行。
  • 你可以用蒙版做透明度。请参阅 matchTemplate 文档。
  • 是的,我想这是一个很好的解决方案,你能给我看看这个想法的样本吗?如何创建面具?我在 matchTemplate 中找不到如何使用掩码。文档没有真正的信息,只是对参数的描述。
  • 蒙版只是您的模板 Alpha 通道。分离 RGB 图像和 alpha 通道。与RGB通道图像做模板匹配,并使用分离的alpha通道作为掩码。

标签: python opencv opencv3.0


【解决方案1】:

对于模板匹配算法,只要找到相似度的最大值,就应该将创建的像素设置为零,如果不这样做,就像在每次迭代中通过cv2.minMaxLoc函数找到相同的像素一样。

您可能会遇到需要将最大像素周围的小区域设置为零以获得最佳效果的情况。

我为你的问题写了一个简单的代码,但是在这种情况下,模板匹配似乎不是很好

import cv2
import numpy as np

method = cv2.TM_CCORR_NORMED
threshold = 0.7


img_main = cv2.imread('images/garden.jpg')
template = cv2.imread('images/frame_trans.png', cv2.IMREAD_GRAYSCALE)
template_gray = template

img_main_gray = cv2.cvtColor(img_main, cv2.COLOR_BGR2GRAY)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_main_gray, template_gray, method)

cv2.normalize(res, res, 0., 1., cv2.NORM_MINMAX)
cv2.threshold(res, threshold, 1, cv2.THRESH_TOZERO)

i = 0

border=45  # I have added this line to control the area that must be zero
while i < 20:
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    print(max_val)
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc

    if max_val > threshold:
#         print(top_left)
        bottom_right = (top_left[0] + w, top_left[1] + h)
#         cv2.circle(img_main,max_loc,5,(0,0,255),1)
        cv2.rectangle(img_main, top_left, bottom_right, (0, 0, 255), 5)
        cv2.floodFill(img_main_gray, None, top_left, 0, 0.1, 1.0)
    i += 1
    res[max_loc[1]-border:max_loc[1]+border,max_loc[0]-border:max_loc[0]+border]=0  # set zero the max loc

img_main=cv2.cvtColor(img_main,cv2.COLOR_BGR2RGB)
import matplotlib.pyplot as plt
plt.figure(figsize=(10,12))
plt.imshow(res)
plt.figure(figsize=(10,12))
plt.imshow(img_main)

【讨论】:

  • 我尝试在场景中使用floodFill,就像在opencv示例中一样,但它不起作用
  • 您正试图从res 中找到最佳匹配,并且在while 循环之前计算res,因此在不更新res 的情况下更改图像不会影响查找矩形
  • 是的,在应用floodFill 之后没有任何反应。你让我以某种方式在 while 循环中重新计算 res,对吧?我想在主图像上用黑色填充矩形,然后在循环中再次调用matchTemplate
  • 不,这种方式可能会得到你想要的,但它很耗时,从计算角度来看你不应该使用它,因为在match template你正在计算所有可能的相似性,我不知道你经历了多少,但你可以绘制res,你可以看到你已经计算了每个像素的相似度,所以在其他方面你可以将它解释为在res中寻找前10或前100,所以你不需要改变图像,但你必须改变res
  • 欲了解更多信息,请查看我在另一个问题中的回答stackoverflow.com/questions/59485106/…
【解决方案2】:

这里是如何在 Python/OpenCV 中使用透明模板图像进行模板匹配。很抱歉使用 Imagemagick 图像,但我已经有那个例子了。

输入:

透明模板:

import cv2
import numpy as np

# read image
img = cv2.imread('logo.png')

# read template with alpha
tmplt = cv2.imread('hat_alpha.png', cv2.IMREAD_UNCHANGED)
hh, ww = tmplt.shape[:2]

# extract template mask as grayscale from alpha channel and make 3 channels
tmplt_mask = tmplt[:,:,3]
tmplt_mask = cv2.merge([tmplt_mask,tmplt_mask,tmplt_mask])

# extract templt2 without alpha channel from tmplt
tmplt2 = tmplt[:,:,0:3]

# do template matching
corrimg = cv2.matchTemplate(img,tmplt2,cv2.TM_CCORR_NORMED, mask=tmplt_mask)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(corrimg)
max_val_ncc = '{:.3f}'.format(max_val)
print("correlation match score: " + max_val_ncc)
xx = max_loc[0]
yy = max_loc[1]
print('xmatch =',xx,'ymatch =',yy)

# draw red bounding box to define match location
result = img.copy()
pt1 = (xx,yy)
pt2 = (xx+ww, yy+hh)
cv2.rectangle(result, pt1, pt2, (0,0,255), 1)

cv2.imshow('image', img)
cv2.imshow('template2', tmplt2)
cv2.imshow('template_mask', tmplt_mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save results
cv2.imwrite('logo_hat_match2.png', result)


结果显示匹配位置的边界框:

【讨论】:

    【解决方案3】:

    @fmw42 非常感谢您的想法!我已经越过了你的代码和我的代码,但我只有一个结果(见下文)。 我的下一个问题:如何捕获少量结果?

    import cv2
    import numpy as np
    
    method = cv2.TM_CCORR_NORMED
    threshold = 0.90
    
    # read scene image
    main_img = cv2.imread('images/garden.jpg')
    
    # read template with alpha
    template = cv2.imread('images/frame_trans.png', cv2.IMREAD_UNCHANGED)
    h, w = template.shape[:2]
    
    # extract template mask as grayscale from alpha channel and make 3 channels
    tmplt_mask = template[:, :, 3]
    tmplt_mask = cv2.merge([tmplt_mask, tmplt_mask, tmplt_mask])
    
    # extract templt2 without alpha channel from tmplt
    tmplt2 = template[:, :, 0:3]
    
    res = cv2.matchTemplate(main_img, tmplt2, method, mask=tmplt_mask)
    
    output_img = main_img.copy()
    
    i = 0
    while i < 100:
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
            top_left = min_loc
        else:
            top_left = max_loc
    
        if max_val > threshold:
            print("%s: %s" % (max_val, top_left))
            bottom_right = (top_left[0] + w, top_left[1] + h)
            cv2.rectangle(output_img, top_left, bottom_right, (0, 0, 255), 2)
            cv2.floodFill(res, None, top_left, 0, 0.1, 1.0)
        else:
            break
        i += 1
    
    cv2.imwrite('sample8_output.png', output_img)
    cv2.imshow('sample8', output_img)
    cv2.waitKey()
    
    
    

    控制台输出:

    PyDev console: starting.
    Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32
    runfile('D:/MyProjects/PyHeroRecognition/sample8_alpha.py', wdir='D:/MyProjects/PyHeroRecognition')
    0.9918215870857239: (71, 45)
    >>>
    

    结果图像输出

    【讨论】:

    • 我的代码只搜索了最佳匹配。您必须在 if 条件下的 while 循环中使用不同的输出名称编写输出。在 while 循环中将计数器置于您的条件中。然后使用类似cv2.imwrite("result_{0}.png".format(i), output_img)
    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 2014-04-11
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 2011-12-13
    相关资源
    最近更新 更多