模板匹配实现定位的步骤:
St1 将模板图和搜索图从BGR转化为GRAY;
St2 对模板图和搜索图进行均衡化处理
St3 模板图和搜索图进行滤波
St4 模板图和搜索图分别求其梯度
St5 模板匹配,求其求其最佳和最差匹配位置,归一化处理
代码如下:
#include <opencv2/core/core.hpp>
#include "opencv2/opencv.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>
using namespace std;
using namespace cv;
const char* sourceImage = "sourceImage";
Point pre_pt, cur_pt;
Mat ReserchImg,tmpImg;
Rect SquareRect,drawRect;
/*函数声明区*/
void drawing_image();
void Clean();
void Image_fileter(Mat resImg, Mat &output_img);
void matcher(Mat researchImg, Mat tmpImg, Mat DrawImg);
int Img_remap(Mat input, Mat &outout);
void on_mouse(int event, int x, int y, int flags, void *param)
{
Mat drawImage,remapImage;
ReserchImg.copyTo(drawImage);
if (event == CV_EVENT_LBUTTONDOWN)
{
pre_pt = cur_pt = Point(-1, -1);
pre_pt = cur_pt = Point(x, y);
//if (cur_pt == Point(-1, -1))
cout << "鼠标按下,当前坐标为:" << cur_pt << endl;
}
else if (event == CV_EVENT_MOUSEMOVE&&(flags == CV_EVENT_FLAG_LBUTTON))
{
cur_pt = Point(x, y);
}
else if (event == CV_EVENT_LBUTTONUP)
{
SquareRect = Rect(-1, -1, 1, 1);
cur_pt = Point(x, y);
int tmp_height = cur_pt.y - pre_pt.y;
int tmp_width = cur_pt.x - pre_pt.x;
SquareRect.x = pre_pt.x;
SquareRect.y = pre_pt.y;
SquareRect.width = tmp_width;
SquareRect.height = tmp_height;
cout << "鼠标按下之前坐标为:" << cur_pt << endl;
if (SquareRect.area() >125 || (SquareRect.width >15 && SquareRect.height > 15))
{
tmpImg = ReserchImg(SquareRect).clone();
if (tmpImg.empty())
{
return;
}
// Img_remap(tmpImg,remapImage);
matcher(ReserchImg, tmpImg, drawImage);
}
}
}
int main(int argc, char *argv[])
{
ReserchImg = imread("C://花分割.jpg");
char tim = '0';
if (!ReserchImg.data)
{
cout << "loading image failed" << endl;
return 0;
}
/*鼠标事件*/
cv::namedWindow("sourceImage", CV_WINDOW_AUTOSIZE);
cvSetMouseCallback(sourceImage, on_mouse, NULL);
{
drawing_image();
//imshow(sourceImage, ReserchImg);
waitKey(0);
}
return 0;
}
char coord[20] = {'0'};
void drawing_image()
{
if (SquareRect.area() >125 || (SquareRect.width >15 && SquareRect.height > 15))
{
sprintf_s(coord, "(%d ,%d)", SquareRect.x, SquareRect.y);
putText(ReserchImg, coord, cur_pt, cv::FONT_HERSHEY_COMPLEX, 1, Scalar(0, 255, 0));
rectangle(ReserchImg, SquareRect, Scalar(0, 255, 255));
}
imshow(sourceImage, ReserchImg);
}
void Clean()
{
SquareRect.x = -1;
SquareRect.y = -1;
SquareRect.width = 0;
SquareRect.height = 0;
}
void Image_fileter(Mat resImg, Mat &output_img)
{
Mat _resImg;
if (resImg.channels() != 1) cvtColor(resImg, _resImg, CV_BGR2GRAY); //转为gray图
/*均衡化处理*/
equalizeHist(_resImg, output_img);//均衡化就是把直方图每个灰度级进行归一化处理,根据相应的灰度值修正原图的每个像素。
/*高斯滤波*/ //高斯滤波就是每一个像素点的值都有其本身和领域内的其他像素值经过加权平均后得到的
Mat Kernel = getStructuringElement(cv::MORPH_RECT, Size(5, 5), Point(-1, -1)); //getStructuringElement()可以生成形态学操作中用到的核 矩形 5*5 个1
GaussianBlur(output_img, output_img, Size(5, 5),0); //高斯处理
/*求梯度*/
morphologyEx(output_img, output_img, cv::MORPH_GRADIENT, Kernel); // 形态学梯度保留物体的边缘轮廓 膨胀与腐蚀之差
}
void matcher(Mat researchImg, Mat tmpImg,Mat DrawImg)
{
Mat Resch_img, tmp_img; //定义收索图 模版图
double min = 0.0, max = 0.0;
Point minLoc = Point(-1, -1), maxLoc = Point(-1, -1); // 初试位置
int tmp_w = researchImg.cols - tmpImg.cols+1; //图像大小 参考opencv3编程入门 367页
int tmp_h = researchImg.rows - tmpImg.rows + 1;
Mat mat_mval = Mat(Size(tmp_w, tmp_h), CV_32FC1); //定义这么大空间的图像
//调用函数 一系列操作 转gray 均衡化 然后高斯滤波然后形态学操作 找边缘轮廓
Image_fileter(researchImg, Resch_img);
Image_fileter(tmpImg, tmp_img);
//matchTemplate()函数用于匹配出和模版重叠的图像区域
matchTemplate(Resch_img, tmp_img, mat_mval, TM_CCOEFF_NORMED); //第三个参数就是比较结果的映射图像 大小也有了
///normalize(mat_mval, mat_mval, 0, 1); //可以进行一步标准化
char mat_ch[50] = {0};
minMaxLoc(mat_mval, &min, &max, &minLoc,&maxLoc,Mat()); //通过minmaxloc函数定位最匹配的位置
drawRect = Rect(maxLoc, Size(tmpImg.cols, tmpImg.rows)); //画矩形框
sprintf_s(mat_ch, "good match(%.1f)", max);
putText(DrawImg, mat_ch, drawRect.br(), cv::FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
rectangle(DrawImg, drawRect, Scalar(255, 0, 0));
imshow("match", DrawImg);
}
/*图片的放射变化*/
int Img_remap(Mat input ,Mat &outout)
{
Mat image, imgx, imgy, remapdst;
char mode = '0';
image = input.clone();
if (image.empty())
{
cout << "Picture load error" << endl;
return -1;
}
imgx.create(image.size(), CV_32FC1);
imgy.create(image.size(), CV_32FC1);
for (int row = 0; row < image.rows; ++row)
{
for (int col = 0; col < image.cols; ++col)
{
imgx.at<float>(row, col) = saturate_cast<float>(image.rows - row);
imgy.at<float>(row, col) = saturate_cast<float>(image.cols - col);
}
}
remap(image, remapdst, imgx, imgy, INTER_LINEAR);
remapdst.copyTo(outout);
imshow("remap", remapdst);
}
注释没有全部都看完!
测试了一下 在原图上用鼠标随机圈一个矩形 match图上会显示匹配你画的位置,有时候准确度低,代表匹配的不好 0.9和1是比较完美的!