OpenCV-Python实现多模板匹配

模板匹配的作用在图像识别领域作用可大了。那什么是模板匹配?

模板匹配,就是在一幅图像中寻找另一幅模板图像最匹配(也就是最相似)的部分的技术。

多模板匹配

在上一篇的实战中,我们通过人物眼睛的子图,找出了其在图像中出现位置。但是,有些情况下,并不仅仅只有一次,比如我们讲解傅里叶变换时,曾介绍一张草原的狮子图。如果匹配某个草,可能单个图像内会有很多,这个时候就要找出多个匹配结果。

而函数cv2.minMaxLoc()仅仅能找出最值,无法给出所有匹配区域的位置信息。所以,要想匹配多个结果,就需要进行如下4个步骤:

获取匹配位置的集合

首先,Numpy库中的函数where()能够获取模板匹配位置的集合。对于不同的输入,其返回值是不同的。

  • 当输入是一维数组时,返回值是一维索引,只是一组索引数组。
  • 当输入是二维数组时,返回的是匹配值的位置索引,因此会有两组索引数组表示返回值的位置。

比如,我们的灰度图像一般都是二维数组。下面,我们来查找一个二维数组中,值大于8的元素索引:

import numpy as np

img = np.array([[2, 4, 6, 8, 10], [9, 60, 10, 30, 4], [55, 21, 11, 7, 5]])
result = np.where(img > 5)
print(result)

运行之后,控制台会输出如下内容:

如果你对Numpy不是很了解的化。下面博主在将数据转换以下,基本上都能看懂了。转换之后,格式如下:

第一行为大于5的值的X坐标,第二行为大于5的值的Y坐标。那么上面大于5的数组索引为:[0,2],[0,3],[0,4],[1,0],[1,1],[1,2],[1,3],[2,0],[2,1],[2,2],[2,3]。你可以回溯对比看看是不是一致的。

通过np.where()函数可以找出在cv2.matchTemplate()函数的返回值中,哪些位置上的值是大于阈值threshold的。具体操作代码如下:

loc=np.where(res>threshold)

循环

因为我们找到的原图对应的模板图像不止一个,要处理多个值,肯定会用到循环。因此,在获取匹配值的索引后,可以采用如下语句遍历所有匹配的位置,对这些位置做标记:

for i in 匹配位置集合:
	标记匹配位置

在循环中使用zip()

函数zip()用可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

例如,我们获取的索引为x,y,z。下面我们使用zip()将它们打包成元组。代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = np.array([[2, 4, 6, 8, 10], [9, 60, 10, 30, 4], [55, 21, 11, 7, 5]])
result = np.where(img > 5)
for i in zip(*result):
    print(i)

这里我们还是使用上面的值,输出结果如下:

这里自动将我们刚才满足条件的索引打包成了元素格式。是不是比刚才的控制台输出结果更加的直观呢?

替换坐标

我们上面得到的结果是符合条件的索引:(行号,列号),但我们需要绘制匹配位置的矩形,需要的是(列号,行号)。

所以,在使用cv2.rectangle()绘制矩形前,要先将函数numpy.where()得到的位置索引行列互换,行列互换可以通过如下代码实现:

import numpy as np

img = np.array([[2, 4, 6, 8, 10], [9, 60, 10, 30, 4], [55, 21, 11, 7, 5]])
result = np.where(img > 5)
for i in zip(*result[::-1]):
    print(i)

运行之后,输出结果如下:

实战多模板匹配

既然我们已经了解了标记绘制多个模板位置的4个步骤。下面,我们直接将上面的代码整理以下,即可完成多模板的匹配。具体代码如下所示:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("34.jpg", 0)
template = cv2.imread("4_1.jpg", 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.9
loc = np.where(res >= 0.9)
for i in zip(*loc[::-1]):
    cv2.rectangle(img, i, (i[0] + w, i[1] + h), 255, 1)
plt.imshow(img, cmap="gray")
plt.axis("off")
plt.show()

这里的代码与上面4个步骤一摸一样,具体就不做过多的讲解了。运行之后,多个模板也就匹配完成。

附录:

模板图

原图

实例:基于opencv的多目标模板匹配

利用opencv进行多目标模板匹配,只要是利用其matchTemplate函数,但在多目标(这里是讨论目标图片中不同大小模板的匹配),以下贴出代码和图片,供大家参考:

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;

Point getNextMinLoc(Mat &result, Point minLoc, int maxValue, int templatW, int templatH);

int main(void)
{
 Mat src = imread("1_2.png");
 Mat srcCopy = src.clone();

 Mat temp = imread("1_4.png");
 Mat result;

 if (src.empty() || temp.empty())
 {
  cout << "打开图片失败" << endl;
  return 0;
 }

 vector<Mat> templat;
 vector<float> minV;
 vector<Point> minL;

 int srcW, srcH, templatW, templatH, resultH, resultW;
 srcW = src.cols;
 srcH = src.rows;
 templat.push_back(temp);
 double minValue, maxValue;
 Point minLoc, maxLoc;

 for (int i=0;i<10;i++)
 {
  cout << i << ": ";
  templatW = templat[i].cols;
  templatH = templat[i].rows;

  if (srcW < templatW || srcH < templatH)
  {
   cout << "模板不能比原图大" << endl;
   return 0;
  }

  resultW = srcW - templatW + 1;
  resultH = srcH - templatH + 1;

  result.create(Size(resultW, resultH), CV_32FC1);
  matchTemplate(src, templat[i], result, CV_TM_SQDIFF_NORMED);

  minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc);

  cout << "min1: " << minValue << endl;
  if (minValue<=0.070055)
  {
   rectangle(srcCopy, minLoc, Point(minLoc.x + templatW, minLoc.y + templatH), Scalar(0, 0, 255), 2, 8, 0);

   Point new_minLoc;
   new_minLoc = getNextMinLoc(result, minLoc, maxValue, templatW, templatH);

   float *data = result.ptr<float>(new_minLoc.y);

   cout << "min2: " << data[new_minLoc.x] << " ";
   if (data[new_minLoc.x]<=0.5)
   {
    cout << "进这个函数了:" << i << ":" << new_minLoc.x;
    cout << " " << new_minLoc.y;
    rectangle(srcCopy, new_minLoc, Point(new_minLoc.x + templatW, new_minLoc.y + templatH),
     Scalar(0, 255, 0), 2, 8, 0);
    new_minLoc = getNextMinLoc(result, new_minLoc, maxValue, templatW, templatH);
   }

   float *data1 = result.ptr<float>(new_minLoc.y);
   cout << "min3: " << data1[new_minLoc.x] << " " << endl;
   if (data1[new_minLoc.x] <= 0.4)
   {

    rectangle(srcCopy, new_minLoc, Point(new_minLoc.x + templatW, new_minLoc.y + templatH),
     Scalar(255, 0, 0), 2, 8, 0);
   }
  }
  cout << "#" << endl;
  Mat temp_templat;
  resize(templat[i], temp_templat, Size(templat[i].cols / 1.1, templat[i].rows / 1.1));
  templat.push_back(temp_templat);
 }

 imshow("结果", srcCopy);
 waitKey(0);
 return 0;
}

Point getNextMinLoc(Mat &result, Point minLoc, int maxValue, int templatW, int templatH)
{
 //imshow("result", result);
 //cout << "maxvalue: " << maxValue << endl;
 int startX = minLoc.x - templatW / 3;
 int startY = minLoc.y - templatH / 3;
 int endX = minLoc.x + templatW / 3;
 int endY = minLoc.y + templatH / 3;
 if (startX < 0 || startY < 0)
 {
  startX = 0;
  startY = 0;
 }
 if (endX > result.cols - 1 || endY > result.rows - 1)
 {
  endX = result.cols - 1;
  endY = result.rows - 1;
 }
 int y, x;
 for (y = startY; y < endY; y++)
 {
  for (x = startX; x < endX; x++)
  {
   float *data = result.ptr<float>(y);

   data[x] = maxValue;
  }
 }
 double new_minValue, new_maxValue;
 Point new_minLoc, new_maxLoc;
 minMaxLoc(result, &new_minValue, &new_maxValue, &new_minLoc, &new_maxLoc);
 //imshow("result_end", result);
 return new_minLoc;
}

以下是结果图:

到此这篇关于OpenCV-Python实现多模板匹配的文章就介绍到这了,更多相关OpenCV 多模板匹配内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • opencv模板匹配相同位置去除重复的框

    使用opencv自带的模板匹配 1.目标匹配函数:cv2.matchTemplate() res=cv2.matchTemplate(image, templ, method, result=None, mask=None) image:待搜索图像 templ:模板图像 result:匹配结果 method:计算匹配程度的方法,主要有以下几种: CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配:最好的匹配值为0:匹配越差,匹配值越大. CV_TM_CCORR 相关匹配法:该方法

  • OpenCV 模板匹配

    最近小编实现一个微信小程序「跳一跳」的自动化. 主要涉及到了OpenCV的模板匹配和边缘检测技术,以及Android开发调试工具ADB. 如果放在一起说,感觉内容有些多. 所以,分三期来讲,也能多了解一些东西. 首先介绍模板匹配,然后边缘检测,最后结合ADB实现「跳一跳」自动化. 游戏虽然过时了,但是拿来练练手还是不错的. 编程就该是快乐的,哈哈. / 01 / 模板匹配 模板匹配,就是在整个图像区域里发现与给定子图像相匹配的小块区域. 这里需要一个模板图像(给定的子图像)和一个待检测的图像(原

  • python基于OpenCV模板匹配识别图片中的数字

    前言 本博客主要实现利用OpenCV的模板匹配识别图像中的数字,然后把识别出来的数字输出到txt文件中,如果识别失败则输出"读取失败". 操作环境: OpenCV - 4.1.0 Python 3.8.1 程序目标 单个数字模板:(这些单个模板是我自己直接从图片上截取下来的) 要处理的图片: 终端输出: 文本输出: 思路讲解 代码讲解 首先定义两个会用到的函数 第一个是显示图片的函数,这样的话在显示图片的时候就比较方便了 def cv_show(name, img): cv2.imsh

  • Python和OpenCV进行多尺度模板匹配实现

    目录 1. 效果图 2. 原理 3. 步骤 4. 源码 5. 参考 这篇博文将实现如何将标准模板匹配扩展到多尺度,从而使其更加健壮.使其可以处理模板和输入图像大小不同的匹配. 1. 效果图 模板匹配问题:对于模板和图像中不一致的情况,会发生错误检测. 如下图左侧模板小,右侧图像中大,虽然完全一致,只是大小不一样,却未被检测到. 优化:多尺度模板匹配,对于模板和图像中有平移和缩放的情况可以完美工作. 如下图: 多尺度模板匹配,gif 详细效果图: 2. 原理 使用cv2.matchTemplate

  • Python+Opencv实现图像匹配功能(模板匹配)

    本文实例为大家分享了Python+Opencv实现图像匹配功能的具体代码,供大家参考,具体内容如下 1.原理 简单来说,模板匹配就是拿一个模板(图片)在目标图片上依次滑动,每次计算模板与模板下方的子图的相似度,最后就计算出了非常多的相似度: 如果只是单个目标的匹配,那只需要取相似度最大值所在的位置就可以得出匹配位置: 如果要匹配多个目标,那就设定一个阈值,就是说,只要相似度大于比如0.8,就认为是要匹配的目标. 1.1 相似度度量指标 差值平方和匹配 CV_TM_SQDIFF 标准化差值平方和匹

  • OpenCV-Python实现多模板匹配

    模板匹配的作用在图像识别领域作用可大了.那什么是模板匹配? 模板匹配,就是在一幅图像中寻找另一幅模板图像最匹配(也就是最相似)的部分的技术. 多模板匹配 在上一篇的实战中,我们通过人物眼睛的子图,找出了其在图像中出现位置.但是,有些情况下,并不仅仅只有一次,比如我们讲解傅里叶变换时,曾介绍一张草原的狮子图.如果匹配某个草,可能单个图像内会有很多,这个时候就要找出多个匹配结果. 而函数cv2.minMaxLoc()仅仅能找出最值,无法给出所有匹配区域的位置信息.所以,要想匹配多个结果,就需要进行如

  • python计算机视觉opencv图像金字塔轮廓及模板匹配

    目录 1.图像金字塔 ①高斯金字塔 ②拉普拉斯金字塔 2.图像轮廓 ①寻找轮廓 ②轮廓特征 ③轮廓绘制 3.模板匹配 ①模板匹配 ②匹配框线绘制 ③多对象匹配 4.直方图统计 ①直方图绘制 ②直方图统计 ③直方图的mask操作 ④直方图均衡化 5.傅里叶变换 1.图像金字塔 ①高斯金字塔 向下采样,数据会越来越少,减少的方式是:将偶数行和列删除 向上采样,数据会越来越多,将图像在每个方向上扩大为原来的两倍,新增的行和列用0来填充.使用先前同样的内核与放大后的图像卷积,获得近似值. 上采样之后,图

  • Python OpenCV实现图像模板匹配详解

    目录 1.什么是模板匹配及模板匹配方法matchTemplate() 介绍 素材准备 2.单模板匹配 2.1 单目标匹配 2.2 多目标匹配 3.多模板匹配 1.什么是模板匹配及模板匹配方法matchTemplate() 介绍 提供一个模板图像,一个目标图像,且满足模板图像是目标图像的一部分,从目标图像中寻找特定的模板图像的过程,即为模板匹配.OpenCV提供了matchTemplate()方法帮助我们实现模板匹配. 该方法语法如下: cv2.matchTemplate(image, templ

  • Python+Opencv实现图像模板匹配详解

    目录 引言 一.匹配方法 二.匹配单个对象 三.匹配多个对象 引言 什么是模板匹配呢? 看到这里大家是否会觉得很熟悉的感觉涌上心头!在人脸识别是不是也会看见 等等. 模板匹配可以看作是对象检测的一种非常基本的形式.使用模板匹配,我们可以使用包含要检测对象的“模板”来检测输入图像中的对象. 一.匹配方法 cv2.matchTemplate(img, templ, method) 参数:(img: 原始图像.temple: 模板图像.method: 匹配度计算方法) 方法如下: cv2.TM_SQD

  • Python开发之基于模板匹配的信用卡数字识别功能

    环境介绍 Python 3.6 + OpenCV 3.4.1.15 原理介绍 首先,提取出模板中每一个数字的轮廓,再对信用卡图像进行处理,提取其中的数字部分,将该部分数字与模板进行匹配,即可得到结果. 模板展示 完整代码 # !/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 2020/1/11 14:57 # @Author: Martin # @File: utils.py # @Software:PyCharm import cv2

随机推荐