模板匹配—归一化相关系数匹配算法

模板匹配—归一化相关系数匹配算法_第1张图片
模板匹配—归一化相关系数匹配算法_第2张图片
python代码:

1 import numpy as np
 2 import cv2
 3 
 4 def EM(pModel, width, height):
 5     sum = np.double(0.0)
 6     for i in range(0,height):
 7         for j in range(0,width):
 8             sum += pModel[i][j]
 9     return sum
10 
11 def EM2(pModel, width, height):
12     sum = np.double(0.0)
13     for i in range(0,height):
14         for j in range(0,width):
15             sum += pModel[i][j]*1.0*pModel[i][j]
16     return sum
17 
18 def EI(pToSearch, l, h, u, v, pModel, width, height):
19     sum = np.double(0.0)
20     roi = pToSearch[v:v+height, u:u+width]
21     for i in range(0,height):
22         for j in range(0,width):
23             sum += roi[i][j]
24     return sum
25 
26 def EI2(pToSearch, l, h, u, v, pModel, width, height):
27     sum = np.double(0.0)
28     roi = pToSearch[v:v+height, u:u+width]
29     for i in range(0,height):
30         for j in range(0,width):
31             sum += roi[i][j]*1.0*roi[i][j]
32     return sum
33 
34 def EIM(pToSearch, l, h, u, v, pModel, width, height):
35     sum = np.double(0.0)
36     roi = pToSearch[v:v+height, u:u+width]
37     for i in range(0,height):
38         for j in range(0,width):
39             sum += pModel[i][j]*1.0*roi[i][j]
40     return sum
41 
42 def Match(pToSearch, l, h, pModel, width, height):
43     uMax = l-width
44     vMax = h-height
45     N = width*height
46     len = (uMax+1)*(vMax+1)
47     MatchRec = [0.0 for x in range(0, len)]
48     k = 0
49 
50     M = EM(pModel,width,height)
51     M2 = EM2(pModel,width,height)
52     for p in range(0, uMax+1):
53         for q in range(0, vMax+1):
54             I = EI(pToSearch,l,h,p,q,pModel,width,height)
55             I2 = EI2(pToSearch,l,h,p,q,pModel,width,height)
56             IM = EIM(pToSearch,l,h,p,q,pModel,width,height)
57 
58             numerator=(N*IM-I*M)*(N*IM-I*M)
59             denominator=(N*I2-I*I)*(N*M2-M*M)
60 
61             ret = numerator/denominator
62             MatchRec[k]=ret
63             k+=1
64 
65     val = 0
66     k = 0
67     x = y = 0
68     for p in range(0, uMax+1):
69         for q in range(0, vMax+1):
70             if MatchRec[k] > val:
71                 val = MatchRec[k]
72                 x = p
73                 y = q
74             k+=1
75     print "val: %f"%val
76     return (x, y)
77 
78 def main():
79     img = cv2.imread('niu.jpg', cv2.IMREAD_GRAYSCALE)
80     temp = cv2.imread('temp.png', cv2.IMREAD_GRAYSCALE)
81 
82     print temp.shape
83     imgHt, imgWd = img.shape
84     tempHt, tempWd = temp.shape
85     #print EM(temp, tempWd, tempHt)
86     (x, y) = Match(img, imgWd, imgHt, temp, tempWd, tempHt)
87     cv2.rectangle(img, (x, y), (x+tempWd, y+tempHt), (0,0,0), 2)
88     cv2.imshow("temp", temp)
89     cv2.imshow("result", img)
90     cv2.waitKey(0)
91     cv2.destroyAllWindows()
92 
93 if __name__ == '__main__':
94     main()

归一化相关系数匹配法

模板匹配—归一化相关系数匹配算法_第3张图片
在这里插入图片描述

/*
* pImage: 待匹配图像
* image: 待匹配图像宽(width*depth并已4字节对齐)
* roiSize: 待匹配图像尺寸
* pTemplate: 模板图像
* templStep: 模板图像宽
* templSize: 模板图像尺寸
* pResult: 匹配结果
* resultStep: 匹配结果宽
* pBuffer: 中间结果数据缓存
*/
IPCVAPI_IMPL( CvStatus, icvMatchTemplate_CoeffNormed_32f_C1R,
              (const float *pImage, int imageStep, CvSize roiSize,
               const float *pTemplate, int templStep, CvSize templSize,
               float *pResult, int resultStep, void *pBuffer) )
{
    float *imgBuf = 0;              // 待匹配图像相关数据
    float *templBuf = 0;            // 模板图像数据
    double *sumBuf = 0;             // 待匹配图像遍历块单行和
    double *sqsumBuf = 0;           // 待匹配图像遍历块单行平方和
    double *resNum = 0;             // 模板图像和待匹配图像遍历块内积
    double *resDenom = 0;           // 待匹配图像遍历块累加和及待匹配图像遍历块平方累加和
    double templCoeff = 0;          // 模板图像均分差倒数
    double templSum = 0;            // 模板图像累加和

    int winLen = templSize.width * templSize.height;
    double winCoeff = 1. / (winLen + DBL_EPSILON);          // + DBL_EPSILON 加一个小整数防止分母为零

    CvSize resultSize = cvSize( roiSize.width - templSize.width + 1,
                                roiSize.height - templSize.height + 1 );
    int x, y;

    // 计算并为imgBuf、templBuf、sumBuf、sqsumBuf、resNum、resDenom分配存储空间
    CvStatus result = icvMatchTemplateEntry( pImage, imageStep, roiSize,
                                             pTemplate, templStep, templSize,
                                             pResult, resultStep, pBuffer,
                                             cv32f, 1, 1,
                                             (void **) &imgBuf, (void **) &templBuf,
                                             (void **) &sumBuf, (void **) &sqsumBuf,
                                             (void **) &resNum, (void **) &resDenom );

    if( result != CV_OK )
        return result;

    imageStep /= sizeof_float;
    templStep /= sizeof_float;
    resultStep /= sizeof_float;

    /* calc common statistics for template and image */
    {
        const float *rowPtr = (const float *) imgBuf;
        double templSqsum = icvCrossCorr_32f_C1( templBuf, templBuf, winLen );          // 模板图像平方累加和

        templSum = icvSumPixels_32f_C1( templBuf, winLen );                             // 模板图像累加和
        templCoeff = (double) templSqsum - ((double) templSum) * templSum * winCoeff;   // 模板图像均方差的平方
        templCoeff = icvInvSqrt64d( fabs( templCoeff ) + FLT_EPSILON );                 // 模板图像均方差倒数

        for( y = 0; y < roiSize.height; y++, rowPtr += templSize.width )
        {
            sumBuf[y] = icvSumPixels_32f_C1( rowPtr, templSize.width );                 // 待匹配图像按模板图像宽度求每行之和(遍历位置第一列)
            sqsumBuf[y] = icvCrossCorr_32f_C1( rowPtr, rowPtr, templSize.width );       // 待匹配图像按模板图像宽度求每行平方之和(遍历位置第一列)
        }
    }

    /* main loop - through x coordinate of the result */
    for( x = 0; x < resultSize.width; x++ )
    {
        double sum = 0;
        double sqsum = 0;
        float *imgPtr = imgBuf + x;                                                      // 待匹配图像起始位置

        /* update sums and image band buffer */                                          // 如果不是第1列需重新更新sumBuf,更新后sumBuf为遍历位置第x列每行之和(行宽为模板图像宽)
        if( x > 0 )
        {
            const float *src = pImage + x + templSize.width - 1;
            float *dst = imgPtr - 1;
            float out_val = dst[0];

            dst += templSize.width;

            for( y = 0; y < roiSize.height; y++, src += imageStep, dst += templSize.width )
            {
                float in_val = src[0];

                sumBuf[y] += in_val - out_val;
                sqsumBuf[y] += (in_val - out_val) * (in_val + out_val);
                out_val = dst[0];
                dst[0] = (float) in_val;
            }
        }

        for( y = 0; y < templSize.height; y++ )                                          // 求遍历位置第x列,第1行处遍历块累加和sum及平方累加和sqsum
        {
            sum += sumBuf[y];
            sqsum += sqsumBuf[y];
        }

        for( y = 0; y < resultSize.height; y++, imgPtr += templSize.width )
        {
            double res = icvCrossCorr_32f_C1( imgPtr, templBuf, winLen );               // 求模板图像和待匹配图像y行x列处遍历块的内积

            if( y > 0 )                                                                 // 如果不是第1行需更新遍历块累加和sum及平方累加和sqsum
            {
                sum -= sumBuf[y - 1];
                sum += sumBuf[y + templSize.height - 1];
                sqsum -= sqsumBuf[y - 1];
                sqsum += sqsumBuf[y + templSize.height - 1];
            }
            resNum[y] = res;
            resDenom[y] = sum;
            resDenom[y + resultSize.height] = sqsum;
        }

        for( y = 0; y < resultSize.height; y++ )
        {
            double sum = ((double) resDenom[y]);
            double wsum = winCoeff * sum;
            double res = ((double) resNum[y]) - wsum * templSum;
            double nrm_s = ((double) resDenom[y + resultSize.height]) - wsum * sum;

            res *= templCoeff * icvInvSqrt64d( fabs( nrm_s ) + FLT_EPSILON );
            pResult[x + y * resultStep] = (float) res;
        }
    }

    return CV_OK;
}

在这里插入图片描述
转自:模板匹配算法详细解说

你可能感兴趣的:(算法,机器视觉,算法,opencv,计算机视觉,边缘检测,cv)