OpenCV中的模板匹配非常棒。并且您可以将掩码传递给cv2.minMaxLoc,以便您只在图像的一部分中搜索(排序)所需的模板。您还可以在matchTemplate操作中使用掩码,但这只会掩盖模板。
我想找一个模板,我想确保这个模板位于我图片的其他区域。
计算minMaxLoc的掩码似乎很重。也就是说,计算 准确的 掩码感觉很重。如果以简单的方式计算遮罩,则忽略模板的大小。
示例是有序的。我的输入图像如下所示。他们有点做作。我想找到糖果棒,但只有在钟面白圈内 完全 时才会找到。
在clock1中,直板在圆形钟面内,它是一个“通过”。但是在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)
使用clock2输出 甚至找到了糖果吧 虽然它的一部分是在圈外
因此,为了正确制作一个掩码,我使用了一堆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)
似乎是正确的。由于模板形状,它不能是圆形的。如果我用这个面具运行clock2.jpg我得到:
有效。没有发现糖果棒。但我希望我能用更少的代码行完成......
修改: 我做了一些分析。我运行了100个循环的“简单”方式和“准确”方式和每秒计算帧数(fps):
因此使用NumPy制作面具需要付出一些代价。这些测试是在相对强大的工作站上完成的。它可能会在更适度的硬件上变得更加丑陋......
答案 0 :(得分:2)
@Alexander Reynolds在评论中提出了一个非常好的观点,即如果模板图像(我们试图找到的东西)有很多黑色或大量白色,必须要小心。对于许多问题,我们将知道先验模板的外观,我们可以指定白色背景或黑色背景。
我使用的cv2.multiply似乎比numpy.multiply更快。 <?php include_once('common/header.php');?>
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="#">Dashboard</a>
</li>
<li class="breadcrumb-item active">My Dashboard</li>
</ol>
</div>
<!-- HERE WILL BE ALL PAGE DATA WILL BE SHOWN -->
<?php echo $chart_content; ?>
</div>
<?php require_once('common/footer.php');?>
具有额外的优势,它会自动将结果剪辑到0到255之间。
cv2.multiply
分析结果:
在原始问题中,使用此方法相对于12.7 fps的性能影响非常小。然而,它的缺点是它仍然会找到仍然粘在边缘上的模板。根据问题的确切性质,这在许多应用中都是可以接受的。
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)
从默认的内核中心更改为左上角(0,0)
anchor
此代码提供与OP相同的掩码,但是为11.89 fps。与方法1 相比,此技术可以提供更高的准确性,但性能略高。。