C++ OpenCV #007 鼠标操作

opencv的setMouseCallback()函数能够监听鼠标的操作与响应,此函数会在调用之后不断查询鼠标信息直到窗口销毁


1. 鼠标监听与响应

  • 注意操作范围是在图像范围,在创建或读取的图像中点击鼠标才能监听

  • 监听事件:按下鼠标,鼠标移动,鼠标弹起

  • 响应:当监听到相应的事件时,我们可以编写对应的响应



2. 测试

  • 函数原型:setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);

    winname:窗口名称

    onMouse:回调函数名称

    userdata:用户数据

  • 回调函数:on_mouse(int event, int x, int y, int flags, void* userdata)

    event:监听的事件

    x:当前x坐标

    y:当前y坐标

    flags:代表鼠标的拖拽事件

    userdata:用户数据

  • 常用的监听事件:

    // Event:
     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         //中键双击
    
    // FLAG:
    EVENT_FLAG_LBUTTON 1           //左鍵拖曳
    EVENT_FLAG_RBUTTON 2           //右鍵拖曳
    EVENT_FLAG_MBUTTON 4           //中鍵拖曳
    EVENT_FLAG_CTRLKEY 8           //(8~15)按Ctrl不放事件
    EVENT_FLAG_SHIFTKEY 16         //(16~31)按Shift不放事件
    EVENT_FLAG_ALTKEY 32           //(32~39)按Alt不放事件
    
  • 程序:注意,旧版本事件需要加CV_,新版本取消

    #include <opencv2/opencv.hpp>
    #include <opencv2/core/utils/logger.hpp>
    #include<iostream>
    using namespace std;
    using namespace cv;
    
    int  num; //记录调用次数
    
    void close_log() {
        utils::logging::setLogLevel(utils::logging::LOG_LEVEL_ERROR);
    }
    
    //鼠标回调函数
    void on_mouse(int event, int x, int y, int flags, void* userdata)
    {
    	num++;
    	cout << "第 " << num << " 次回调鼠标事件" << endl;
    	if (event == EVENT_MOUSEMOVE)
    	{
    		cout << "触发鼠标移动事件" << endl;
    	}
    	if (event == EVENT_LBUTTONDOWN)
    	{
    		cout << "触发左键按下事件" << endl;
    	}
    	if (event == EVENT_LBUTTONUP)
    	{
    		cout << "触发左键抬起事件" << endl;
    	}
    	if (event == EVENT_RBUTTONDOWN)
    	{
    		cout << "触发右键按下事件" << endl;
    	}
    	if (event == EVENT_RBUTTONUP)
    	{
    		cout << "触发右键抬起事件" << endl;
    	}
    	if (event == EVENT_LBUTTONDBLCLK)
    	{
    		cout << "触发左键双击事件" << endl;
    	}
    	if (event == EVENT_RBUTTONDBLCLK)
    	{
    		cout << "触发右键双击事件" << endl;
    	}
    }
    
    int main()
    {
    	// 关闭日志
    	close_log();
    
    	// 创建画布
    	Mat image(512, 512, CV_8UC3, Scalar(0, 0, 0));
    
    	imshow("image", image);
    	// 鼠标事件监听
    	setMouseCallback("image", on_mouse, 0);
    	waitKey();
    	system("pause");
    }
    
  • 运行结果:注意要在图像范围内操作鼠标才会被监听



3. 案例:

使用鼠标进行动态矩形绘制

#include <opencv2/opencv.hpp>
#include <opencv2/core/utils/logger.hpp>
#include<string>
#include<iostream>
using namespace std;
using namespace cv;

// 定义全局变量
Mat canvas(512, 512, CV_8UC3, Scalar(0, 0, 0));
Mat temp = canvas.clone(); // 把原图复制一份
Point pt;
bool flag;

void close_log() {
    utils::logging::setLogLevel(utils::logging::LOG_LEVEL_ERROR);
}

void on_mouse(int event, int x, int y, int flags, void* userdata) {
    // 先把 void* 转为 Mat* 再解引用,即img和canvas指向同一个数据
    // Mat canvas = *(Mat*)userdata;

    switch (event) {
    case EVENT_LBUTTONDOWN:
		  // 添加点pt,接收鼠标左键按下时的(x,y)
        pt.x = x;
        pt.y = y;
        // 鼠标左键按下后,flag置为真
        flag = true;
        break;
    case EVENT_MOUSEMOVE:
        if (flag) {
            // 把 temp 拷贝给 canvas,temp为源图片(无任何内容)
            // 每移动鼠标,先把画布用原图覆盖,再绘制矩形
            temp.copyTo(canvas);
			  // 画矩形的两点,point1 按下鼠标的点,point2 鼠标移动的点
            rectangle(canvas, Point(pt.x, pt.y), Point(x, y), Scalar(0, 0, 255), 1, 8, 0);
        }
        break;
    case EVENT_LBUTTONUP:
        // 鼠标左键按弹起,flag置为假。
        flag = false;
        break;
    default:
        break;
    }

}

void image_process() {
    namedWindow("draw", WINDOW_AUTOSIZE);
    setMouseCallback("draw", on_mouse, 0);

    // 不断调用回调函数,如果waitKey(0)则会堵塞窗口
    while (1) {
        imshow("draw", canvas);
        if (waitKey(10) == 27) {
            break;
        }
    }
}

int main() {
    close_log();
    image_process();
    return 0;
}

运行结果:

posted @ 2023-06-28 23:06  枫_Null  阅读(351)  评论(0)    收藏  举报