• 企业400电话
  • 网络优化推广
  • AI电话机器人
  • 呼叫中心
  • 全 部 栏 目

    网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    OpenCV-Python实现多模板匹配
    POST TIME:2021-10-18 13:33

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

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

    多模板匹配

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

    而函数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;
     }
    
     vectorMat> templat;
     vectorfloat> minV;
     vectorPoint> 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;i10;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.ptrfloat>(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.ptrfloat>(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.ptrfloat>(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 多模板匹配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
    • opencv-python图像配准(匹配和叠加)的实现
    • Opencv Python实现两幅图像匹配
    • Python使用Opencv实现图像特征检测与匹配的方法
    • Python和OpenCV进行多尺度模板匹配实现
    • OpenCV-Python模板匹配人眼的实例
    • python基于OpenCV模板匹配识别图片中的数字
    • Python开发之基于模板匹配的信用卡数字识别功能
    • Python+Opencv实现图像匹配功能(模板匹配)
    上一篇:OpenCV-Python使用分水岭算法实现图像的分割与提取
    下一篇:OpenCV-Python实现凸包的获取
  • 相关文章
  • 

    关于我们 | 付款方式 | 荣誉资质 | 业务提交 | 代理合作


    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    X

    截屏,微信识别二维码

    微信号:veteran88

    (点击微信号复制,添加好友)

     打开微信