opencv回调函数中鼠标响应cvSetMouseCallback函数,绘制矩形
首先明确一点,这个函数在程序中始终运行,任何时候当你的鼠标有动作的时候,该函数被调用。
首先是回调函数:
(摘自百度百科)回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
机制如下:
- 定义一个回调函数
- 提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者
- 当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理
这么做的意义就在于可以把调用者和被调用者分开。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
下面一个简单的回调函数的例子:
#include <iostream>
int main()
{
void caller(void (*) ()); //函数声明
void func(); //函数声明
void (*p) (); //声明指针变量,其中p指向函数的指针,该函数无输入,返回值类型为void,左边括号里p就是指针变量名
p=func; //给指针变量赋值
caller(p); //回调
getchar();
}
//回调函数
void caller(void (*fnp) ())
{
printf("调用成功");
fnp();
}
//被调函数
void func()
{
printf("回调成功");
}
接下来就是opencv中cvSetMouseCallback的理解和应用:
void cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param=NULL );
window_name 回调函数需要注册到的 窗口名字,即产生事件的窗口。
on_mouse 指定窗口里每次鼠标事件发生的时候,被调用的函数指针,回调函数。
第三个参数用来传递额外的信息给前面提到的void* param。
这个函数的原型应该为 void Foo(int event, int x, int y, int flags, void* param);
其中
event是 CV_EVENT_*变量之一, x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系),
flags是CV_EVENT_FLAG的组合,param是用户定义的传递到cvSetMouseCallback函数调用的参数。
param 用户定义的传递到回调函数的参数。
放代码
#include <algorithm>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
float xMin,yMin,width,height;
CvRect ROI_rect;
int kick_state=0;
CvPoint p1,p2;
void on_MouseHandle(int event,int x,int y,int flags, void* param)
{
Mat* frame=(Mat*)param;//将参数传递给内部的变量,并使用。
if(event==CV_EVENT_LBUTTONDOWN)
{
cout<<"左键被按下"<<endl;
ROI_rect.x=x;
ROI_rect.y=y;
kick_state=true;
}
else if(event==CV_EVENT_MOUSEMOVE&&kick_state)
{
cout<<"鼠标在移动"<<endl;
p1=cvPoint(ROI_rect.x,ROI_rect.y);
p2=cvPoint(x,y);
}
else if(event==CV_EVENT_LBUTTONUP&&kick_state)
{
cout<<"左键被抬起"<<endl;
xMin=cv::min(p1.x,p2.x);
yMin=cv::min(p1.y,p2.y);
width=abs(p2.x-p1.x);
height=abs(p2.y-p1.y);
rectangle(*frame,Point(xMin,yMin),Point(xMin+width,yMin+height),Scalar(0,255,0),2,8,0);
imshow("Image",*frame);
kick_state=false;
}
}
int main()
{
Mat frame;
Mat* pframe=&frame;
frame=imread("path",1);
imshow("image",frame);
waitKey(1);//这一步最好加上,有时候会因为没有等待,图片无法正常显示
setMouseCallback("Image",on_MouseHandle,(void*)pframe);//这里,我将第三个参数,即传递到回调函数中的参数,定义为一帧图片,也就是将读入的图片传给回调函数,让它能够在函数内部使用。实际上也可以什么都不传入,把frame定义成全局变量。这样回调函数也可以使用。
waitKey(0);
}
运行结果如下:
其实我是在测试KCF算法,第一部分就是要选定一个被跟踪的目标,于是采用了这种方式。选定目标之后,随便敲击键盘,开始后续跟踪算法。话已至此,贴一张后续跟踪效果图
that is all!btw,最近有点忙啊。。。