opencv鼠标事件函数setMouseCallback()详解

opencv鼠标事件函数setMouseCallback()详解
1、鼠标事件函数:
(1)鼠标事件函数原型:setMouseCallback(),此函数会在调用之后不断查询回调函数onMouse(),直到窗口销毁
  void setMouseCallback(
	const String& winname, 
	MouseCallback onMouse, 
	void* userdata = 0
)

参数解释:
 winname:窗口名称;
 onMouse:回调函数;
 userdata:传递给回调函数用户自定义的外部数据,userdata是一个 void 类型的指针;

(2)回调函数onMouse(),可随意命名,但是要与 setMouseCallback()函数里的回调函数名称一致
void onMouse(
	int event, 
	int x, 
	int y, 
	int flags, 
	void *userdata
) 

参数解释:
event:表示鼠标事件类型的常量(
	#define CV_EVENT_MOUSEMOVE 0             //滑动
	#define CV_EVENT_LBUTTONDOWN 1           //左键点击
	#define CV_EVENT_RBUTTONDOWN 2           //右键点击
	#define CV_EVENT_MBUTTONDOWN 3           //中键点击
	#define CV_EVENT_LBUTTONUP 4             //左键放开
	#define CV_EVENT_RBUTTONUP 5             //右键放开
	#define CV_EVENT_MBUTTONUP 6             //中键放开
	#define CV_EVENT_LBUTTONDBLCLK 7         //左键双击
	#define CV_EVENT_RBUTTONDBLCLK 8         //右键双击
	#define CV_EVENT_MBUTTONDBLCLK 9         //中键双击
);
x和y:鼠标指针在图像坐标系的坐标;
flags:鼠标事件标志的常量;
userdata:回调函数接收,用户自定义的外部数据,userdata是一个 void 类型的指针;

2、代码示例:

利用鼠标事件函数,提取ROI区域:

(1)main.cpp
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    
	//读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy4.jpg");
	if (src.empty()) {
    
    
		printf("could not load image..../n");
		return -1;
	}

	Demo demo;
	demo.mouseEvent(src);

	waitKey();
	destroyAllWindows();
	return 0;
}
(2)头文件demo.h
#include <opencv2/opencv.hpp>

using namespace cv;

class Demo
{
    
    
public:
	void mouseEvent(Mat &image);
private:

};

(3)demo.cpp
#include <Demo.h>

using namespace std;

Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void onMouse(int event, int x, int y, int flags, void *userdata) {
    
    
	/**
	* 对指针userdata,进行转换和解引用的操作,将userdata指向的Mat对象,赋值给名为image的变量,以便后续对图像数据的处理:
	* userdata是一个void类型的指针,需要转换为Mat类型的指针,然后用*运算符解引用,得到Mat对象,再赋值给名为image的变量,这样就可以对image进行操作了;
	*/
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {
    
    
		// 起点坐标
		sp.x = x;
		sp.y = y;
		std::cout << "start point:" << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {
    
    
		ep.x = x;
		ep.y = y;
		// 结束点坐标
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {
    
    
			Rect box(sp.x, sp.y, dx, dy);
			temp.copyTo(image);
			imshow("ROI区域", image(box));
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			imshow("鼠标绘制", image);
			// ready for next drawing
			sp.x = -1;
			sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
    
    
		if (sp.x > 0 && sp.y > 0) {
    
    
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0) {
    
    
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(image);
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
			}
		}
	}
}

void Demo::mouseEvent(Mat &image) {
    
    
	namedWindow("鼠标事件", WINDOW_AUTOSIZE);

	/**
	* 由于回调函数需要传入的是一个void类型指针,我们先取image的地址,再将&image强制转换为void类型指针,具体操作如下:
	* &image:获取变量image的内存地址,即Mat对象的指针;
	* (void*):是一个强制类型转换,将image的地址转换为void类型指针,这样就可以将参数传递给回调函数了;
	*/
	setMouseCallback("鼠标绘制", onMouse, (void*)(&image));
	imshow("鼠标绘制", image);
	temp = image.clone();
}

(4)效果演示

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_33867131/article/details/132583785