在图像处理时,如果我们需要实现实时的改变值,并重新开始程序,就需要我们自己实现回调函数,其中,对于鼠标事件的回调,需要我们重写鼠标回调函数void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数
函数中的主要参数:
其中,int型event事件分别有:
重写回调函数后,我们只要使用setMouseCallback函数打开调用即可使用
minMaxLoc()函数找最大最小值
函数原型:void minMaxLoc(InputArray src,double * minVal=0,double* maxVal=0,Point* minLoc=0,Point* maxLoc=0,InputArray mask=noArray())
参数说明:
模板匹配函数matchTemplate()
模板匹配是从一张图片里找到与另一模板图像最匹配的部分
函数原型:void matchTemplate(InputArray image,InputArray templ,OutputArray result,int method)
参数说明:
六种匹配方式及参数:
可能有帮助的解释
对于matchTemplate函数中result大小的解释:
比如源图尺寸为WH,待匹配图为wh,那么输出结果大小就是(W-w+1)(H-h+1),原因是匹配是拿着小图在大图上移动来计算值的,所以移动的范围就是(W-w+1)(H-h+1),计算的结果就存储在这个结果矩阵中
总体代码及注释
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat image; //当前帧图像
Mat imageCopy; //用于拷贝的当前帧图像
Mat rectImage; //子图像
bool leftButtonDownFlag = false; //左键单击后视频暂停标志位
Point beginPoint; //矩形框起点
Point endPoint; //矩形框终点
int resultRows; //模板匹配result的行
int resultcols; //模板匹配result的列
Mat ImageResult; //模板匹配result
double minValue; //模板匹配result最小值
double maxValude; //模板匹配result最大值
Point minPoint; //模板匹配result最小值位置
Point maxPoint; //模板匹配result最大值位置
int frameCount = 0; //帧数统计
void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数
void Tips() {
cout << "请选择要使用的匹配规则:" << endl;
cout << " 1.平方差匹配" << endl;
cout << " 2.归一化平方差匹配" << endl;
cout << " 3.相关匹配" << endl;
cout << " 4.归一化相关匹配" << endl;
cout << " 5.系数匹配" << endl;
cout << " 6.化相关系数匹配" << endl;
cout << " 0.退出" << endl;
}
int main(int argc, char*argv[])
{
VideoCapture capture("C:\\Users\\14527\\Desktop\\Video\\cut.AVI");
int capture_fps = capture.get(CV_CAP_PROP_FPS); //获取视频帧率
int capture_count = capture.get(CV_CAP_PROP_FRAME_COUNT);
int capture_width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
int capture_height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "视频帧率:" << capture_fps<> choice;
namedWindow("Video");
setMouseCallback("Video", onMouse); //设置鼠标回调函数
while (choice)
{
if (!leftButtonDownFlag) //鼠标左键按下绘制矩形时,视频暂停播放
{
capture >> image;
frameCount++; //帧数
}
if (!image.data || waitKey(pauseTime + 30) == 27) //图像为空或Esc键按下退出播放
{
break;
}
if (rectImage.data)
{
ImageResult = Mat::zeros(resultRows, resultcols, CV_32FC1);//建立结果矩阵,注意是单通道的32位浮点型
switch (choice) { //根据一开始的选择使用对应的匹配模式
case 1:
matchTemplate(image, rectImage, ImageResult, TM_SQDIFF);
break;
case 2:
matchTemplate(image, rectImage, ImageResult, TM_SQDIFF_NORMED);
break;
case 3:
matchTemplate(image, rectImage, ImageResult, TM_CCORR);
break;
case 4:
matchTemplate(image, rectImage, ImageResult, TM_CCORR_NORMED);
break;
case 5:
matchTemplate(image, rectImage, ImageResult, TM_CCOEFF);
break;
case 6:
matchTemplate(image, rectImage, ImageResult, TM_CCOEFF_NORMED);
break;
}
minMaxLoc(ImageResult, &minValue, &maxValude, &minPoint, &maxPoint, Mat()); //最小值最大值获取
Point point;
switch (choice) {//为了统一处理,所以先把Point取出来
case 1:
point = minPoint;
break;
case 2:
point = minPoint;
break;
case 3:
point = maxPoint;
break;
case 4:
point = maxPoint;
break;
case 5:
point = maxPoint;
break;
case 6:
point = maxPoint;
break;
}
rectangle(image, point, Point(point.x + rectImage.cols, point.y + rectImage.rows), Scalar(0, 0, 255), 2); //绘制
//更新当前模板匹配的模板
Mat resultImage = image(Rect(point, Point(point.x + rectImage.cols, point.y + rectImage.rows)));
rectImage = resultImage.clone();
//当前帧数输出到视频流
writer << image;
}
imshow("Video", image);
}
return 0;
}
//鼠标回调函数
void onMouse(int event, int x, int y, int flags, void *ustc)
{
if (event == CV_EVENT_LBUTTONDOWN) //检测到左键按下时
{
leftButtonDownFlag = true; //标志位为true,也就是停止读取下一帧图像
beginPoint = Point(x, y); //设置左键按下点的矩形起点
endPoint = beginPoint;
}
if (event == CV_EVENT_MOUSEMOVE && leftButtonDownFlag)
{ //当鼠标移动且之前左键有按下的话
imageCopy = image.clone();
endPoint = Point(x, y);
if (beginPoint != endPoint)
{
//在复制的图像上绘制矩形
rectangle(imageCopy, beginPoint, endPoint, Scalar(0, 0, 255), 2);
}
//imshow("Video", imageCopy);
}
if (event == CV_EVENT_LBUTTONUP) //左键放开时,开始匹配
{
leftButtonDownFlag = false;
Mat subImage = image(Rect(beginPoint, endPoint)); //截取图像
rectImage = subImage.clone(); //给全局的待匹配图像
resultRows = image.rows - rectImage.rows + 1; //输出结果图像的行数及列数
resultcols = image.cols - rectImage.rows + 1;
//imshow("Sub Image", rectImage);
}
}