1. 程式人生 > >影象處理中的模板匹配c++實現

影象處理中的模板匹配c++實現

一、理論基礎

  • 基於相關的模板匹配技術可直接用於在一幅影象中,尋找某種子影象模式。對於大小為MxN的影象f(x,y)和大小為JxK的子影象模式w(x,y),f與w的相關可表示為:

這裡寫圖片描述

  • 其種,x=0,1,2,…N-K,y=0,1,2,…M-J。此處
    的目的是尋找匹配而不是對f(x,y)進行濾波操作,因此w的原點被設定在子影象的左上角,
    並且式(11-3) 給出的形式也完全適用於J和K 為偶數的情況。

  • 計算相關c(x,y)的過程就是在影象f(x,y)中逐點地移動子影象w(x,小),使w 的原點和點
    (x,y)重合,然後計算w與f中被w覆蓋的影象區域對應畫素的乘積之和,以此計算結果作
    為相關影象c(x,)在(x,y)點的響應。

  • 相關可用於在影象f(x,y)中找到與子影象w(x,y)匹配的所有位置。實際上,當w 按照上
    段中描述的過程移過整幅影象f之後,最大的響應點(xo,yo)即為最佳匹配的左上角點。我們
    也可以設定一個閾值T,認為響應值大於該閾值的點均是可能的匹配位置。

  • 相關的計算是通過將影象元素和子模式影象元素聯絡起來獲得的,將相關元素相乘後累
    加。我們完全可以將子影象w視為一個按行或按列儲存的向量這裡寫圖片描述,將計算過程中被w覆蓋的影象區域視為另一個按照同樣的方式儲存的向量這裡寫圖片描述.這樣一來,相關計算就- 成了向量之間的點積運算。

兩個向量的點積為:
這裡寫圖片描述

  • 其中,Θ 為向量這裡寫圖片描述這裡寫圖片描述之間的夾角。顯然,當這裡寫圖片描述
    這裡寫圖片描述具有完全相同的方向(平行) 時,這裡寫圖片描述,從而式(11-4) 取得其最大值這裡寫圖片描述,這就意味著當影象的區域性區域類似於子影象模式時,相關運算產生最大的響應。然而,式(11-4) 最終的取值還與向量這裡寫圖片描述這裡寫圖片描述自身的模有關,這將導致按照式(11-4) 計算的相關響應存在著對f和w 的灰度幅值比較敏感的缺陷。這樣一來,在f的高灰度區域,可能儘管其內容與子影象w的內容並不相近,但由於這裡寫圖片描述自身較大而同樣產生一個很高的響應。可通過對向量以其模值來歸一化解決這一問題,即通過來計算。
    這裡寫圖片描述

改進的用於匹配的相關計算公式如下:
這裡寫圖片描述

二、程式碼部分

  • 看了腦疼的理論,下面看看讓人愉快的程式碼吧。

TemplateMatch.h

#pragma once
#include<opencv2\opencv.hpp>
using namespace cv;
typedef unsigned char BYTE;
void TemplateMatch(Mat * pTo, Mat * pTemplate,Mat * src);

TemplateMatch.cpp

 #include"TemplateMatch.h"

void TemplateMatch(Mat * pTo, Mat * pTemplate, Mat * src)
{

    //迴圈變數
    int i, j, m, n;

    double dSumT; //模板元素的平方和
    double dSumS; //影象子區域元素的平方和
    double dSumST; //影象子區域和模板的點積    

                   //響應值
    double R;

    //記錄當前的最大響應
    double MaxR;

    //最大響應出現位置
    int nMaxX;
    int nMaxY;

    int nHeight = src->rows;
    int nWidth = src->cols;
    //模板的高、寬
    int nTplHeight = pTemplate->rows;
    int nTplWidth = pTemplate->cols;

    //計算 dSumT
    dSumT = 0;
    for (m = 0; m < nTplHeight; m++)
    {
        for (n = 0; n < nTplWidth; n++)
        {
            // 模板影象第m行,第n個象素的灰度值
            int nGray =*pTemplate->ptr(m, n);

            dSumT += (double)nGray*nGray;
        }
    }

    //找到影象中最大響應的出現位置
    MaxR = 0;
    for (i = 0; i < nHeight - nTplHeight + 1; i++)
    {
        for (j = 0; j < nWidth - nTplWidth + 1; j++)
        {
            dSumST = 0;
            dSumS = 0;

            for (m = 0; m < nTplHeight; m++)
            {
                for (n = 0; n < nTplWidth; n++)
                {
                    // 原影象第i+m行,第j+n列象素的灰度值
                    int nGraySrc = *src->ptr(i + m, j + n);

                    // 模板影象第m行,第n個象素的灰度值
                    int nGrayTpl = *pTemplate->ptr(m, n);

                    dSumS += (double)nGraySrc*nGraySrc;
                    dSumST += (double)nGraySrc*nGrayTpl;
                }
            }

            R = dSumST / (sqrt(dSumS)*sqrt(dSumT));//計算相關響應

            //與最大相似性比較
            if (R > MaxR)
            {
                MaxR = R;
                nMaxX = j;
                nMaxY = i;
            }
        }
    }

    //將找到的最佳匹配區域複製到目標影象
    for (m = 0; m < nTplHeight; m++)
    {
        for (n = 0; n < nTplWidth; n++)
        {
            int nGray = *src->ptr(nMaxY + m, nMaxX + n);
            //pTo->setTo(nMaxX + n, nMaxY + m, RGB(nGray, nGray, nGray));
            pTo->at<BYTE>(nMaxY + m, nMaxX + n) = nGray;
        }
    }

}   

測試程式碼

#include"TemplateMatch.h"
#include<iostream>

using namespace std;
int main()
{
    Mat src = imread("./src.jpg", 0);
    Mat Template = imread("./template.jpg", 0);
    Mat pt=src;
    pt.data = new BYTE[src.cols*src.rows];
    memset(pt.data, 255, src.cols*src.rows);
    TemplateMatch(&pt, &Template, &src);
    imshow("S", src);
    imshow("T", Template);
    imshow("P", pt);

    imwrite("S.jpg", src);
    imwrite("T.jpg", Template);
    imwrite("P.jpg", pt);
    waitKey(0);
    return 0;
}

效果如下:
這裡寫圖片描述

    下面給出這個工程的百度雲連線:連結:http://pan.baidu.com/s/1jIuuT3w 密碼:veto

寫的不好的地方,還希望指正,O(∩_∩)O謝謝。
在這我要強烈推薦一本書:《數字影象處理與機器視覺 Visual C 與Matlab實現》,這本書寫的很基礎,適合初學者和研究人員