鼠标事件响应函数
setMouseCallback()
void cv::setMouseCallback( const String & winname,
MouseCallback onMouse,
void* userdata = 0
)
·winname:添加鼠标响应的窗口名字
·onMouse:鼠标响应的回调函数
·userdata:传递给回调函数的可选参数
用于检测鼠标事件,比如鼠标进行移动或者点击之类的操作,那么可以通过此函数进行检测,第一个参数时需要进行鼠标响应检测的显示图像的窗口,如果显示图像的命名为窗口,那么参数就要定义为窗口,也就是通过这个参数,我们知道鼠标的响应是与图片息息相关的,如果程序中没有显示图片,那么也就没有办法去检测鼠标的响应。
第二个参数是当鼠标进行了相应的操作之后,这个函数所启动的回调函数。
第三个参数,一般情况下我们可以不使用此参数。
响应的回调函数
MouseCallback()
typedef void(*cv::MouseCallback)(int event,int x,int y,int flags,void*userdata)
·event:鼠标响应事件标志,参数为EVENT_*形式。
·x:鼠标指针在图像中的x坐标。
·y:鼠标指针在图像坐标系中的y坐标。
·flags:鼠标响应标志,参数为EVENT_FLAG_*形式。
·userdata:传递给回调函数的可选参数。
第一个参数形式是EVENT_*形式,这里面的内容大多都是鼠标的瞬间操作,比如点击左键,右键,滑轮向前向后滚动。
第二,三个参数是鼠标在坐标系里的x坐标,y坐标。
第四个标志是鼠标响应标志,它的参数类型为EVENT_FLAG_*形式,多用于一种持续性动作的标志,比如按住左/右键拖拽等长时间存在的动作。
最后一个参数是传递给回调参数的可选参数,是与前面检测鼠标响应所相对应的,一般情况下可不使用。
鼠标响应事件标志
鼠标响应标志
示例
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv; //opencv的命名空间
using namespace std;
Mat img, imgPoint;
Point prePoint;//前一时刻鼠标的坐标,用于绘制直线
void mouse(int event, int x, int y, int flags, void*);
int main()
{
img = imread("E:/opencv/opencv-4.6.0-vc14_vc15/opencv/lenac.png");
if (!img.data)
{
cout << "请确认输入图像名称是否正确" << endl;
return -1;
}
img.copyTo(imgPoint);
imshow("图像窗口1", img);
imshow("图像窗口2", imgPoint);
setMouseCallback("图像窗口1", mouse, 0);//鼠标响应
waitKey(0);//等待函数用于显示图像
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)) //鼠标按住左键移动第3章图像基本操作
{
//通过绘制直线显示鼠标移动轨迹
Point pt(x, y); //通过前一时刻的位置prePoint和当前时刻的位置pt绘制一条两点之间的线段
line(img, prePoint, pt, Scalar(255, 255, 255), 2, 5, 0);
prePoint = pt; //将当时时刻的位置,置为前一时刻的位置,用于下一步操作的结果
imshow("图像窗口1", img);//将绘制的结果显示在图像中
//通过改变图像像素显示鼠标移动轨迹,得到鼠标当前位置(x,y),分别将其四领域内的像素改为白色的像素
imgPoint.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y, x - 1) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y, x + 1) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y + 1, x) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y + 1, x) = Vec3b(255, 255, 255);
imshow("图像窗口2", imgPoint);
}
}
结果
我们在图像1中快速拖拽左键,发现图像2中点很松散,说明在进行鼠标检测时,是需要时间的,如果在这个时间内移动了过多的像素位置。那么就没有办法将移动的中间那些区域改成白色,但是若使用的是两点之间的方法,那么我只需要知道每一次检测的时候,鼠标的坐标点即可,通过两个点就可以连接处一个轨迹。可以看出,若想绘制运动轨迹,最好的方式就是使用两点连线的形式,但是若鼠标移动的过慢,那么两种方法的结果是一样的。