ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

opencv的模板匹配方法

2021-09-30 13:34:54  阅读:178  来源: 互联网

标签:loc 匹配 cv2 opencv result np dets data 模板


模板匹配

在opencv中进行模板匹配使用cv2.matchTemplate函数,简单使用如下:

import cv2
import numpy as np

img = cv2.imread('landscape.jpg', cv2.IMREAD_GRAYSCALE)
tpl = cv2.imread('template.jpg', cv2.IMREAD_GRAYSCALE)

result = cv2.matchTemplate(img, tpl, cv2.TM_CCORR_NORMED)
# 返回的max_loc 是按照Opencv 的坐标(x, y),不是numpy的(row, col)
(_, max_val, _, max_loc) = cv2.minMaxLoc(result)
# 利用最大值*0.99 作为阈值,阈值可根据情况设置
threshold = max_val * 0.99
# loc = [[x1, x2, x3...], [y1, y2, y3]]  注意和numpy的row col转换
loc = np.where(result >= threshold)

tr = img.copy()
for pt in zip(*loc[::-1]):
	cv2.rectangle(tr, pt, (pt[0] + tw, pt[1] + th), (0, 0, 255), 1)

其中

result = cv2.matchTemplate(img, tpl, cv2.TM_CCORR_NORMED)

假设landscape图片大小为5120x9760,读取进来的img矩阵大小为9760*5120,template图片大小为366x533,读入tpl的大小为533x366。则我们可以推算出result的大小:(9760-533+1, 5120-366+1)=(9208, 4755)。数组中记录的是进行模板匹配的相合数据。result[m][n]代表的是从img的m行n列像素点开始进行匹配的结果。你可以把result[m][n]转化到PyQT的坐标系,变为(n, m),那么图像在PyQt的范围就是(n, m) ~ (n+tw, m+th)。

loc返回值是一个二维矩阵:[[row0, row1, row2, ...],[col0, col1, col2, ...]](row0, col0)是指在result中row0行col0列符合条件。

关于[::-1]的解释:a = np.array([1, 2, 3, 4])执行a[::-1]后返回结果为[4, 3, 2, 1],对于二维矩阵b = np.array([[1, 2],[5, 6]])执行b[::-1]后返回结果为[[5, 6], [1, 2]]。对于返回loc执行这步操作是因为result是按(x, y)顺序排列,对于x来说其实代表的是列,如果我们想要行在前,必须反过来。

*loc[::-1]最前方的*,是解除一层[],例如a = np.array([[1, 2],[5, 6]])*a[1, 2], [5, 6]

上述的代码存在一些问题:匹配出的模板有重叠,例如,图片((0, 0), (100, 100))区域匹配度比较高,但是((1, 1), (101, 101))的匹配度也很高,这就导致匹配出多个重叠区域。可以通过nms极大值抑制。

th, tw = tpl.shape[:2]
loc = np.where(result >= threshold)
score = result[result >= max_val*0.99] # 返回的是值,值原来顺序变为一维矩阵

xmin = np.array(loc[1])
ymin = np.array(loc[0])
xmax = xmin + tw
ymax = ymin + th
# 全部转为一维列向量
xmin, ymin, xmax, ymax = xmin.reshape(-1, 1), ymin.reshape(-1, 1), xmax.reshape(-1, 1), ymax.reshpae(-1, 1)
score = score.reshape(-1, 1)

data_hlist = []
data_hlist.append(xmin); data_hlist.append(ymin); data_hlist.append(xmax); data_hlist.append(ymax); data_hlist.append(score)
data_hstack = np.hstack(data_hlist) #按照 xmin, ymin, xmax, ymax, score 顺序
thresh = 0.3 #设置NMS交互比
keep_dets = py_nms(data_hstack, thresh)
dets = data_hstack[keep_dets]

tr = img.copy()
for rec in dets:
	cv2.rectangle(tr, (int(rec[0]), int(rec[1])), (int(rec[2]), int(rec[3])), (0, 0, 255), 2)

实现py_nms函数:

# NMS 非极大值抑制
def py_nms(dets, thresh):
    """Pure Python NMS baseline."""
    # x1、y1、x2、y2、以及score賦值
    # (x1、y1)(x2、y2)為box的左上和右下角坐标
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]
    # 每一个候选框的面积
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    # order是按照score降序排序的有,返回的是索引数组,[::-1]为了将升序变为降序
    order = scores.argsort()[::-1]
    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        # 计算当前概率最大矩形框与其他矩形框的相交框的坐标,得到的是向量
        xx1 = np.maximum(x1[i], x1[order[1:]]) # x1[i]虽然为一个数,但是由于numpy的broadcast机制,xx1是一个数组
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])
        # 计算相交框的面积,注意矩形框不相交时w或h算出來会是负数,用0代替
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        # 计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)
        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        # 找到重叠度不高于阈值的矩形框索引
        inds = np.where(ovr <= thresh)[0]
        # 将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回來
        order = order[inds + 1]
    return keep

标签:loc,匹配,cv2,opencv,result,np,dets,data,模板
来源: https://www.cnblogs.com/loganxu/p/15233523.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有