Opencv-Python学习笔记(十二):模板匹配

本篇博客记录学习OpenCV-Python模板匹配的相关知识。

  • 使用模板匹配在一幅图像中查找目标。
  • 学习到的函数有: cv2.matchTemplate()cv2.minMaxLoc()。

原理

模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。 OpenCV 为我们提供了函数: cv2.matchTemplate()。如同 2D 卷积,它也是用模板图像在输入图像(大图)上滑动,并在每一个位置对模板图像和与其对应的输入图像的子区域进行比较。OpenCV 提供了几种不同的比较方法(见下文)。其返回的结果是一个灰度图像,每一个像素值表示了此区域与模板的匹配
程度。如果输入图像的大小是( W乘H),模板的大小是( w乘h),输出的结果的大小就是( W-w+1, H-h+1)。当你得到这幅图之后,就可以使用函数cv2.minMaxLoc() 来找到其中的最小值和最大值的位置了。第一个值为矩形左上角的点,( w, h)为模板矩形的宽和高。这个矩形就是找到的模板区域了。
OpenCV 提供的几种不同的比较方法:

  • TM_SQDIFF:计算平方不同,计算出来的值越小,越相关。
  • TM_CCORR:计算相关性,计算出来的值越大,越相关。
  • TM_CCOEFF:计算相关系数,计算出来的值越大,越相关。
  • TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近于0,越相关。
  • TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近于1,越相关。
  • TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近于1,越相关。

接下来我们用一个示例进行验证,虽然有六种不同的比较方法,但是在实际应用中一般会使用归一化的比较方法,下面的示例我我们用TM_SQDIFF_NORMED比较方法。

模板图片:

 实验代码:

import cv2 as cv
import numpy as np


# 模板匹配,就是在整个图像区域发现与给定子图像匹配的小块区域,
# 需要模板图像T和待检测图像-源图像S
# 工作方法:在待检测的图像上,从左到右,从上倒下计算模板图像与重叠子图像匹配度,
# 匹配度越大,两者相同的可能性越大。
def template_demo():
    tpl = cv.imread("F:/Pycharm/opencv_exercises-master/images/rabbit.jpg")  # 模板图片
    print("模板大小:", tpl.shape)
    target = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu22.jpg")  # 原图
    print("原图大小:", target.shape)
    cv.imshow("template", tpl)
    cv.imshow("target", target)
    methods = [cv.TM_SQDIFF_NORMED, cv.TM_CCORR_NORMED, cv.TM_CCOEFF_NORMED]  # 三种模板匹配方法
    th, tw = tpl.shape[:2]

    result = cv.matchTemplate(target, tpl, cv.TM_SQDIFF_NORMED)  # 得到匹配结果
    print("结果大小:", result.shape)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
    print("min_val", min_val)
    print("max_val", max_val)
    print("min_loc", min_loc)
    print("max_loc", max_loc)
    tl = min_loc
    br = (tl[0] + tw, tl[1] + th)
    cv.rectangle(target, tl, br, (0, 0, 255), 2)  # tl为左上角坐标,br为右下角坐标,从而画出矩形
    cv.imshow("target", target)
    

if __name__ == '__main__':
    template_demo()

    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()  # 关闭所有窗口

 打印结果值:

可见其返回的结果是一个灰度图像,每一个像素值表示了此区域与模板的匹配程度。如果输入图像的大小是( 727,1011),模板的大小是( 317,256),输出的结果的大小就是( 727-317+1, 1011-256+1)-->(411,756) 。

接下来我们看一下其他两种归一化的比较方法效果图。

实验代码:

import cv2 as cv
import numpy as np


# 模板匹配,就是在整个图像区域发现与给定子图像匹配的小块区域,
# 需要模板图像T和待检测图像-源图像S
# 工作方法:在待检测的图像上,从左到右,从上倒下计算模板图像与重叠子图像匹配度,
# 匹配度越大,两者相同的可能性越大。
def template_demo():
    tpl = cv.imread("F:/Pycharm/opencv_exercises-master/images/rabbit.jpg")  # 模板图片
    print("模板大小:", tpl.shape)
    target = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu22.jpg")  # 原图
    print("原图大小:", target.shape)
    cv.imshow("template", tpl)
    cv.imshow("target", target)
    methods = [cv.TM_SQDIFF_NORMED, cv.TM_CCORR_NORMED, cv.TM_CCOEFF_NORMED]  # 三种模板匹配方法
    th, tw = tpl.shape[:2]

    for md in methods:
        print(md)
        result = cv.matchTemplate(target, tpl, md)  # 得到匹配结果
        print("结果大小:", result.shape)
        min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
        print("min_val", min_val)
        print("max_val", max_val)
        print("min_loc", min_loc)
        print("max_loc", max_loc)
        if md == cv.TM_SQDIFF_NORMED:  # cv.TM_SQDIFF_NORMED最小时最相似,其他最大时最相似
            tl = min_loc  # 左上角点位
        else:
            tl = max_loc

        br = (tl[0] + tw, tl[1] + th)
        cv.rectangle(target, tl, br, (0, 0, 255), 2)  # tl为左上角坐标,br为右下角坐标,从而画出矩形
        cv.imshow("match-"+np.str(md), target)


if __name__ == '__main__':
    template_demo()

    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()  # 关闭所有窗口

效果图:

数据结果:

 上面介绍的都是单个匹配,但是如果我们要是进行人脸检测,虽然实际应用是通过机器学习算法实现,但是用我们今天学习的知识也是可以实现的,可能用上面的方法就有点行不通了,因为一张图中会有多张人脸,这时候我们就需要匹配多个对象。下面用个简单的例子进行测试。

步骤也是一样的:

  • 读入模板图像和目标图像
  • 进行模板匹配(打印出返回值,方便下一步操作的判断)
  • TM_CCOEFF_NORMED方法进行比较判断根据上一步的打印值,设定一个阈值
  • 然后寻找位置,将大于0.8的位置保存起来
  • 在匹配到的区域绘制矩形

实验代码:

import cv2 as cv
import numpy as np


# 模板匹配,就是在整个图像区域发现与给定子图像匹配的小块区域,
# 需要模板图像T和待检测图像-源图像S
# 工作方法:在待检测的图像上,从左到右,从上倒下计算模板图像与重叠子图像匹配度,
# 匹配度越大,两者相同的可能性越大。
def more_template_demo():
    tpl = cv.imread("F:/Pycharm/opencv_exercises-master/images/mario_coin.jpg")  # 模板图片
    target = cv.imread("F:/Pycharm/opencv_exercises-master/images/mario.jpg")  # 原图
    cv.imshow("template", tpl)
    cv.imshow("target", target)
    th, tw = tpl.shape[:2]
    result = cv.matchTemplate(target, tpl, cv.TM_CCOEFF_NORMED)  # 得到匹配结果
    print("result", result)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
    print("max_val", max_val)
    threshold = 0.8
    # 取模板匹配程度大于80%的坐标
    local = np.where(result >= threshold)
    for tl in zip(*local[::-1]):  # *表示可选参数
        botton_right = (tl[0] + tw, tl[1] + th)
        cv.rectangle(target, tl, botton_right, (0, 0, 255), 2)
    cv.imshow("target", target)


if __name__ == '__main__':
   
    more_template_demo()
    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()  # 关闭所有窗口

实验效果图:

整体工程代码:

 

import cv2 as cv
import numpy as np


# 模板匹配,就是在整个图像区域发现与给定子图像匹配的小块区域,
# 需要模板图像T和待检测图像-源图像S
# 工作方法:在待检测的图像上,从左到右,从上倒下计算模板图像与重叠子图像匹配度,
# 匹配度越大,两者相同的可能性越大。
def template_demo():
    tpl = cv.imread("F:/Pycharm/opencv_exercises-master/images/rabbit.jpg")  # 模板图片
    print("模板大小:", tpl.shape)
    target = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu22.jpg")  # 原图
    print("原图大小:", target.shape)
    cv.imshow("template", tpl)
    cv.imshow("target", target)
    methods = [cv.TM_SQDIFF_NORMED, cv.TM_CCORR_NORMED, cv.TM_CCOEFF_NORMED]  # 三种模板匹配方法
    th, tw = tpl.shape[:2]

    # result = cv.matchTemplate(target, tpl, cv.TM_SQDIFF_NORMED)  # 得到匹配结果
    # print("结果大小:", result.shape)
    # min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
    # print("min_val", min_val)
    # print("max_val", max_val)
    # print("min_loc", min_loc)
    # print("max_loc", max_loc)
    # tl = min_loc
    # br = (tl[0] + tw, tl[1] + th)
    # cv.rectangle(target, tl, br, (0, 0, 255), 2)  # tl为左上角坐标,br为右下角坐标,从而画出矩形
    # cv.imshow("target", target)
    for md in methods:
        print(md)
        result = cv.matchTemplate(target, tpl, md)  # 得到匹配结果
        print("结果大小:", result.shape)
        min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
        print("min_val", min_val)
        print("max_val", max_val)
        print("min_loc", min_loc)
        print("max_loc", max_loc)
        if md == cv.TM_SQDIFF_NORMED:  # cv.TM_SQDIFF_NORMED最小时最相似,其他最大时最相似
            tl = min_loc  # 左上角点位
        else:
            tl = max_loc

        br = (tl[0] + tw, tl[1] + th)
        cv.rectangle(target, tl, br, (0, 0, 255), 2)  # tl为左上角坐标,br为右下角坐标,从而画出矩形
        cv.imshow("match-" + np.str(md), target)
        # cv.imshow("match-" + np.str(md), result)


def more_template_demo():
    tpl = cv.imread("F:/Pycharm/opencv_exercises-master/images/mario_coin.jpg")  # 模板图片
    target = cv.imread("F:/Pycharm/opencv_exercises-master/images/mario.jpg")  # 原图
    cv.imshow("template", tpl)
    cv.imshow("target", target)
    th, tw = tpl.shape[:2]
    result = cv.matchTemplate(target, tpl, cv.TM_CCOEFF_NORMED)  # 得到匹配结果
    print("result", result)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
    print("max_val", max_val)
    threshold = 0.8
    # 取模板匹配程度大于80%的坐标
    local = np.where(result >= threshold)
    for tl in zip(*local[::-1]):  # *表示可选参数
        botton_right = (tl[0] + tw, tl[1] + th)
        cv.rectangle(target, tl, botton_right, (0, 0, 255), 2)
    cv.imshow("target", target)


if __name__ == '__main__':
    # template_demo()
    more_template_demo()
    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()  # 关闭所有窗口

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MMagicLoren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值