OpenCV探索之路(九):模板匹配

模板匹配的做用在圖像識別領域做用可大了。那什麼是模板匹配?ios

模板匹配,就是在一幅圖像中尋找另外一幅模板圖像最匹配(也就是最類似)的部分的技術。算法

說的有點抽象,下面給個例子說明就很明白了。函數

在上面這幅全明星照中,咱們想找出姚明頭像的位置,並把它標記出來,能夠作到嗎?
測試

能夠,這就是模板匹配的要作的事情。ui

其實模板匹配實現的思想也是很簡單很暴力的,就是拿着模板圖片(姚明頭像)在原圖(全明星照)中從左上至右下依次滑動,直到遇到某個區域的類似度低於咱們設定的閾值,那麼咱們就認爲該區域與模板匹配了,也就是咱們找到了姚明的位置,並把它標記出來。spa

OpenCV中是經過MtachTemplate函數完成。code

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

using namespace std;
using namespace cv;

int main()
{
    Mat img, templ, result;
    img = imread("nba.jpg");
    templ = imread("76.png");

    int result_cols = img.cols - templ.cols + 1;
    int result_rows = img.rows - templ.rows + 1;
    result.create(result_cols, result_rows, CV_32FC1);

    matchTemplate(img, templ, result, CV_TM_SQDIFF_NORMED);//這裏咱們使用的匹配算法是標準平方差匹配 method=CV_TM_SQDIFF_NORMED,數值越小匹配度越好
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

    double minVal = -1;
    double maxVal;
    Point minLoc;
    Point maxLoc;
    Point matchLoc;
    cout << "匹配度:" << minVal << endl;
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());


    cout << "匹配度:" << minVal << endl;

    matchLoc = minLoc;

    rectangle(img, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, 8, 0);

    imshow("img", img);
    waitKey(0);

    return 0;
}

結果看來,大姚的頭像位置確實被綠框標記出來了!很準!orm

我還在程序中特地打印出匹配度的最小值,由於咱們知道這個算法是數值越小匹配度越高,由輸出的結果看來這個數值還真的很小,說明匹配度真的至關高!
blog

既然咱們能夠取得匹配度的數值,那咱們是否是也能夠利用該數值進行閾值對比呢?好比我想把在閾值範圍以內的頭像都標記出來。能夠這麼作:圖片

//閾值判別,小於0.01才認爲匹配成功,纔將頭像框出來
if (minVal < 0.001)
{
        rectangle(img, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, 8, 0);
}

同理,若是是數值越大代表匹配度越大的算法,就使用maxVal來對比就能夠了。

上面的模板匹配咱們使用了標準平方差匹配 CV_TM_SQDIFF_NORMED算法,看起來效果還不錯,那還有其餘算法嗎?

問得好。OpenCV經過函數 matchTemplate 實現了模板匹配算法。可用的方法有6個:

一般,隨着從簡單的測量(平方差)到更復雜的測量(相關係數),咱們可得到愈來愈準確的匹配(同時也意味着愈來愈大的計算代價)。
最好的辦法是對全部這些設置多作一些測試實驗,以便爲本身的應用選擇同時兼顧速度和精度的最佳方案。

你想採用哪一種算法,只須要將對應的傳進函數matchTemplate裏就能夠了。

下面給出利用trackbar顯示出多種模板那匹配算法的代碼。

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat g_srcImage, g_tempalteImage, g_resultImage;
int g_nMatchMethod;
int g_nMaxTrackbarNum = 5;


void on_matching(int, void*)
{
    Mat srcImage;
    g_srcImage.copyTo(srcImage);
    int resultImage_cols = g_srcImage.cols - g_tempalteImage.cols + 1;
    int resultImage_rows = g_srcImage.rows - g_tempalteImage.rows + 1;
    g_resultImage.create(resultImage_cols, resultImage_rows, CV_32FC1);

    matchTemplate(g_srcImage, g_tempalteImage, g_resultImage, g_nMatchMethod);
    normalize(g_resultImage, g_resultImage, 0, 2, NORM_MINMAX, -1, Mat());
    double minValue, maxValue;
    Point minLocation, maxLocation, matchLocation;
    minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation);

    if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == CV_TM_SQDIFF_NORMED)
    {
        matchLocation = minLocation;
    }
    else
    {
        matchLocation = maxLocation;
    }

    rectangle(srcImage, matchLocation, Point(matchLocation.x + g_tempalteImage.cols, matchLocation.y + g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8, 0);
    rectangle(g_resultImage, matchLocation, Point(matchLocation.x + g_tempalteImage.cols, matchLocation.y + g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8, 0);

    imshow("原始圖", srcImage);
    imshow("效果圖", g_resultImage);

}

int main()
{
    g_srcImage = imread("nba.jpg");
    if (!g_srcImage.data)
    {
        cout << "原始圖讀取失敗" << endl;
        return -1;
    }
    g_tempalteImage = imread("76.png");
    if (!g_tempalteImage.data)
    {
        cout << "模板圖讀取失敗" << endl;
        return -1;
    }

    namedWindow("原始圖", CV_WINDOW_AUTOSIZE);
    namedWindow("效果圖", CV_WINDOW_AUTOSIZE);
    createTrackbar("方法", "原始圖", &g_nMatchMethod, g_nMaxTrackbarNum, on_matching);

    on_matching(0, NULL);


    waitKey(0);

    return 0;
}

固然也會有一些算法匹配失敗的.

實驗證實,該段程序效果很不錯,但注意的是,模板配在原圖摳出模板圖的形式下準確率才比較高,否則的話可能準確度就不過高了。

那麼模板匹配能在哪些項目有應用呢?我說一下個人經驗。

最近我在參與實驗室的一個項目,作的是發票的分類,分類的方法我首先採用的是模板匹配,也就是從一類發票中摳出一些特徵區域,以此做爲模板,本身設定閾值,低於閾值就是算是跟該類發票匹配了,就能夠 對其進行分類。在個人測試看來,準確率還能夠,不過也隱藏這一個比較大的隱患就是,一旦發票種類多了,好比100種,那麼檢測時間就會指數上升,這是不可取的。

相關文章
相關標籤/搜索