在opencv里,模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)



1.相关函数:

opencv里提供cv2.matchTemplate(src, template, method)函数来进行模板匹配,关于这个函数有以下几点要注意:

(1)在opencv里,method总共有6种:

cv2.TM_CCOEFF

cv2.TM_CCOEFF_NORMED

cv2.TM_CCORR

cv2.TM_CCORR_NORMED

cv2.TM_SQDIFF

cv2.TM_SQDIFF_NORMED

其中,cv2.TM_SQDIFF_NORMED,cv2.TM_SQDIFF这两种,其输出结果矩阵里最小值是匹配程度最好的,其余四种都是矩阵里最大值是匹配程度最好的。

(2)这个函数的最终结果是一个矩阵,如果我们使用cv2.minMaxLoc(src)函数,便可以找到对应的最大值,和最小值的坐标位置

例子:

img = cv2.imread("Mine.png", 1)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread("temp_2.png", 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
min_val ,max_val, min_loc, max_loc = cv2.minMaxLoc(res)
img = cv2.rectangle(img,max_loc,(max_loc[0]+w,max_loc[1]+h),(0,0,255),2)

 

python opencv识别匹配坐标 opencv python模板匹配_python opencv识别匹配坐标

屏幕剪辑的捕获时间: 2018/4/17 22:00

 



2.多对象匹配

有时候,如果你要匹配的模板,在图形中多次出现,那么就需要多对象匹配。

多对象匹配的原理很简单,因为opencv里的模板匹配,是将图形里的每一处和模板进行对比,所以同一个模板下,多对象匹配情况下,结果矩阵里会有好几个值,和最大(小)值接近,如果我们设置一个阈值,在这个阈值以上(以下)的值都提取出来,再分别得到他们的坐标,理论上只要这个阈值设置的恰当,就可以将多对象都匹配出来。

 

在使用多对象匹配时,先介绍几个方便处理这个过程的函数:

 

  np.nonzero()

这个函数的输入是一个多维数组,其作用是将所有非0值的索引放入一个多维数组里作为结果输出,如果输入是1维,结果应该也是1维,2维的结果应该也是2维,往上同理。

例如:

A=[[0,1,1],[0,0,0],[1,0,0]]

result = np.nonzero(A)

print  result

python opencv识别匹配坐标 opencv python模板匹配_数组_02

我们可以看出A这个数组里,非0的数值分别是第0个小数组的第1个,第0个小数组第2个,第2个小数组第0个。所以结果放在两个数组里[0.0.2],[1.2.0]

 

 np.where[condition, x, y]

对于这个函数,conditon,x,y都是同维度的数组,其结果也是个同维度的数组,它的作用是这样的,condition里的第(i,j)里的数看作一个bool类型的数,如果是true,将x里对应的(i,j)数值放入结果的(i,j)位置,如果是false就将y里对应的(i,j)数值放入结果的(i,j)位置。

这个函数还有一种情况,如果输入只有conditon一个参数,则是输出np.nonzero(condition)

 

如果将一个numpy的array与一个数做比较,则是将array里每一个数值分别与这个数做对比,将结果放入每一个数对应的位置

例如:

A=np.array([[0,1,1],[0,0,0],[1,0,0]])

result=A>=1

print  result

 

python opencv识别匹配坐标 opencv python模板匹配_数组_03

屏幕剪辑的捕获时间: 2018/4/17 22:39

 

Zip()

  zip函数的输入是不定量个list或者tuple,如A,B,C,这个函数将输入的list或者tuple的第i位

(0<i<len(list))位取出,组成(Ai,Bi,Ci)再将这些tuple放入一个list里输出:

例如:

A = [0,1,2]

B = [1,4,5]

C = [7,0,0]

print zip(A,B,C)

 

python opencv识别匹配坐标 opencv python模板匹配_python opencv识别匹配坐标_04

屏幕剪辑的捕获时间: 2018/4/17 22:56

 

值得注意的是,zip的输入是不定函数,其数量是不定的,所以使用zip(*arg),将所有参数放入一个list里,作为输入,也是可以的,所以上面的代码也可以这样写:

D = [[0,1,2], [1,4,5],[7,0,0]]

print zip(*D)

其输出和上面一样。

 

讲了这么多,我们来看看多对象匹配具体怎么完成,代码如下:

img = cv2.imread("Mine.png", 1)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread("temp.png", 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
 
locs = np.where(res >=0.985)
for loc in zip(*locs[::-1]):
     img =cv2.rectangle(img, loc, (loc[0] + w, loc[1] + h), (0, 0, 255), 3)

 

python opencv识别匹配坐标 opencv python模板匹配_模板匹配_05

屏幕剪辑的捕获时间: 2018/4/17 23:01

 

以上代码中,黑色部分和之前单个匹配一样,对于红色部分。

python opencv识别匹配坐标 opencv python模板匹配_python opencv识别匹配坐标_06

0.985是我们设置的阈值,res>=0.958的作用是将结果array里符合条件的数值换成True ,反之换成False。

 np.where的作用是将true的索引输出到 loc变量

python opencv识别匹配坐标 opencv python模板匹配_数组_07

 loc[::-1]将输出的索引变换成x,y坐标,因为索引和x,y坐标是正好相反的,所以要对换下位置。

然后再循环坐标,分别画出红色边界。