1.API

setMouseCallback   设置指定窗口的鼠标处理程序

共3个参数第1个参数 窗口名称第2个参数 处理鼠标事件的回调函数第3个参数 传递给回调函数的可选参数

MouseCallback类型的函数 鼠标回调函数

   共5个参数,这5个参数全是针对鼠标的捕捉第1个参数 捕捉的鼠标事件(查阅文档可知,都有什么类型)第2个参数 捕捉的鼠标事件的x坐标第3个参数 捕捉的鼠标事件的y坐标第4个参数 标志捕捉的事件是哪一个键(有5种,查阅文档可知)第5个参数 void*类型的可选传入数据

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:
EVENT_FLAG_LBUTTON 1 按下左键
EVENT_FLAG_RBUTTON 2 按下右键
EVENT_FLAG_MBUTTON 4 按下中键
EVENT_FLAG_CRTLKEY 8 按下ctrl键
EVENT_FLAG_SHIFTKEY 16 按下shift键
EVENT_FLAG_ALTKEY 32 按下alt键

2.实例代码 应用

注:

1、因为自定义的on_draw方法有接收userdata参数,所以setMouseCallback的userdata一定要传,不然程序直接异常结束

2、用rectangle函数画完矩形一定要及时更新图像(imshow),不然绘制不出来

3、要想看到鼠标的整个绘制过程,要添加EVENT_MOUSEMOVE事件,还要判断只有鼠标左键按下的时候才进行绘制,每次绘制结束的时候要复位

4、绘制时只想要绘制一个,每次绘制前,前面一个图就要檫除,可以先保存一下原图,temp = image.clone();然后到绘制的时候 temp.copyTo(image);完成对前面绘制矩形的檫除

5、可以绘制矩形后要想提取ROI区域,用imshow("ROI area", image(box));

6、矩形的绘制一定要在窗口里面(可完善)

通过鼠标绘制矩形

为了演示通过鼠标绘制矩形,我们选择三个鼠标事件

左键按下 - EVENT_LBUTTONDOWN
鼠标移动 - EVENT_MOUSEMOVE
左键松开 - EVENT_LBUTTONUP

这里要注意几点

setMouseCallback要传入窗口的名字,所以要使用namedWindow事先创建一个窗口,不然会报错
我们绘制矩形的时候,如果终点在图像外就会报错,只要根据if判断即可,不过本文没有处理
我们这里,实现了通过鼠标在四个区域绘制矩形

无轨迹

//函数定义
void mouse_drawing_demo(Mat& image);
//函数实现
Point sp(-1, -1), ep(-1, -1);
static void on_draw(int event, int x, int y, int flags, void* userdata) {Mat image = *((Mat*)userdata);if (event == EVENT_LBUTTONDOWN) {//左键按下sp.x = x;sp.y = y;std::cout << "起点:" << sp;}if (event == EVENT_LBUTTONUP) {//左键松开ep.x = x;ep.y = y;std::cout << "终点:" << ep << std::endl;int w = ep.x - sp.x;int h = ep.y - sp.y;if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x+w, sp.y+h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x+w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y+h, w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);}imshow("鼠标绘制矩形", image);}
}void QuickDemo::mouse_drawing_demo(Mat& image) {namedWindow("鼠标绘制矩形", WINDOW_AUTOSIZE);setMouseCallback("鼠标绘制矩形", on_draw, (void*)(&image));imshow("鼠标绘制矩形", image);}

第二版 - 增加绘制轨迹

Point sp(-1, -1), ep(-1, -1);
static void on_draw(int event, int x, int y, int flags, void* userdata) {Mat image = *((Mat*)userdata);if (event == EVENT_LBUTTONDOWN) {//左键按下sp.x = x;sp.y = y;std::cout << "起点:" << sp;}if (flags == EVENT_FLAG_LBUTTON && event == EVENT_MOUSEMOVE) {//按下左键+鼠标移动ep.x = x;ep.y = y;int w = ep.x - sp.x;int h = ep.y - sp.y;if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x + w, sp.y + h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x + w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y + h, w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);}imshow("鼠标绘制矩形", image);}if (event == EVENT_LBUTTONUP) {//左键松开ep.x = x;ep.y = y;std::cout << "终点:" << ep << std::endl;int w = ep.x - sp.x;int h = ep.y - sp.y;if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x+w, sp.y+h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x+w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y+h, w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);}imshow("鼠标绘制矩形", image);}
}
void QuickDemo::mouse_drawing_demo(Mat& image) {namedWindow("鼠标绘制矩形", WINDOW_AUTOSIZE);setMouseCallback("鼠标绘制矩形", on_draw, (void*)(&image));imshow("鼠标绘制矩形", image);}

第三版 - 只保留最新的绘制轨迹

Point sp(-1, -1), ep(-1, -1);
Mat temp;//保存最初图像
static void on_draw(int event, int x, int y, int flags, void* userdata) {Mat image = *((Mat*)userdata);if (event == EVENT_LBUTTONDOWN) {//左键按下sp.x = x;sp.y = y;std::cout << "起点:" << sp;}if (flags == EVENT_FLAG_LBUTTON && event == EVENT_MOUSEMOVE) {//按下左键+鼠标移动ep.x = x;ep.y = y;int w = ep.x - sp.x;int h = ep.y - sp.y;temp.copyTo(image);if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x + w, sp.y + h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x + w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y + h, w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);}imshow("鼠标绘制矩形", image);}if (event == EVENT_LBUTTONUP) {//左键松开ep.x = x;ep.y = y;std::cout << "终点:" << ep << std::endl;int w = ep.x - sp.x;int h = ep.y - sp.y;if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x+w, sp.y+h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x+w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y+h, w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);}imshow("鼠标绘制矩形", image);}
}void QuickDemo::mouse_drawing_demo(Mat& image) {namedWindow("鼠标绘制矩形", WINDOW_AUTOSIZE);setMouseCallback("鼠标绘制矩形", on_draw, (void*)(&image));imshow("鼠标绘制矩形", image);temp = image.clone();
}

通过矩形选择ROI区域

copyto是直接覆盖,clone是复制

需要在开始时候复制,监听时候覆盖

接下来,我么试一下通过绘制矩形提取ROI区域

Point sp(-1, -1), ep(-1, -1);
Mat temp;//保存最初图像
static void on_draw(int event, int x, int y, int flags, void* userdata) {Mat image = *((Mat*)userdata);if (event == EVENT_LBUTTONDOWN) {//左键按下sp.x = x;sp.y = y;std::cout << "起点:" << sp;}if (flags == EVENT_FLAG_LBUTTON && event == EVENT_MOUSEMOVE) {//按下左键+鼠标移动temp.copyTo(image);//恢复最初图像ep.x = x;ep.y = y;int w = ep.x - sp.x;int h = ep.y - sp.y;if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x + w, sp.y + h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x + w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y + h, w, -h), Scalar(0, 0, 255), 2, 8, 0);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);}imshow("鼠标绘制矩形", image);}if (event == EVENT_LBUTTONUP) {//左键松开ep.x = x;ep.y = y;std::cout << "终点:" << ep << std::endl;int w = ep.x - sp.x;int h = ep.y - sp.y;Rect box;//提取ROI用if (w < 0 && h < 0) {//↖rectangle(image, Rect(sp.x+w, sp.y+h, -w, -h), Scalar(0, 0, 255), 2, 8, 0);box = Rect(sp.x + w, sp.y + h, -w, -h);}if (w < 0 && h >= 0) {//↙rectangle(image, Rect(sp.x+w, sp.y, -w, h), Scalar(0, 0, 255), 2, 8, 0);box = Rect(sp.x + w, sp.y, -w, h);}if (w >= 0 && h < 0) {//↗rectangle(image, Rect(sp.x, sp.y+h, w, -h), Scalar(0, 0, 255), 2, 8, 0);box = Rect(sp.x, sp.y + h, w, -h);}if (w >= 0 && h >= 0) {//↘rectangle(image, Rect(sp.x, sp.y, w, h), Scalar(0, 0, 255), 2, 8, 0);box = Rect(sp.x, sp.y, w, h);}imshow("鼠标绘制矩形", image);imshow("ROI区域",temp(box));}
}void QuickDemo::mouse_drawing_demo(Mat& image) {namedWindow("鼠标绘制矩形", WINDOW_AUTOSIZE);setMouseCallback("鼠标绘制矩形", on_draw, (void*)(&image));imshow("鼠标绘制矩形", image);temp = image.clone();
}

这里要注意几点

因为这只是一种简单的,通过矩形进行的ROI提取,提取的区域有时会有一些问题。
比如:提取矩形ROI区域时,如果box的width比较小,就会出现部分覆盖提取的问题。

C++ opencv 鼠标事件响应相关推荐

  1. Python,OpenCV鼠标事件进行矩形、圆形的绘制(随机颜色、随机半径)

    Python,OpenCV鼠标事件进行矩形.圆形的绘制(随机颜色.随机半径) 1. 效果图 2. 源码 参考 这篇博客将介绍鼠标事件,并介绍鼠标事件矩形.圆形的绘制: 所有的鼠标事件(左键按下.左键释 ...

  2. Day 2 - Opencv 鼠标事件回调并在图像上显示像素值

    Day 2 - Opencv 鼠标事件回调并在图像上显示像素值 #include <highgui.hpp> #include <opencv.hpp> #include &l ...

  3. openCV鼠标事件实例

    1.原理 OpenCV的鼠标事件主要涉及两个函数: 回调函数cvSetMouseCallback void cvSetMouseCallback( const char* window_name, C ...

  4. OpenCV鼠标事件和滑动条事件

    鼠标事件 ① 鼠标事件是通过传统的回调函数机制来完成. void your_mouse_callback(int event, int x, int y, int flags, void* param ...

  5. opencv 鼠标事件

    import cv2 as cv events = [i for i in dir(cv) if 'EVENT' in i] print( events ) # 打印所有的鼠标事件 import nu ...

  6. opencv画框返回坐标 python_python opencv鼠标事件实现画框圈定目标获取坐标信息

    本文实例为大家分享了python-opencv鼠标事件画框圈定目标的具体代码,供大家参考,具体内容如下 在视频/相机中,用鼠标画矩形框,圈定目标,从而获得鼠标的起始坐标点a.终止坐标点b # -*- ...

  7. opencv控制鼠标事件

    1.基础知识和API OpenCV允许我们对窗口上的鼠标动作做出响应.回调函数,就是执行以后会执行这个函数 cv2.setMouseCallback(winname, callback, userda ...

  8. Python机器视觉--OpenCV入门--鼠标事件与TrackBar控件(含小项目:OpenCV调色板)

    1.鼠标事件与TrackBar控件 1.1控制鼠标 OpenCV允许我们对窗口上的鼠标动作做出响应. setMouseCallback(winname, callback, userdata) win ...

  9. Opencv中的鼠标事件

    在Opencv当中的highgui模块中有大量可以用来处理图像的函数,他们可以使程序对鼠标或者键盘事件做出相应,也可以在图像上绘制形状或者写入文本. 这里主要说一下鼠标事件. 功能 通过编程,你可以让 ...

最新文章

  1. 异步socket的线程分配(C#)
  2. 小米电脑做开发java_JAVA学习系列之一-搭建开发环境
  3. windows server 2008 r2 enterprise ,惠普DL 580 G7服务器报,事件 ID: 47错误。
  4. 关于IDEA 的一些常用设置
  5. yii 2.0 代码阅读 小记
  6. Java.lang.Boolean类
  7. apk 签名v1与v2的区别
  8. 父路径_Logtail 新功能:采集路径黑名单
  9. 显示日期的指令: date
  10. MySQL 分组查询
  11. 分享3个数据分析实战项目(附最新资料包)
  12. php实现单例模式类singletonv,php设计模式 singleton (单例模式)
  13. 查看linux网络带宽
  14. python期望输出隐藏_【归纳综述】马尔可夫、隐马尔可夫 HMM 、条件随机场 CRF 全解析及其python实现...
  15. python qt gui快速编程 pdf_翻译:《用python和Qt进行GUI编程》——介绍
  16. Python中if判断语句在只有一个break子句时可以写在一行
  17. 微信支付?一起观摩Safesound勒索病毒的骚操作
  18. 如何修改Android APP的图标和名字
  19. 计算机界十位顶级人物!
  20. Windows下4K屏mobaxterm远程桌面设置

热门文章

  1. 动物伦理,为了人的尊严
  2. 谁是古代最风流的首席娱乐官?
  3. 算法提高 第五题 java 题解 1096
  4. 乡村振兴吹响品牌号角——首届中国乡村振兴品牌大会成功举办
  5. Unity 使用UGUI制作连连看小游戏
  6. 大数据的过去、现在和未来:万字长文解读《大数据四十二条》
  7. R.layout是什么?
  8. 猪是坚强的,所以取名朱坚强!
  9. 企业经营模拟——采购经理职责
  10. 面向对象编程的正确姿势