说明
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、多模板匹配: