Learning OpenCV 鼠标事件

win7+VS2013+OpenCV 2.4.9

鼠标事件响应采用回调函数CallBack的方式来处理。

什么是回调函数呢?

*******************************************************************************

其实回调就是一种利用函数指针进行函数调用的过程.  

为什么要用回调呢?比如我要写一个子模块给你用,   来接收远程socket发来的命令.当我接收到命令后,   需要调用你的主模块的函数,   来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令,     我也不知道你的主模块是什么.cpp或者.h,   或者说,   我根本不用关心你在主模块里怎么处理它,   也不应该关心用什么函数处理它......   怎么办?

使用回调!

—— lone wolf

 

使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。

—— 某专家

 

回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。

—— 绿叶

 

http://hi.baidu.com/zhuyipeng/blog/item/863fefdb7c736c63d1164eec.html 是一篇比较好的文章。

 

什么是回调函数?
  回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自己定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中弹出。
  理解回调函数!

—— jufengfeng

 

Function Pointers provide the concept of callback functions.

—— newty.de

*******************************************************************************

看了这么多的资料,我只将每位的定义总结一下就一句话:回调函数就是函数指针的一种用法。

在鼠标事件处理中,

回调函数callback可以是满足指定输入参数以及返回参数类型的任何函数。

这里,我们必须清楚告诉回调函数触发的事件以及触发位置。

函数还需要知道,用户是否在触发鼠标事件的同时触发了shift或alt等按键。

回调函数格式:

void CvMouseCallback(
	int event,//鼠标事件
	int x,//鼠标指针(cruser)当前位置的水平坐标
	int y,//鼠标指针(cruser)当前位置的垂直坐标
	int flags,//鼠标事件标志
	void* param//额外需要传入的参数
	);

还需要将回调函数注册到OpenCV中,实现的函数是cvSetMouseCallback

void cvSetMouseCallback(
	const	char* window_name,//指定回调函数需要注册到的窗口,也就是产生事件的窗口
	CvMouseCallback on_mouse,//自己定义的回调函数
	void* param=NULL//给CvMouseCallback传入的参数
	);

例程:

实现一个程序,使得用户可以通过鼠标来画矩形。

//An example program in which the 
//user can draw boxes on the screen.
#include <cv.h>
#include<highgui.h>
void my_mouse_callback(int event,int x,int y, int flags,void* param);//自定义的回调函数声明

CvRect box;
bool drawing_box=false;

void draw_box(IplImage* img,CvRect rect)
{
	cvRectangle(
		img,
		cvPoint(box.x,box.y),
		cvPoint(box.x+box.width,box.y+box.height),
		//cvScalar(0xff,0x00,0x00);
		CV_RGB(255,0,0)//red
		);
}

int main(int argc,char** argv)
{
	box=cvRect(-1,-1,0,0);
	IplImage* image=cvCreateImage(
		cvSize(512,512),
		IPL_DEPTH_8U,
		3);
	cvZero(image);
	IplImage* temp=cvCloneImage(image);//复制全部图片内容
	cvNamedWindow("Box Example");

	cvSetMouseCallback(//注册回调函数
		"Box Example",
		my_mouse_callback,
		(void*)image);

	while(1){
		cvCopyImage(image,temp);
		if(drawing_box) draw_box(temp,box);
		cvShowImage("Box Example",temp);
		if(cvWaitKey(15)==27)break;
	}
	cvReleaseImage(&image);
	cvReleaseImage(&temp);
	cvDestroyAllWindows();
}
void my_mouse_callback(int event,int x,int y, int flags,void* param)
{
	IplImage* image=(IplImage*) param;
	switch (event)
	{
		//鼠标拖动
		//依照当前点坐标和矩形起始点坐标设置矩形的宽度和高度
	case CV_EVENT_MOUSEMOVE:{
		if(drawing_box)
		{
			box.width=x-box.x;
			box.height=y-box.y;
		}
							}
							break;
	//鼠标左键按下,开始绘图,设置矩形起始点
	case CV_EVENT_LBUTTONDOWN:{
		drawing_box=true;
		box=cvRect(x,y,0,0);
							  }
							  break;
	//鼠标左键弹起,绘图结束,把矩形写入image
	//如果width或height是负数,取其绝对值,并将靠近左上角的顶点设为矩形起始点
	case CV_EVENT_LBUTTONUP:{
		drawing_box=false;
		if(box.width<0)
		{
			box.x+=box.width;
			box.width*=-1;
		}
		if(box.height<0)
		{
			box.y+=box.height;
			box.height*=-1;
		}
		draw_box(image,box);//将矩形写入image
							}
							break;
	default:
		break;
	}
}



运行cmd,效果图:







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值