java opencv 模板匹配算法_OpenCV模板匹配算法详解

本文介绍了OpenCV中的模板匹配算法,包括理论介绍和6种匹配方法,重点讲述了归一化相关系数匹配法,并提供了Python示例代码。还深入解析了OpenCV0.9.5版本的模板匹配源码,帮助理解算法实现细节。
摘要由CSDN通过智能技术生成

http://www.cnblogs.com/zhaoweiwei/p/OpenVC_matchTemplate.html1 理论介绍

模板匹配是在一幅图像中寻找一个特定目标的方法之一,这种方法的原理非常简单,遍历图像中的每一个可能的位置,比较各处与模板是否“相似”,当相似度足够高时,就认为找到了我们的目标。OpenCV提供了6种模板匹配算法:平方差匹配法CV_TM_SQDIFF

归一化平方差匹配法CV_TM_SQDIFF_NORMED

相关匹配法CV_TM_CCORR

归一化相关匹配法CV_TM_CCORR_NORMED

相关系数匹配法CV_TM_CCOEFF

归一化相关系数匹配法CV_TM_CCOEFF_NORMED

用T表示模板图像,I表示待匹配图像,切模板图像的宽为w高为h,用R表示匹配结果,匹配过程如下图所示:

b22636f4a6755f6ef7e48d9968707c7c.png

上述6中匹配方法可用以下公式进行描述:

2d0d2a932244d815618f10314ea296f4.png

2 示例代码

下面给出方法6的python代码

cdec0645add3fc3c328197dda5c76203.png 归一化相关系数匹配法

代码58行中的N就是公式(6)中的w*h,由于python代码运行速度比较慢,代码的58、59行相当于对公式(6)的分子分母都进行了平方操作,并且分子分母都乘以了N方,以减小计算量,所以代码61行的ret相当于公式(6)中的R(x,y)的平方,

为了更快的进行算法验证,用上述代码进行验证时请尽量选用较小的匹配图像及模板图像,下图显示了我的匹配结果(待匹配图像295x184模板69x46用了十几分钟):

1c95b1db85f563aa18152226b562b644.png

3 OpenCV源码

较新版本的OpenCV库中的模板匹配已经进行了较多的算法改进,直接看新版本中的算法需要了解很多相关理论知识,所以我们结合OpenCV0.9.5的源码进行讲解,该版本的源码基本上是C风格代码更容易进行理解(如果要对

OpenCV源码进行研究,建议用该版本进行入门),仍以归一化相关系数匹配法为例进行分析。

69c5a8ac3fa60e0848d784a6dd461da6.png1 /* 2 * pImage: 待匹配图像3 * image: 待匹配图像宽(width*depth并已4字节对齐)4 * roiSize: 待匹配图像尺寸5 * pTemplate: 模板图像6 * templStep: 模板图像宽7 * templSize: 模板图像尺寸8 * pResult: 匹配结果9 * resultStep: 匹配结果宽10 * pBuffer: 中间结果数据缓存11 */ 12 IPCVAPI_IMPL( CvStatus, icvMatchTemplate_CoeffNormed_32f_C1R,13 (const float *pImage, intimageStep, CvSize roiSize,14 const float *pTemplate, inttemplStep, CvSize templSize,15 float *pResult, int resultStep, void *pBuffer) )16 {17 float *imgBuf = 0; //待匹配图像相关数据 18 float *templBuf = 0; //模板图像数据 19 double *sumBuf = 0; //待匹配图像遍历块单行和 20 double *sqsumBuf = 0; //待匹配图像遍历块单行平方和 21 double *resNum = 0; //模板图像和待匹配图像遍历块内积 22 double *resDenom = 0; //待匹配图像遍历块累加和及待匹配图像遍历块平方累加和 23 double templCoeff = 0; //模板图像均分差倒数 24 double templSum = 0; //模板图像累加和 25 26 int winLen = templSize.width *templSize.height;27 double winCoeff = 1. / (winLen + DBL_EPSILON); //+ DBL_EPSILON 加一个小整数防止分母为零 28 29 CvSize resultSize = cvSize( roiSize.width - templSize.width + 1,30 roiSize.height - templSize.height + 1);31 intx, y;32 33 //计算并为imgBuf、templBuf、sumBuf、sqsumBuf、resNum、resDenom分配存储空间 34 CvStatus result =icvMatchTemplateEntry( pImage, imageStep, roiSize,35 pTemplate, templStep, templSize,36 pResult, resultStep, pBuffer,37 cv32f, 1, 1,38 (void **) &imgBuf, (void **) &templBuf,39 (void **) &sumBuf, (void **) &sqsumBuf,40 (void **) &resNum, (void **) &resDenom );41 42 if( result !=CV_OK )43 returnresult;44 45 imageStep /=sizeof_float;46 templStep /=sizeof_float;47 resultStep /=sizeof_float;48 49 /*calc common statistics for template and image*/ 50 {51 const float *rowPtr = (const float *) imgBuf;52 double templSqsum = icvCrossCorr_32f_C1( templBuf, templBuf, winLen ); //模板图像平方累加和 53 54 templSum = icvSumPixels_32f_C1( templBuf, winLen ); //模板图像累加和 55 templCoeff = (double) templSqsum - ((double) templSum) * templSum * winCoeff; //模板图像均方差的平方 56 templCoeff = icvInvSqrt64d( fabs( templCoeff ) + FLT_EPSILON ); //模板图像均方差倒数 57 58 for( y = 0; y < roiSize.height; y++, rowPtr +=templSize.width )59 {60 sumBuf[y] = icvSumPixels_32f_C1( rowPtr, templSize.width ); //待匹配图像按模板图像宽度求每行之和(遍历位置第一列) 61 sqsumBuf[y] = icvCrossCorr_32f_C1( rowPtr, rowPtr, templSize.width ); //待匹配图像按模板图像宽度求每行平方之和(遍历位置第一列) 62 }63 }64 65 /*main loop - through x coordinate of the result*/ 66 for( x = 0; x < resultSize.width; x++)67 {68 double sum = 0;69 double sqsum = 0;70 float *imgPtr = imgBuf + x; //待匹配图像起始位置 71 72 /*update sums and image band buffer*/ //如果不是第1列需重新更新sumBuf,更新后sumBuf为遍历位置第x列每行之和(行宽为模板图像宽) 73 if( x > 0)74 {75 const float *src = pImage + x + templSize.width - 1;76 float *dst = imgPtr - 1;77 float out_val = dst[0];78 79 dst +=templSize.width;80 81 for( y = 0; y < roiSize.height; y++, src += imageStep, dst +=templSize.width )82 {83 float in_val = src[0];84 85 sumBuf[y] += in_val -out_val;86 sqsumBuf[y] += (in_val - out_val) * (in_val +out_val);87 out_val = dst[0];88 dst[0] = (float) in_val;89 }90 }91 92 for( y = 0; y < templSize.height; y++ ) //求遍历位置第x列,第1行处遍历块累加和sum及平方累加和sqsum 93 {94 sum +=sumBuf[y];95 sqsum +=sqsumBuf[y];96 }97 98 for( y = 0; y < resultSize.height; y++, imgPtr +=templSize.width )99 {100 double res = icvCrossCorr_32f_C1( imgPtr, templBuf, winLen ); //求模板图像和待匹配图像y行x列处遍历块的内积 101 102 if( y > 0 ) //如果不是第1行需更新遍历块累加和sum及平方累加和sqsum 103 {104 sum -= sumBuf[y - 1];105 sum += sumBuf[y + templSize.height - 1];106 sqsum -= sqsumBuf[y - 1];107 sqsum += sqsumBuf[y + templSize.height - 1];108 }109 resNum[y] =res;110 resDenom[y] =sum;111 resDenom[y + resultSize.height] =sqsum;112 }113 114 for( y = 0; y < resultSize.height; y++)115 {116 double sum = ((double) resDenom[y]);117 double wsum = winCoeff *sum;118 double res = ((double) resNum[y]) - wsum *templSum;119 double nrm_s = ((double) resDenom[y + resultSize.height]) - wsum *sum;120 121 res *= templCoeff * icvInvSqrt64d( fabs( nrm_s ) +FLT_EPSILON );122 pResult[x + y * resultStep] = (float) res;123 }124 }125 126 returnCV_OK;127 }

69c5a8ac3fa60e0848d784a6dd461da6.png

以上代码是归一化相关系数法核心函数icvMatchTemplate_CoeffNormed_32f_C1R的源码,我已经在源码中进行了详细的注释,读者需自己再进行理解,需要进一步说明的是:

代码118行res就是计算公式(6)的分子部分,代码56行templCoeff就是计算公式(6)分母的左半部分,代码121行icvInvSqrt64d函数就是在计算公式(6)分母的右半部分,该行res的最终结果正是公式(6)中的R(x,y)。

4 结束语

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值