openCV——模板匹配

单模板匹配

import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline 
def cvshow(name, ndarray):
    img = cv2.imshow(name, ndarray)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

模板匹配是指在当前图像 A 内寻找与图像 B 最相似的部分,一般将图像 A 称为输入图像,
将图像 B 称为模板图像。模板匹配的操作方法是将模板图像 B 在图像 A 上滑动,遍历所有像
素以完成匹配。

API

result = cv2.matchTemplate(image, templ, method[, mask ] )

  • image 为原始图像,必须是 8 位或者 32 位的浮点型图像。
  • templ 为模板图像。它的尺寸必须小于或等于原始图像,并且与原始图像具有同样的类型。
  • method 为匹配方法。有六种方法,如下图
  • mask 为模板图像掩模。它必须和模板图像 templ 具有相同的类型和大小。通常情况下该值使用默认值即可。当前,该参数仅支持 TM_SQDIFF 和 TM_CCORR_NORMED 两个值。
  • 返回值 result 是由每个位置的比较结果组合所构成的一个结果集,类型是单通道 32 位浮点型。如果输入图像(原始图像)尺寸是 WH,模板的尺寸是 wh,则返回值的大小为(W-w+1)*(H-h+1)。

openCV——模板匹配_第1张图片

下图是计算公式:
openCV——模板匹配_第2张图片

method 的值为 cv2.TM_SQDIFF 和 cv2.TM_SQDIFF_NORMED 时,result 值为 0 表示匹配度最好,值越大,表示匹配度越差;
method 的值为 cv2.TM_CCORR、cv2.TM_CCORR_NORMED、cv2.TM_CCOEFF和cv2.TM_CCOEFF_NORMED 时,result 的值越小表示匹配度越差,值越大表示匹配度越好

在查找最佳匹配时,首先要确定使用的是何种 method,然后再确定到底是查找最大值,还是查找最小值。查找最值(极值)与最值所在的位置,可以使用 cv2.minMaxLoc()函数实现。

minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc( src [, mask] )

  • src 为单通道数组。
  • minVal 为返回的最小值,如果没有最小值,则可以是 NULL(空值)。
  • maxVal 为返回的最大值,如果没有最小值,则可以是 NULL。
  • minLoc 为最大值的位置,如果没有最大值,则可以是 NULL。
  • maxLoc 为最大值的位置,如果没有最大值,则可以是 NULL。
  • mask 为用来选取掩模的子集,可选项。
lena = cv2.imread("lena.jpg")
template = cv2.imread("template.png")
# 模板匹配
res = cv2.matchTemplate(lena, template, cv2.TM_CCOEFF_NORMED)
# 相关系数则是值越大越匹配
minVal, maxVal, minLoc, maxloc = cv2.minMaxLoc(res)
img = cv2.rectangle(lena, (maxloc[0], maxloc[1]), (maxloc[0]+template.shape[1], maxloc[1]+template.shape[0]), (255, 0, 0), 2)
cvshow("lena", img)

Img = cv.rectangle( img, pt1, pt2, color[, thickness])

  • img 表示要标记的目标图像
  • pt1 是矩形的顶点
  • pt2 是 pt1 的对角顶点
  • color 是要绘制矩形的颜色或灰度级(灰度图像)
  • thickness 是矩形边线的宽度

多模板匹配

有些情况下,要搜索的模板图像很可能在输入图像内出现了多次,这时就需要想匹配多个结果,使用函数 cv2.minMaxLoc()是无法实现的,需要利用np.where()进行处理。要找出多个匹配结果。

a = np.arange(12).reshape(3, 4)
b = np.where(a>2)
print(a)
print(b)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
(array([0, 1, 1, 1, 1, 2, 2, 2, 2], dtype=int64), array([3, 0, 1, 2, 3, 0, 1, 2, 3], dtype=int64))

可以看出,np.where()返回值为一个元组,每个元素为一个array,array中的元素代表索引。因为a为二维矩阵,所以返回两个数组,一个代表行索引,一个代表列索引,行列索引一一匹配成一个坐标

函数 zip()用可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表

# 将原始图像扩充为4份进行多模板匹配
lena = cv2.imread("lena.jpg")
mid = np.hstack((lena, lena))
res = np.vstack((mid, mid))
cvshow("res", res)
# 读入模板
template = cv2.imread("template.png")
# 模板匹配
result = cv2.matchTemplate(res, template, cv2.TM_CCOEFF_NORMED)

width, height = template.shape[1], template.shape[0]

# 阈值筛选
filter = np.where(result>0.95)
# 打包行列索引对并遍历
for item in zip(*filter[::-1]):  #filter[::-1]表示行列数组互换位置,原来是第一个数组为行索引,第二个数组为列索引,但是列索引才表示x,行索引表示y
    print(item)
    cv2.rectangle(res, (item[0], item[1]), (item[0]+width, item[1]+height), (0, 255, 0), 1)
cvshow("res", res)
(127, 111)
(390, 111)
(127, 374)
(390, 374)

其实按这个道理来说,应该会有很多区域可以匹配成功,但是每个图象里怎么就一个框呢?其实是都画出来了,尤其是最相似的区域里有很多框,只不过都重合在一起了,框的线条粗细才1,可以把阈值调低看框是不是会变很粗


你可能感兴趣的:(openCV,图像处理,目标检测,计算机视觉,opencv,深度学习)