gpt4 book ai didi

python-3.x - 模板匹配 : efficient way to create mask for minMaxLoc?

转载 作者:太空宇宙 更新时间:2023-11-03 21:32:03 27 4
gpt4 key购买 nike

OpenCV 中的模板匹配很棒。您可以将掩码传递给 cv2.minMaxLoc,这样您就可以只在部分图像中搜索(某种程度上)所需的模板。您也可以在 matchTemplate 操作中使用掩码,但这只会掩码模板。

我想找到一个模板,并且我想确保这个模板在我的图像的某个其他区域内。

计算 minMaxLoc 的掩码似乎有点繁重。也就是说,计算一个准确 掩码感觉很重。如果您以简单的方式计算掩码,它会忽略模板的大小。

例子是有序的。我的输入图像如下所示。他们有点做作。我想找到糖果棒,但前提是它完全在钟面的白色圆圈内。

时钟1 clock1

时钟2 clock2

模板 template

在时钟 1 中,糖果棒位于圆形钟面内,是“PASS”。但是在 clock2 中,糖果棒只是部分在脸上,我希望它是一个“失败”。这是一个简单的代码示例。我使用 cv.HoughCircles 来查找钟面。

import numpy as np
import cv2

img = cv2.imread('clock1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

template = cv2.imread('template.png')
t_h, t_w = template.shape[0:2] # template height and width

# find circle in gray image using Hough transform
circles = cv2.HoughCircles(gray, method = cv2.HOUGH_GRADIENT, dp = 1,
minDist = 150, param1 = 50, param2 = 70,
minRadius = 131, maxRadius = 200)
i = circles[0,0]
x0 = i[0]
y0 = i[1]
r = i[2]

# display circle on color image
cv2.circle(img,(x0, y0), r,(0,255,0),2)

# do the template match
result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# finally, here is the part that gets tricky. we want to find highest
# rated match inside circle and we'd like to use minMaxLoc

# make mask by drawing circle on zero array
mask = np.zeros(result.shape, dtype = np.uint8) # minMaxLoc will throw
# error w/o np.uint8
cv2.circle(mask, (x0, y0), r, color = 1, thickness = -1)

# call minMaxLoc
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result, mask = mask)

# draw found rectangle on img
if max_val > 0.4: # use 0.4 as threshold for finding candy bar
cv2.rectangle(img, max_loc, (max_loc[0]+t_w, max_loc[1]+t_h), (0,255,0), 4)

cv2.imwrite('output.jpg', img)

使用clock1输出
output from clock1

使用clock2输出甚至找到糖果棒虽然有一部分在圈外 output from clock2

因此,为了正确制作 mask ,我使用了一堆 NumPy 操作。我制作了四个单独的蒙版(一个用于模板边界框的每个角),然后将它们组合在一起。我不知道 OpenCV 中有任何便利功能可以为我做掩码。我有点担心所有的数组操作都会很昂贵。有更好的方法吗?

h, w = result.shape[0:2]

# make arrays that hold x,y coords
grid = np.indices((h, w))
x = grid[1]
y = grid[0]

top_left_mask = np.hypot(x - x0, y - y0) - r < 0
top_right_mask = np.hypot(x + t_w - x0, y - y0) - r < 0
bot_left_mask = np.hypot(x - x0, y + t_h - y0) - r < 0
bot_right_mask = np.hypot(x + t_w - x0, y + t_h - y0) - r < 0

mask = np.logical_and.reduce((top_left_mask, top_right_mask,
bot_left_mask, bot_right_mask))
mask = mask.astype(np.uint8)
cv2.imwrite('mask.png', mask*255)

这是“奇特”面具的样子:
enter image description here

似乎是对的。由于模板形状,它不能是圆形的。如果我用这个掩码运行 clock2.jpg 我得到: output with fancy mask on clock2.jpg

它有效。没有识别出糖果棒。但我希望我能用更少的代码行来做到这一点......

编辑:我做了一些分析。我以“简单”方式和“准确”方式运行了 100 个循环并计算了每秒帧数 (fps):

  • 简单方法:12.7 fps
  • 准确方式:7.8 fps

因此使用 NumPy 制作面具需要付出一些代价。这些测试是在功能相对强大的工作站上完成的。它可能会在更普通的硬件上变得更丑陋......

最佳答案

方法一:在cv2.matchTemplate之前'mask'图像

只是为了好玩,我尝试为我传递给 cv2.matchTemplate 的图像制作自己的面具。看看我能达到什么样的表现。需要明确的是,这不是一个合适的蒙版——我将所有要忽略的像素设置为一种颜色(黑色或白色)。这是为了解决只有 TM_SQDIFF 和 TM_CORR_NORMED 支持正确掩码的事实。

@Alexander Reynolds 在评论中提出了一个非常好的观点,如果模板图像(我们试图找到的东西)有很多黑色或白色,则必须小心。对于许多问题,我们将先验知道模板是什么样的,我们可以指定白色背景或黑色背景。

我使用 cv2.multiply ,这似乎比 numpy.multiply 快. cv2.multiply 具有额外的优势,它会自动将结果限制在 0 到 255 的范围内。

import numpy as np
import cv2
import time

img = cv2.imread('clock1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

template = cv2.imread('target.jpg')
t_h, t_w = template.shape[0:2] # template height and width

mask_background = 'WHITE'

start_time = time.time()

for i in range(100): # do 100 cycles for timing
# find circle in gray image using Hough transform
circles = cv2.HoughCircles(gray, method = cv2.HOUGH_GRADIENT, dp = 1,
minDist = 150, param1 = 50, param2 = 70,
minRadius = 131, maxRadius = 200)
i = circles[0,0]
x0 = i[0]
y0 = i[1]
r = i[2]

# display circle on color image
cv2.circle(img,(x0, y0), r,(0,255,0),2)

if mask_background == 'BLACK': # black = 0, white = 255 on grayscale
mask = np.zeros(img.shape, dtype = np.uint8)

elif mask_background == 'WHITE':
mask = 255*np.ones(img.shape, dtype = np.uint8)

cv2.circle(mask, (x0, y0), r, color = (1,1,1), thickness = -1)
img2 = cv2.multiply(img, mask) # element wise multiplication
# values > 255 are truncated at 255
# do the template match
result = cv2.matchTemplate(img2, template, cv2.TM_CCOEFF_NORMED)

# call minMaxLoc
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

# draw found rectangle on img
if max_val > 0.4:
cv2.rectangle(img, max_loc, (max_loc[0]+t_w, max_loc[1]+t_h), (0,255,0), 4)

fps = 100/(time.time()-start_time)
print('fps ', fps)

cv2.imwrite('output.jpg', img)

分析结果:

  • 黑色背景 12.3 fps
  • 白色背景 12.1 fps

相对于原始问题中的 12.7 fps,使用此方法对性能的影响很小。但是,它的缺点是它仍然会找到仍然稍微超出边缘的模板。根据问题的确切性质,这在许多应用中可能是可以接受的。

方法二:使用cv2.boxFilter为 minMaxLoc 创建掩码

在此技术中,我们从圆形掩码开始(如在 OP 中),然后使用 cv2.boxFilter 对其进行修改。我们将 anchor 从内核的默认中心更改为左上角 (0, 0)

import numpy as np
import cv2
import time

img = cv2.imread('clock1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

template = cv2.imread('target.jpg')
t_h, t_w = template.shape[0:2] # template height and width
print('t_h, t_w ', t_h, ' ', t_w)

start_time = time.time()

for i in range(100):
# find circle in gray image using Hough transform
circles = cv2.HoughCircles(gray, method = cv2.HOUGH_GRADIENT, dp = 1,
minDist = 150, param1 = 50, param2 = 70,
minRadius = 131, maxRadius = 200)
i = circles[0,0]
x0 = i[0]
y0 = i[1]
r = i[2]

# display circle on color image
cv2.circle(img,(x0, y0), r,(0,255,0),2)

# do the template match
result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# finally, here is the part that gets tricky. we want to find highest
# rated match inside circle and we'd like to use minMaxLoc

# start to make mask by drawing circle on zero array
mask = np.zeros(result.shape, dtype = np.float)
cv2.circle(mask, (x0, y0), r, color = 1, thickness = -1)

mask = cv2.boxFilter(mask,
ddepth = -1,
ksize = (t_w, t_h),
anchor = (0,0),
normalize = True,
borderType = cv2.BORDER_ISOLATED)
# mask now contains values from zero to 1. we want to make anything
# less than 1 equal to zero
_, mask = cv2.threshold(mask, thresh = 0.9999,
maxval = 1.0, type = cv2.THRESH_BINARY)
mask = mask.astype(np.uint8)

# call minMaxLoc
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result, mask = mask)

# draw found rectangle on img
if max_val > 0.4:
cv2.rectangle(img, max_loc, (max_loc[0]+t_w, max_loc[1]+t_h), (0,255,0), 4)

fps = 100/(time.time()-start_time)
print('fps ', fps)

cv2.imwrite('output.jpg', img)

此代码提供与 OP 相同的掩码,但帧率为 11.89 fps。与方法 1 相比,此技术为我们提供了更高的准确性,同时对性能的影响也略有增加。

关于python-3.x - 模板匹配 : efficient way to create mask for minMaxLoc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50614950/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com