說明
1、模板匹配不支持放大縮小,圖像旋轉,不適用於縮放與旋轉情況;應保證模板圖像與搜尋的圖像具有相同的大小,方向;
2、模板匹配用來尋找一幅圖像中與模板最匹配的部分,模板圖像大小必須小於搜尋的原圖像,且類型必須相同;
3、CvInvoke.MatchTemplate()函數:輸出比較映射圖像result類型爲:32位單通道圖像,尺寸大小爲 : (W-w+1)*(H-h+1);映射圖像結果中最佳匹配的地方最亮,圖像像素值最大;可先將映射圖像歸一化到0-1,再尋找maxLoc與maxValue,設定一個閾值,大於閾值的認爲是匹配圖像結果(實現多模板匹配);匹配方法常用:CcorrNormed(歸一化相關匹配法)
4、CvInvoke.MinMaxLoc() : 尋找圖像中最大最小像素值及其位置;
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Util;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Drawing;
namespace lesson20
{
class Program
{
static void Main(string[] args)
{
///單模板匹配
//Mat src = CvInvoke.Imread("src.png");
//CvInvoke.Imshow("src", src);
//Mat result = src.Clone();
//Mat tempImg = CvInvoke.Imread("temp.png");
//int rows_dst = src.Rows - tempImg.Rows + 1;
//int cols_dst = src.Cols - tempImg.Cols + 1;
//Mat dst = new Mat(rows_dst,cols_dst,DepthType.Cv32F,1); //創建合適大小的32位浮點型單通道圖像
//CvInvoke.MatchTemplate(src, tempImg, dst, TemplateMatchingType.CcoeffNormed); //模板匹配
//CvInvoke.Imshow("match", dst); //輸出32位匹配圖(imshow()自動縮放)
//CvInvoke.Normalize(dst, dst, 0, 1, NormType.MinMax, dst.Depth);//歸一化到0-1
//double minValue = 1000, maxvalue = -1;
//Point minLoc = new Point();
//Point maxLoc = new Point();
//CvInvoke.MinMaxLoc(dst, ref minValue, ref maxvalue, ref minLoc, ref maxLoc); //尋找最大最小值位置
//CvInvoke.Rectangle(result, new Rectangle(maxLoc.X, maxLoc.Y, tempImg.Width, tempImg.Height),
// new MCvScalar(0, 255, 0), 2);
//CvInvoke.Imshow("result", result);
//CvInvoke.WaitKey(0);
///視頻模板匹配
//VideoCapture cap = new VideoCapture("1.mp4");
//Mat tempImg = CvInvoke.Imread("green.jpg");
//if(!cap.IsOpened)
//{
// Console.WriteLine("could not open the video...");
// return;
//}
//Mat frame = new Mat();
//while(true)
//{
// cap.Read(frame);
// if(frame.IsEmpty)
// {
// continue;
// }
// int matchresult_rows = frame.Rows - tempImg.Rows + 1;
// int matchresult_cols = frame.Cols - tempImg.Cols + 1;
// Mat matchresult_img = new Mat(matchresult_rows, matchresult_cols, DepthType.Cv32F, 1);
// CvInvoke.MatchTemplate(frame, tempImg, matchresult_img, TemplateMatchingType.CcoeffNormed);
// CvInvoke.Imshow("match result", matchresult_img);
// CvInvoke.Normalize(matchresult_img, matchresult_img, 0, 1,
// NormType.MinMax, matchresult_img.Depth); //歸一化
// double minValue = 0, maxValue = 0;
// Point minLoc = new Point(0, 0);
// Point maxLoc = new Point(0, 0);
// CvInvoke.MinMaxLoc(matchresult_img, ref minValue, ref maxValue, ref minLoc, ref maxLoc);
// CvInvoke.Rectangle(frame, new Rectangle(maxLoc.X, maxLoc.Y, tempImg.Width, tempImg.Height), new MCvScalar(0, 255, 0), 2);
// CvInvoke.Imshow("template trace", frame);
// if(CvInvoke.WaitKey(30) == 27)
// {
// break;
// }
//}
///多模板匹配方法
Mat src = CvInvoke.Imread("src.png");
CvInvoke.Imshow("src", src);
Mat result = src.Clone();
Mat tempImg = CvInvoke.Imread("temp.png");
int matchImg_rows = src.Rows - tempImg.Rows + 1;
int matchImg_cols = src.Cols - tempImg.Cols + 1;
Mat matchImg = new Mat(matchImg_rows, matchImg_rows, DepthType.Cv32F,1); //存儲匹配結果
CvInvoke.MatchTemplate(src, tempImg, matchImg, TemplateMatchingType.CcoeffNormed);
CvInvoke.Imshow("match", matchImg);
CvInvoke.Normalize(matchImg, matchImg, 0, 1, NormType.MinMax, matchImg.Depth); //歸一化
double minValue = 0.0, maxValue = 0.0;
Point minLoc = new Point();
Point maxLoc = new Point();
CvInvoke.MinMaxLoc(matchImg,ref minValue,ref maxValue,ref minLoc,ref maxLoc);
Image<Gray, Single> imgMatch = matchImg.ToImage<Gray, Single>();
int count = 0;
int tempH = 0, tempW = 0;
for(int i =0; i < imgMatch.Rows;i++)
{
for(int j = 0; j < imgMatch.Cols;j++)
{
float matchValue = imgMatch.Data[i,j,0];
if((matchValue > 0.7) && (Math.Abs(j - tempW) > 10) && (Math.Abs(i - tempH)> 10)) //只繪製處於最大範圍內的點
{
count++;
CvInvoke.Rectangle(result, new Rectangle(j, i, tempImg.Width, tempImg.Height), new MCvScalar(255, 0, 0), 2);
tempH = i;
tempW = j;
}
}
}
CvInvoke.Imshow("result", result);
CvInvoke.WaitKey(0);
}
}
}
效果
1、單模板匹配:(只尋找最佳匹配的一幅圖像)
2、視頻模板匹配:
3、多模板匹配: