【OpenCV Python】核心操作--模板匹配
在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)
屏幕剪辑的捕获时间: 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
我们可以看出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
屏幕剪辑的捕获时间: 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)
屏幕剪辑的捕获时间: 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)
屏幕剪辑的捕获时间: 2018/4/17 23:01
以上代码中,黑色部分和之前单个匹配一样,对于红色部分。
0.985是我们设置的阈值,res>=0.958的作用是将结果array里符合条件的数值换成True ,反之换成False。
np.where的作用是将true的索引输出到 loc变量
loc[::-1]将输出的索引变换成x,y坐标,因为索引和x,y坐标是正好相反的,所以要对换下位置。
然后再循环坐标,分别画出红色边界。