open cv鼠标操作(回调函数)

本文介绍了如何在OpenCV中使用`SetMouseCallback`函数设置鼠标回调,详细解析了回调函数的参数及鼠标事件类型,包括鼠标滑动、点击和拖拽等,并提到了按键状态标志位的检测。

鼠标消息回调函数 SetMouseCallback

函数原型 c++: void setMousecallback(const string& winname, MouseCallback onMouse, void* userdata=0)
winname:窗口的名字
onMouse:鼠标响应函数,回调函数。指定窗口里每次鼠标时间发生的时候,被调用的函数指针

这个函数的原型应该为void on_Mouse(int event, int x, int y, int flags, void* param);

userdate:传给回调函数的参数


鼠标响应函数的参数
void on_Mouse( int event, int x, int y, int flags, void* param );

event是 CV_EVENT_*变量之一
EVENT_MOUSEMOVE 滑动
EVENT_LBUTTONDOWN 左击
EVENT_RBUTTONDOWN 右击
EVENT_MBUTTONDOWN 中键点击
EVENT_LBUTTONUP 左键放开
EVENT_RBUTTONUP 右键放开
EVENT_MBUTTONUP 中键放开
EVENT_LBUTTONDBLCLK 左键双击
EVENT_RBUTTONDBLCLK 右键双击
EVENT_MBUTTONDBLCLK 中键双击

x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系)

flags是CV_EVENT_FLAG的组合

flag的状态有:
EVENT_FLAG_LBUTTON 左键拖拽
EVENT_FLAG_RBUTTON 右键拖拽
EVENT_FLAG_MBUTTON 中键拖拽
EVENT_FLAG_CTRLKEY 按住Ctrl不放
EVENT_FLAG_SHIFTKEY 按住Shift不放
EVENT_FLAG_ALTKEY 按住Alt不放

param是用户定义的传递到setMouseCallback函数调用的参数

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;
Mat src, dst;
Mat tempsrc;

void Mouse(int event, int x, int y, int flags, void* param);//鼠标操作函数


void DrawRectangle(Mat& src, Rect box);//绘制矩形函数


bool draw = false;//决定是否进行绘制的布尔旗帜draw

Rect Rectangle;//定义矩形数据类型Rectangle

RNG rng(12345);
int main()
{

	src = imread("D:/实验台/机器视觉/测试图片/格子衬衫.jpg");
	if (src.empty())//如果src这个数据库属性为空
	{
		cout << "无法打开" << endl;
		return -1;
	}
	imshow("原图", src);
	
	Rectangle = Rect(-1, -1, 0, 0);//定义一个空矩形模板
	//Rect(x,y,width,height); 其中x,y为矩形模板的坐标(-1表示坐标为空 不在任何坐标上) width和height为矩形的宽度和高度

	//为了方便显示线条重新对原图像进行处理
	Mat src(600, 800, CV_8UC3);
	src = Scalar::all(0);//将src所有像素值置为0 即将src变为纯黑色图片


	//Mat tempsrc = Mat::zeros(src.size(), src.type());直接在原图上绘制

	namedWindow("程序窗口");
	
	setMouseCallback("程序窗口", Mouse, (void*)&src);//传入src的地址,这样就不必将img设置成全局变量了
	//鼠标响应函数cv:: setMousecallback(const string & winname, MouseCallback onMouse, void* userdata = 0)
	//1.winname:窗口的名字
	//2. onMouse : 鼠标响应函数,回调函数。指定窗口里每次鼠标时间发生的时候,被调用的函数指针 这个函数的原型应该为void on_Mouse(int event, int x, int y, int flags, void* param);
	//3.userdate:传给回调函数的形式参数

	while (1)
	{
		tempsrc = src.clone();//防止绘制图像粘连 要将src的值克隆给tempsrc
		if (draw)//如果draw=true允许绘图
		{
			DrawRectangle(tempsrc, Rectangle);//调用DrawRectangle函数绘制矩形
		}
		imshow("程序窗口", tempsrc);
		if (waitKey(10) == 27)
		{
			break;
		}
	}

	waitKey(0);
	return 0;
}

void Mouse(int event,int x,int y,int flags,void* param)
{
	//int event -- 中断事件 并不是简单的自定义的int形式的变量名 而是CV_EVENT_*变量之一,一般为setMouseCallBack传过来固定数据,常用的几个数据为

	//todoevent中有10个case事例变量
	//EVENT_MOUSEMOVE 滑动		EVENT_LBUTTONDOWN 左击
	//EVENT_RBUTTONDOWN 右击		EVENT_MBUTTONDOWN 中键点击
	//EVENT_LBUTTONUP 左键放开		EVENT_RBUTTONUP 右键放开
	//EVENT_MBUTTONUP 中键放开		EVENT_LBUTTONDBLCLK 左键双击
	//EVENT_RBUTTONDBLCLK 右键双击		EVENT_MBUTTONDBLCLK 中键双击

	//todoevent中有x和y两个坐标变量
	//为鼠标当前所在位置的x坐标  y为鼠标当前所在位子的y坐标

	//todoevent中有一个标志位flag

	//todoevent中的param用来接收setMouseCallback传递过来的用户数据,为void指针类型

	printf("鼠标函数的x=%d y=%d Rectangle的x=%d y=%d wid=%d hei=%d    \r", x, y, Rectangle.x, Rectangle.y, Rectangle.width, Rectangle.height);

	Mat& src = *(Mat*)param;//将param强制转换为Mat指针,*(Mat*)=Mat,就如*(int*)=int一样 void*为万能智能指针 可以指向任何形式的参数 而param只是指针名
	switch (event)
	{
		case EVENT_MOUSEMOVE://如果鼠标移动
		{
			if (draw)//如果draw为true (允许绘制的标志位打开)
			{
				Rectangle.width = x - Rectangle.x;//矩形的宽度为鼠标当前的x坐标减去鼠标左键点击的那一刻赋值给矩形的左上角的x坐标
				Rectangle.height = y - Rectangle.y;//矩形的度高为鼠标当前的y坐标减去鼠标左键点击的那一刻赋值给矩形的左上角的y坐标
			}
		}
		break;

		case EVENT_LBUTTONDOWN://如果鼠标左键按下
		{
			draw = true;//允许绘制的标志位打开 鼠标可以进行矩形绘制
			Rectangle = Rect(x, y, 0, 0);//将鼠标按下时的鼠标当前的x和y坐标赋值给Rect矩形左上角x和y坐标 矩形的宽高等待	case EVENT_MOUSEMOVE的计算
		}
		break;

		case EVENT_LBUTTONUP://如果鼠标左键松开
		{
			draw = false;//允许绘制的标志位关闭 鼠标暂停矩形绘制 
			if (Rectangle.width < 0)//如果绘制出的矩形宽度小于0(以鼠标点击时给定的矩形左上角坐标为界  向左绘制矩形时 Rectangle.width为负值)
			{
				Rectangle.x += Rectangle.width;//矩形左上角的坐标值为矩形左上角x坐标值加上计算出的矩形宽度值(此值为负数)
				Rectangle.width *= -1;//将矩形的宽度值(负数)* -1负负得正取绝对值 
				//abs(Rectangle.width);取绝对值方法二
				
	
			}
			if (Rectangle.height < 0)
			{
				Rectangle.y += Rectangle.height;
				Rectangle.height *= -1;
				//abs(Rectangle.height);
			}

		}
		DrawRectangle(src, Rectangle);//返回的两个实参 src为src图像 Rectangle为获取的矩形框x,y,width,height信息
		break;

		case EVENT_RBUTTONDOWN://如果鼠标右键点击
		{
			src = Scalar::all(0);//将src所有像素值置为0 即将src变为纯黑色图片 去掉绘制的线条
		}
		break;

	}

}

void DrawRectangle(Mat & src, Rect box)//在图像中绘制矩形的函数 形参有两个 Mat类型的src图像的指针 和 Rect类型的矩形变量box 分别接收鼠标操作函数的两个实参src和Rectangle
{
	rectangle(src,box.tl(),box.br(),Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255)),2);
	//矩形绘制函数
	//1.src-模板图像 绘制彩色线条使用CV_8UC3类型  单色线条使用CV_8UC1类型 
	//2.box.tl() -point2i类型的坐标变量 有两个int类型的坐标参数 对应绘制矩形时选定的 矩形左上角 角点的XY坐标 
	//3.box.br() -point2i类型的坐标变量 有两个int类型的坐标参数 对应绘制矩形时选定的 矩形右下角 角点的XY坐标 


	//todo注:rect.tl();意为返回Rectangle矩形的左上角坐标  rect.br();意为返回Rectangle矩形的右下角坐标  矩形变量Rectangle内的参数不能直接进行绘制 
	//矩形绘制函数示例 rectangle(src, Point2i(0, 0), Point2i(500, 500), Scalar(0, 255, 0));

}

在这里插入图片描述

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值