2.10鼠标事件

目录

实验原理

实验代码

运行结果

文章参考


实验原理

在 OpenCV 中存在鼠标的操作,比如左键单击、双击等。对于 OpenCV 来讲,用户的鼠标操作被认为发生了一个鼠标事件,需要对这个鼠标事件进行处理,这就是事件的响应。下面我们来介绍一下鼠标事件。

鼠标事件包括左键按下、左键松开、左键双击、鼠标移动等。当鼠标事件发生时,OpenCV 会让一个鼠标响应函数自动被调用,相当于一个回调函数,这个回调函数就是鼠标事件处理函数。 OpenCV 提供了 setMousecallback 来预先设置回调函数(相当于告诉系统鼠标处理的回调函数已经设置好了,有鼠标事件发生时,系统调用这个回调函数即可),注意是系统调用,而不是开发者调用,因此称为回调函数。函数 setMousecallback 声明如下:

cpp 复制代码
void setMousecallback(const string& winname, MouseCallback onMouse, void*userdata=0);
其中参数
winname 表示窗口的名字,
onMouse 是鼠标事件响应的回调函数指针,
userdate 是传给回调函数的参数。
这个函数名也比较形象,一看就知道是用来设置鼠标回调函数的。 

鼠标事件回调函数类型 MouseCallback 定义如下:

cpp 复制代码
typedef void(* cv::MouseCallback)(int event,int x,int y,int flags,void*useradata);
其中参数 
event 表示鼠标事件,
x 表示鼠标事件的 x 坐标,
y 表示鼠标事件的 y 坐标,
flags 表示鼠标事件的标志,
userdata 是可选的参数。 

鼠标事件 event 主要有以下几种:

cpp 复制代码
enum
{
EVENT_MOUSEMOVE =0, //滑动
EVENT_LBUTTONDOWN =1, //左键单击
EVENT_RBUTTONDOWN=2,//右键单击
EVENT_MBUTTONDOWN=3,//中键单击
EVENT_LBUTTONUP=4,//左键放开
EVENT_RBUTTONUP=5,//右键放开
EVENT_MBUTTONUP=6,//中键放开
EVENT_LBUTTONDBLCLK=7,//左键双击
EVENT_RBUTTONDBLCLK=8,//右键双击
EVENT_MBUTTONDBLCLK=9,//中键双击
EVENT_MOUSEWHEEL=10,//正值表示向前滚动,负值表示向后滚动
EVENT_MOUSEHWHEEL=11//正值表示向左滚动,负值表示向右滚动
};

鼠标事件标志 flags 主要有以下几种:

cpp 复制代码
enum {
EVENT_FLAG_LBUTTON = 1,//按住左键拖曳
EVENT_FLAG_RBUTTON = 2,//按住右键拖曳
EVENT_FLAG_MBUTTON = 4,//按住中键拖曳
EVENT_FLAG_CTRLKEY = 8,//按 Ctrl
EVENT_FLAG_SHIFTKEY = 16,//按 Shift
EVENT_FLAG_ALTKEY = 32//按 Alt
};

通过 event 和 flags 就能清楚地了解当前鼠标发生了哪种操作。

https://cloud.tencent.com/developer/article/1553511https://cloud.tencent.com/developer/article/1553511

line()函数来对直线的绘制。

cpp 复制代码
//https://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/core/doc/drawing_functions.html?highlight=line#cv.Line
void line(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0);

参数:
img: 要绘制线段的图像。
pt1: 线段的起点。
pt2: 线段的终点。
color: 线段的颜色,通过一个Scalar对象定义。
thickness: 线条的宽度。
lineType: 线段的类型。可以取值8, 4, 和CV_AA, 
分别代表8邻接连接线,4邻接连接线和反锯齿连接线。
默认值为8邻接。为了获得更好地效果可以选用CV_AA(采用了高斯滤波)。
shift: 坐标点小数点位数。

实验代码

cpp 复制代码
#include "pch.h"
#include <opencv2/highgui/highgui_c.h>
#include <opencv2\opencv.hpp>
//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 
using namespace cv;
#include<iostream>
using namespace std;
 

#define WINDOW "原图"
Mat g_srcImage, g_dstImage;
Point previousPoint;
bool P = false;
void on_mouse(int event, int x, int y, int flags, void*);
int main()
{
	g_srcImage = imread("200.jpg", 1);
	imshow(WINDOW, g_srcImage);
	setMouseCallback(WINDOW, on_mouse, 0);

	waitKey(0);
	return 0;
}
void on_mouse(int event, int x, int y, int flags, void*)
{
	if (event == EVENT_LBUTTONDOWN)
	{
		previousPoint = Point(x, y);
	}
	else if (event == EVENT_MOUSEMOVE && (flags&EVENT_FLAG_LBUTTON))
	{
		Point pt(x, y);
		line(g_srcImage, previousPoint, pt, Scalar(0, 0, 255), 2, 5, 0);
		//https://blog.csdn.net/hk121/article/details/81085213
		previousPoint = pt;
		imshow(WINDOW, g_srcImage);
	}
}

在代码中,on_mouse 就是用来处理鼠标事件的回调函数,当鼠标有动作产生时,on_mouse 会被系统调用,然后在 on_mouse 中,判断发生了哪种动作,进而进行相应的处理。本例我们关心的是按下鼠标左键,然后按住左键时的鼠标移动。一旦按下鼠标左键,就记录下当时的位置(也就是画线的开始点),位置记录在 previousPoint 中,接着如果继续有鼠标移动事件发生,我们就开始调用函数 line 画线。最后把画了线的图像数据 g_srcImage 用函数 imshow 显示出来。

运行结果

文章参考

程序中如果鼠标右键被按下,则会提示"点击鼠标左键才可以绘制轨迹",点击左键会输出当前鼠标的坐标,并将该点坐标定义为某段轨迹的起始位置。之后按住左键移动鼠标,会进入到第三个逻辑判断,绘制鼠标的移动轨迹。

示例程序中提供了两种绘制轨迹的方法,

第一种是每次调用回调函数获得鼠标位置时更改周围的图像像素值,这种方式比较直观,但是由于回调函数有一定的执行时间,因此当鼠标移动较快时绘制的图像轨迹会出现断点。

第二种绘制轨迹的方式是在前一时刻和当前时刻鼠标位置间绘制直线,这种方式可以避免因鼠标移动过快而带来的轨迹出现断点的问题。

https://cloud.tencent.com/developer/article/1553511

cpp 复制代码
// myMouse.cpp绘制鼠标移动轨迹
#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat img, imgPoint; //全局的图像
Point prePoint; //前一时刻鼠标的坐标,用于绘制直线
void mouse(int event, int x, int y, int flags, void*);

int main()
{
	img = imread("200.jpg");
	if (!img.data)
		{
		cout << "请确认输入图像名称是否正确!" << endl;
		system("pause");
		return -1;
		 }
    img.copyTo(imgPoint);
	imshow("图像窗口1", img);
	imshow("图像窗口2", imgPoint);
	setMouseCallback("图像窗口1", mouse, 0); //鼠标事件
	waitKey(0);
	system("pause");
	return 0;
	}

void mouse(int event, int x, int y, int flags, void*)
{
	if (event == EVENT_RBUTTONDOWN) //单击右键
		{
		cout << "点击鼠标左键才可以绘制轨迹" << endl;
		}
	if (event == EVENT_LBUTTONDOWN) //单击左键,输出坐标
		{
		prePoint = Point(x, y);
		cout << "轨迹起使坐标" << prePoint << endl;
		 }
	if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) //鼠标按住左键移动
		{
		//通过改变图像像素显示鼠标移动轨迹
		imgPoint.at<Vec3b>(y, x) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y, x - 1) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y, x + 1) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y + 1, x) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y + 1, x) = Vec3b(0, 0, 255);
		imshow("图像窗口2", imgPoint);
		
      //通过绘制直线显示鼠标移动轨迹
		Point pt(x, y);
		line(img, prePoint, pt, Scalar(0, 0, 255), 2, 5, 0);
		prePoint = pt;
		imshow("图像窗口1", img);
		}
}
相关推荐
嵌入式大圣19 分钟前
单片机结合OpenCV
单片机·嵌入式硬件·opencv
只怕自己不够好2 小时前
OpenCV 图像运算全解析:加法、位运算(与、异或)在图像处理中的奇妙应用
图像处理·人工智能·opencv
华清远见IT开放实验室3 小时前
【每天学点AI】实战图像增强技术在人工智能图像处理中的应用
图像处理·人工智能·python·opencv·计算机视觉
只怕自己不够好4 小时前
《OpenCV 图像缩放、翻转与变换全攻略:从基础操作到高级应用实战》
人工智能·opencv·计算机视觉
安静读书9 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小陈phd9 小时前
OpenCV从入门到精通实战(九)——基于dlib的疲劳监测 ear计算
人工智能·opencv·计算机视觉
如若12314 小时前
主要用于图像的颜色提取、替换以及区域修改
人工智能·opencv·计算机视觉
lsjweiyi17 小时前
极简AI工具箱网站开源啦!
opencv·开源·微信支付·支付宝支付·百度ai·极简ai工具箱·ai图像处理
Jack黄从零学c++21 小时前
opencv(c++)---自带的卷积运算filter2D以及应用
c++·人工智能·opencv
饭碗、碗碗香1 天前
OpenCV笔记:图像去噪对比
人工智能·笔记·opencv·计算机视觉