OpenCV2马拉松第13圈——模版匹配

收入囊中

http://blog.csdn.net/abcd1992719g/article/details/25505315这里,我们已经学习了如何利用反向投影和meanshift算法来在图像中查找给定模版图片的位置。meanshift针对的是单张图像,在连续图像序列的跟踪中,camshift(Continuously
Adaptive Mean-SHIFT)是一种著名的算法。但在这里,我们先不讨论camshift,而是先讨论最简单的模版匹配。

  • 模版匹配算法
  • opencv normalize函数
  • opencv matchTemplate函数
  • opencv minMaxLoc函数

其中,normalize归一化函数和minMaxLoc函数我们以前用过,在本节将详细阐述他们的用法。

葵花宝典

本节的算法也是属于比较简单的。

我们举个例子:下面分别是源图像和模版图像

站在最单纯的角度,你会怎么做?

毫无疑问,我们要找到一个标准来衡量,square error是最普遍简单的.

步骤:

  1. 遍历图像的所有点
  2. 对于一个点(m,n),计算square error.也就是遍历模版图像的长和高,计算sum( (src(m+x,n+y)-template(x,y))^2 )
  3. 遍历完后,就有了一个和原图大小相等的square error(不考虑边缘)矩阵,然后取出值最小的那个位置

OpenCV就是这么做的,只不过它提供了6种方法(其实是3种,另外3种只不过多了归一化),square error是其中一种

初识API

循环遍历计算的过程OpenCV帮我们做了,matchTemplate

C++: void matchTemplate(InputArray image,
InputArray templ, OutputArray result, int method)
 
  • image – 输入图像
  • templ – 模版图像,不能比输入图像大,类型要和输入图像一致
  • result – 输出的结果,单通道32位浮点数.result图像比输入图像要小,因为考虑了边界.If image is  and templ is  ,
    thenresult is  .
  • method – 有6种方法

method=CV_TM_SQDIFF

  • method=CV_TM_SQDIFF_NORMED

  • method=CV_TM_CCORR

  • method=CV_TM_CCORR_NORMED

  • method=CV_TM_CCOEFF

    where

  • method=CV_TM_CCOEFF_NORMED

NOTE:之前我们用square error时,值越小说明越匹配,但是并不是上面所有的方法都是这样子.

R越小越匹配 (when CV_TM_SQDIFF was
used)

R越大越匹配 (whenCV_TM_CCORR or CV_TM_CCOEFF was
used)

归一化?normalize

我们发现,上面3种是没有归一化的,也就是result可能会是一个值很大的矩阵,几万几十万,imshow是一片黑乎乎。如果我们想看效果,就必须要做归一化了.

C++: void normalize(InputArray src,
OutputArray dst, double alpha=1,
double beta=0, int norm_type=NORM_L2,
int dtype=-1, InputArraymask=noArray() )

假设我有[1,4,5,6,7,10]的矩阵,我们先看3种归一化类型

L1_norm: 每個元素乘上1/sqrt(1+4+5+6+7+10)

L2_norm: 每個元素乘上1/sqrt(1+16+25+36+49+100)

NORM_MINMAX:使每個元素限制在[a=5,b=0]之間算法如下:dst(i)=(src(i)-min(src))*(5-0)/(max(src)-min(src))

1-->0

4-->3*5/9=1.6666

5-->4*5/9=2.2222

比较常用的还是MinMAX,OpenCV默认使用NORM_L2

在使用L1_norm,L2_norm时,alpha,beta就没效果了.

在使用NORM_MINMAX时候,alpha,beta就是你要缩放的范围,我发现两个值换一下没关系,大概OpenCV帮我们判断了大小。

找到最大最小值,minMaxLoc

double minVal; double maxVal; Point minLoc; Point maxLoc;

minMaxLoc( image, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );

the function calls as arguments:

  • image: 输入图像
  • &minVal and &maxVal: Variables to save the minimum and maximum values in result
  • &minLoc and &maxLoc: The Point locations of the minimum and maximum values in the array.
  • Mat(): Optional mask

荷枪实弹

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

Mat img; Mat templ; Mat result;
const char* image_window = "Source Image";
const char* result_window = "Result window";

int match_method;
int max_Trackbar = 5;

void MatchingMethod( int, void* );

int main( int, char** argv )
{
  /// Load image and template
  img = imread( argv[1], 1 );
  templ = imread( argv[2], 1 );

  /// Create windows
  namedWindow( image_window, CV_WINDOW_AUTOSIZE );
  namedWindow( result_window, CV_WINDOW_AUTOSIZE );

  /// Create Trackbar
  const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
  createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );

  MatchingMethod( 0, 0 );

  waitKey(0);
  return 0;
}

void MatchingMethod( int, void* )
{
  Mat img_display;
  img.copyTo( img_display );

  //重要,调用模版匹配再进行归一化
  matchTemplate( img, templ, result, match_method );
  normalize( result, result, 0, 1, NORM_MINMAX);

  double minVal; double maxVal; Point minLoc; Point maxLoc;
  Point matchLoc;
  //找到最大最小点
  minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );

  //根据我前面讲的,分方法取最大还是最小值
  if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    { matchLoc = minLoc; }
  else
    { matchLoc = maxLoc; }

  //画上矩形框框
  rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
  rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );

  imshow( image_window, img_display );
  imshow( result_window, result );

  return;
}

举一反三

有时候,图像中要有多个匹配的地方,这时候就不能只用一次minMaxLoc来解决了,可以去遍历我们的结果矩阵.

计算机视觉讨论群:162501053

转载请注明:http://blog.csdn.net/abcd1992719g

OpenCV2马拉松第13圈——模版匹配,布布扣,bubuko.com

时间: 2024-12-27 10:27:29

OpenCV2马拉松第13圈——模版匹配的相关文章

OpenCV2马拉松第10圈——直方图反向投影(back project)

收入囊中 灰度图像的反向投影 彩色图像的反向投影 利用反向投影做object detect 葵花宝典 什么是反向投影?事实上没有那么高大上! 在上一篇博文学到,图像能够获得自己的灰度直方图. 反向投影差点儿相同是逆过程,由直方图得到我们的投影图. 步骤例如以下: 依据模版图像,得到模版图像的灰度直方图. 对灰度直方图对归一化,归一化后是个概率分布,直方图的积分是1 依据概率分布的直方图,求输入图像的投影图,也就是对每个像素点,我们依据灰度值,能够得到其概率 得到的投影图是介于[0,1]之间的,为

OpenCV2马拉松第27圈——SIFT论文,原理及源码解读

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/28913101 简介 SIFT特征描述子是David G. Lowe 在2004年的ijcv会议上发表的论文中提出来的,论文名为<<Distinctive Image Featuresfrom Scale-Invariant Keypoints>>.这是一个很强大的算法,主要用于图像配准和物体识别等领域,但是其计算量相比也比较大,性价

OpenCV2马拉松第8圈——绘制直方图

收入囊中 灰度直方图 彩色直方图 葵花宝典 直方图的理论还是非常丰富的,应用也很多,诸如: 直方图均衡化 直方图匹配(meanshift,camshift) 在这里,我先介绍基础,如何绘制图像的直方图. 拿灰度图像来说,直方图就是不同的灰度对应的个数,横轴(x)就是[0,256), 纵轴(y)就是对应的个数 如下图,分别是灰度直方图和彩色直方图 初识API C++: void calcHist(const Mat* images, int nimages, const int* channels

OpenCV2马拉松第26圈——FAST特征点检测

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/28424579 关于角点检测,我写过两篇文章 openCV2马拉松第19圈--Harris角点检测(自己实现) OpenCV2马拉松第21圈--形态学操作实现角点检测 有兴趣的童鞋可以去看看--- 收入囊中 FAST角点检测原理 使用OpenCV  FAST API检测角点 葵花宝典 对于一个角点来说,应该与周围的大多数像素点有很大的差别 如上图,

OpenCV2马拉松第15圈——边缘检測(Laplace算子,LOG算子)

收入囊中 拉普拉斯算子 LOG算子(高斯拉普拉斯算子) OpenCV Laplacian函数 构建自己的拉普拉斯算子 利用拉普拉斯算子进行图像的锐化 葵花宝典 在OpenCV2马拉松第14圈--边缘检測(Sobel,prewitt,roberts)  我们已经认识了3个一阶差分算子 拉普拉斯算子是二阶差分算子.为什么要增加二阶的算子呢?试想一下,假设图像中有噪声,噪声在一阶导数处也会取得极大值从而被当作边缘.然而求解这个极大值也不方便.採用二阶导数后,极大值点就为0了.因此值为0的地方就是边界.

OpenCV2马拉松第12圈——直方图比較

收入囊中 使用4种不同的方法进行直方图比較 葵花宝典 要比較两个直方图, 首先必需要选择一个衡量直方图相似度的对照标准.也就是先说明要在哪个方面做对照. 我们能够想出非常多办法,OpenCV採用了下面4种 公式也都不难,我们自己就能实现. d越小,表示差异越低,两幅图像越接近,越相似 初识API C++: double compareHist(InputArray H1, InputArray H2, int method) C++: double compareHist(const Spars

OpenCV2马拉松第16圈——边缘检测(形态学梯度)

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g 收入囊中 利用OpenCV函数进行形态学梯度操作 自定义结构矩阵进行形态学梯度操作 葵花宝典 在此之前,如果你还没接触过灰度图像形态学膨胀与腐蚀,希望你能仔细阅读灰度图像形态学膨胀与腐蚀 本质上,灰度与二值并不差异,二值不过是0与255,膨胀与腐蚀的操作都是一样的 形态学梯度的定义如下: 形态梯度 dst=morph_grad(src,element)=dilate(src,ele

OpenCV2马拉松第17圈——边缘检测(Canny边缘检测)

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g 收入囊中 利用OpenCV Canny函数进行边缘检测 掌握Canny算法基本理论 分享Java的实现 葵花宝典 在此之前,我们先阐述一下canny检测的算法.总共分为4部分. (1)处理噪声 一般用高斯滤波.OpenCV使用如下核 (2)计算梯度幅值 先用如下Sobel算子计算出水平和竖直梯度 我在OpenCV2马拉松第14圈--边缘检测(Sobel,prewitt,robert

OpenCV2马拉松第14圈——边缘检测(Sobel,prewitt,roberts)

收入囊中 差分在边缘检测的角色 Sobel算子 OpenCV sobel函数 OpenCV Scharr函数 prewitt算子 Roberts算子 葵花宝典 差分在边缘检测到底有什么用呢?先看下面的图片 作为人,我们可以很容易发现图中红圈有边界,边界处肯定是非常明显,变化陡峭的,在数学中,什么可以表示变化的快慢,自然就是导数,微分了. 想像有如下的一维图片. 红圈处变化最陡峭,再看导数图 红圈在最高值,也就是导数可以很好表示边缘,因为变化很剧烈 图像中的Sobel算子 是离散差分算子. 结合了