个人资料,仅供学习使用
修改时间——2022年1月23日 17:59:14
学习课程:OpenCV4 C++ 快速入门视频30讲
视频老师:贾志刚

17 鼠标操作与响应

opencv知识点:

  • 设置指定窗口的鼠标处理程序 - setMouseCallback
  • 鼠标事件回调函数 - MouseCallback(通常用户自定义)
  • 简单提取矩形ROI区域 - image(box)

本课所解决的问题:

  • 如何通过鼠标绘制矩形?
  • 如何通过矩形选择ROI区域?

1.鼠标事件

要想在图像上,通过鼠标绘制图形,我们需要了解两个API

  • setMouseCallback
  • MouseCallback类型的回调函数

setMouseCallback

setMouseCallback();
/*
setMouseCallback设置指定窗口的鼠标处理程序共3个参数第1个参数 窗口名称第2个参数 处理鼠标事件的回调函数第3个参数 传递给回调函数的可选参数
*/

MouseCallback

关于自定义MouseCallback(鼠标事件回调函数)
这里说明一下,我们自定义的时候要注意的参数问题

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

2.通过鼠标绘制矩形

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

  • 左键按下 - 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();
}

3.通过矩形选择ROI区域

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

这里要注意几点

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


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();
}

本课所用API查阅

1.setMouseCallback


2.MouseCallback

3.MouseEventFlags



4.MouseEventTypes

【个人笔记】OpenCV4 C++ 快速入门 17课相关推荐

  1. 【个人笔记】OpenCV4 C++ 快速入门 22课

    个人资料,仅供学习使用 修改时间--2022年1月25日 22:09:17 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 22 视频文件摄像头使用 opencv知识点: VI ...

  2. 【个人笔记】OpenCV4 C++ 快速入门 19课

    个人资料,仅供学习使用 修改时间--2022年1月24日 20:17:13 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 19 图像放缩与插值 opencv知识点: 图像放缩 ...

  3. 【个人笔记】OpenCV4 C++ 快速入门 29课

    个人资料,仅供学习使用 修改时间--2022年2月19日 15:02:27 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 29 高斯双边模糊 opencv知识点: 高斯双边模 ...

  4. 【个人笔记】OpenCV4 C++ 快速入门 26课

    个人资料,仅供学习使用 修改时间--2022年2月13日 20:49:07 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 26 直方图均衡化 opencv知识点: 均衡灰度图 ...

  5. 【个人笔记】OpenCV4 C++ 快速入门 25课

    个人资料,仅供学习使用 修改时间--2022年2月13日 20:45:23 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 25 二维直方图 opencv知识点: 计算直方图数 ...

  6. 【个人笔记】OpenCV4 C++ 快速入门 23课

    个人资料,仅供学习使用 修改时间--2022年1月26日 00:49:43 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 23 视频处理与保存 opencv知识点: Vide ...

  7. 【个人笔记】OpenCV4 C++ 快速入门 20课

    个人资料,仅供学习使用 修改时间--2022年1月24日 22:09:02 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 20 图像翻转 opencv知识点: 图像翻转 - ...

  8. 【个人笔记】OpenCV4 C++ 快速入门 14课

    个人资料,仅供学习使用 修改时间--2022年2月13日 09:47:32 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 14 图像几何形状绘制 opencv知识点: 四种几 ...

  9. 【个人笔记】OpenCV4 C++ 快速入门 13课

    个人资料,仅供学习使用 修改时间--2022年2月13日 09:03:23 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 13 图像像素值统计 opencv知识点: 图像像素 ...

最新文章

  1. 惨烈!程序员放弃了 Python!?发生了啥?
  2. 1.4.1.Documents,Fields和Schema概述
  3. 正则表达式学习笔记(一)
  4. 系统设计4:Web服务和流量限制
  5. 第二阶段冲刺-个人总结09
  6. YbtOJ-森林之和【dp】
  7. 为什么很多人上班好好的,却选择去创业?
  8. 微信公众号-注册最全6种类型接口权限,注册哪个好?
  9. 中国航空零部件制造行业业十四五投资发展规划及发展前景预测报告2022-2028年版
  10. 李克平教授讲座——《城市道路交叉口规划规范》解读与绿灯间隔(整理文本)...
  11. tortoise清理本地分支_如何删除TortoiseHg中的意外分支?
  12. 关于KNX/IP 网关协议报文解析以及几个注意事项
  13. 深度学习经典试题29道
  14. winUSB设备的开发方法
  15. PMP-PMBOK-培训(7)Initiating a Project and Preparing the Project Plan
  16. 专利修改:ps换填充色
  17. 虚拟实验工场计算机科学导论论文,计算机科学导论论文
  18. java贪吃蛇博客带图片_java课程设计--贪吃蛇小队博客
  19. minigui:静态编译连接mgncs库时遇到的xml2的问题
  20. 生成Code128A,Code128B,Code128C,EAN128条码

热门文章

  1. java语句while主意点
  2. topcoder srm 540 div1
  3. [摘译]js内存泄漏常见的四种情况
  4. Service通信详解
  5. 浅谈Listener、Filter、Servlet初始化顺序
  6. java中的equals和hashCode
  7. Screens的开发一
  8. Java编程书籍收集(高级)
  9. Git 使用明细,持续完善中......
  10. 学习笔记-数据结构与算法之二叉树