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 上滑动,遍历所有像
素以完成匹配。
result = cv2.matchTemplate(image, templ, method[, mask ] )
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] )
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])
有些情况下,要搜索的模板图像很可能在输入图像内出现了多次,这时就需要想匹配多个结果,使用函数 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,可以把阈值调低看框是不是会变很粗