【OpenCV 4开发详解】窗口交互操作

本文首发于 “小白学视觉”微信公众号,欢迎关注公众号
本文作者为小白,版权归 人民邮电出版社发行所有,禁止转载,侵权必究!

经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

交互操作能够增加用户对程序流程的控制,使得程序可以根据用户需求实现不同的处理结果。有时某一个参数作用需要反复尝试不同的数值,这时交互操作可以实现在程序运行过程中改变参数数值,避免重复运行程序,节省时间同时能够增加结果的对比效果。本节中将介绍OpenCV 4中提供的图像窗口滑动条和鼠标交互响应两种窗口交互操作。

图像窗口滑动条

图像窗口滑动条,顾名思义就是在显示图像的窗口中创建能够通过滑动改变数值的滑动条。有时我们需要动态调节某些参数,以使图像处理的效果更加明显,能够改变参数数值的滑动条可以很好的胜任这项工作。OpenCV 4中通过createTrackbar()函数在显示图像的窗口上创建滑动条,该函数的函数原型在代码清单3-54中给出。

代码清单3-54 createTrackbar()函数原型
1.	int cv::createTrackbar(const String &  trackbarname,
2.	                           const String &  winname,
3.	                           int *  value,
4.	                           int  count,
5.	                           TrackbarCallback  onChange = 0,
6.	                           void *  userdata = 0 
7.	                           )
  • trackbarname:滑动条的名称
  • winname:创建滑动条窗口的名称。
  • value:指向整数变量的指针,该指针指向的值反映滑块的位置,创建后,滑块位置由此变量定义。
  • count:滑动条的最大取值。
  • onChange:每次滑块更改位置时要调用的函数的指针。该函数应该原型为void Foo(int,void *);,其中第一个参数是轨迹栏位置,第二个参数是用户数据。如果回调是NULL指针,则不会调用任何回调,只更新数值。
  • userdata:传递给回调函数的可选参数

该函数能够在图像窗口的上方创建一个范围从0开始的整数滑动条,由于滑动条只能输出整数,如果需要得到小数,必须进行后续处理,例如输出值除以10得到含有1位小数的数据。函数第一个参数是滑动条的名称,第二个参数是创建滑动条的图像窗口的名称。第三个参数是指向整数变量的指针,该指针指向的值反映滑块的位置,在创建滑动条时该参数确定了滑动块的初始位置,当滑动条创建完成后,该指针指向的整数随着滑块的移动而改变。第四个参数是滑动条的最大取值。第五个参数是每次滑块更改位置时要调用的函数的指针。该函数应该原型为void Foo(int,void *),其中第一个参数是轨迹栏位置,第二个参数是用户数据,如果回调是NULL指针,则不会调用任何回调,只更新数值。最后一个参数是传递给回调函数的void *类型数据,如果使用的第三个参数是全局变量,可以不用忽略最后一个参数,使用参数的默认值即可。

为了了解滑动条动态改变参数的方法以及动态参数在程序中的作用,在代码清单3-55中给出了通过滑动条改变图像亮度的示例程序。程序中滑动条控制图像亮度系数,将图像原始灰度值乘以亮度系数得到最终的图像。为了使图像亮度变化比较平滑,将滑动条参数除以100以得到含有两位小数的亮度系数。为了保证每次亮度的改变都是在原始图像的基础上,设置了两个表示图像的img1、 img2全局变量,其中img1表示原始图像,img2表示亮度改变后的图像。程序中,通过拖拽滑动块可以动态的改变图像的亮度,运行结果在图3-34中给出。

代码清单3-55 myCreateTrackbar.cpp在图像中创建滑条改变图像亮度
1.	#include <opencv2/opencv.hpp>
2.	#include <iostream>
3.	
4.	using namespace std;
5.	using namespace cv;
6.	
7.	//为了能在被调函数中使用,所以设置成全局的
8.	int value;
9.	void callBack(int, void*);  //滑动条回调函数
10.	Mat img1, img2;
11.	
12.	int main()
13.	{
14.		img1 = imread("lena.png");
15.		if (!img1.data)
16.		{
17.			cout << "请确认是否输入正确的图像文件" << endl;
18.			return -1;
19.		}
20.		namedWindow("滑动条改变图像亮度");
21.		imshow("滑动条改变图像亮度", img1);
22.		value = 100;  //滑动条创建时的初值
23.		//创建滑动条
24.		createTrackbar("亮度值百分比", "滑动条改变图像亮度", &value, 600, callBack, 0);
25.		waitKey();
26.	}
27.	
28.	static void callBack(int, void*)
29.	{
30.		float a = value / 100.0;
31.		img2 = img1 * a;
32.		imshow("滑动条改变图像亮度", img2);
33.	}
图3-34 myCreateTrackbar.cpp程序中滑动条不同位置对图像亮度的改变

【OpenCV 4开发详解】窗口交互操作_第1张图片

鼠标响应

有时我们需要在图像中标记出重要的区域,这时通过鼠标可以很好的完成这项任务,因此OpenCV 4中也提供了鼠标响应相关函数setMouseCallback(),该函数的函数原型在代码清单3-56中给出。

代码清单3-56 setMouseCallback()函数原型
1.	void cv::setMouseCallback(const String &  winname,
2.	                               MouseCallback  onMouse,
3.	                               void *  userdata = 0 
4.	                               )
  • winname:添加鼠标响应的窗口的名字
  • onMouse:鼠标响应的回调函数。
  • userdata:传递给回调函数的可选参数。

该函数能够为指定的图像窗口创建鼠标响应。函数第一个参数是需要创建鼠标响应的图像窗口的名字。第二个参数为鼠标响应的回调函数,该函数在鼠标状态发生改变时被调用,是一个MouseCallback类型的函数。最后一个参数是传递给回调函数的可选参数,一般情况下使用默认值0即可。
接下来将介绍MouseCallback类型的回调函数,该类型函数的原型在代码清单3-57中给出。

代码清单3-57 MouseCallback类型原型
1.	typedef void(* cv::MouseCallback)(int  event, 
2.	                                         int  x, 
3.	                                         int  y, 
4.	                                         int  flags, 
5.	                                         void  *userdata
6.	                                         )
  • event:鼠标响应事件标志,参数为EVENT_*形式,具体可选参数及含义在表3-9给出。
  • x:鼠标指针在图像坐标系中的x坐标
  • y:鼠标指针在图像坐标系中的y坐标
  • flags:鼠标响应标志,参数为EVENT_FLAG_*形式,具体可选参数及含义在表3-10给出。
  • userdata:传递给回调函数的可选参数

MouseCallback类型的回调函数是一个无返回值的函数,函数名可以任意设置,有五个参数,在鼠标状态发生改变的时候被调用。函数第一个参数是鼠标响应事件标志,参数为EVENT_*形式,具体可选参数及含义在表3-9给出。第二个和第三个参数分别是鼠标当前位置在图像坐标系中的x坐标和y坐标。第四个参数是鼠标响应标志,参数为EVENT_FLAG_形式,具体可选参数及含义在表3-10给出。最后一个参数是传递给回调函数的可选参数,一般情况下用void缺省即可。

表3-9 MouseCallback类型回调函数鼠标响应事件标志可选参数及含义
标志参数 简记 含义
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 正值表示向左滚动,负值表示向右滚动
表3-10 MouseCallback类型回调函数鼠标响应标志及含义
标志参数 简记 含义
EVENT_FLAG_LBUTTON 1 按住左键拖拽
EVENT_FLAG_RBUTTON 2 按住右键拖拽
EVENT_FLAG_MBUTTON 4 按住中键拖拽
EVENT_FLAG_CTRLKEY 8 按下CTRL键
EVENT_FLAG_SHIFTKEY 16 按下SHIFT键
EVENT_FLAG_ALTKEY 32 按下ALT键

鼠标响应简单来说就是当鼠标位于对应的图像窗口内时,时刻检测鼠标状态,当鼠标状态发生改变时调用回调函数,根据回调函数中的判断逻辑选择执行相应的操作。例如回调函数中只处理鼠标左键按下的事件,即判断event标志是否为EVENT_LBUTTONDOWN,只有当event==EVENT_LBUTTONDOWN时才有相应的逻辑操作,否则将不会执行任何操作。

为了了解鼠标响应的使用方法,在代码清单3-58中给出了绘制鼠标移动轨迹的示例程序。程序中如果鼠标右键被按下,则会提示“点击鼠标左键才可以绘制轨迹”,点击左键会输出当前鼠标的坐标,并将该点坐标定义为某段轨迹的起始位置。之后按住左键移动鼠标,会进入到第三个逻辑判断,绘制鼠标的移动轨迹。示例程序中提供了两种绘制轨迹的方法,第一种是每次调用回调函数获得鼠标位置时更改周围的图像像素值,这种方式比较直观,但是由于回调函数有一定的执行时间,因此当鼠标移动较快时绘制的图像轨迹会出现断点。第二种绘制轨迹的方式是在前一时刻和当前时刻鼠标位置间绘制直线,这种方式可以避免因鼠标移动过快而带来的轨迹出现断点的问题。程序运行结果在图3-35给出。

代码清单3-58 myMouse.cpp绘制鼠标移动轨迹
1.	#include <opencv2/opencv.hpp>
2.	#include <iostream>
3.	
4.	using namespace std;
5.	using namespace cv;
6.	
7.	Mat img,imgPoint;  //全局的图像
8.	Point prePoint;  //前一时刻鼠标的坐标,用于绘制直线
9.	void mouse(int event, int x, int y, int flags, void*);
10.	
11.	int main()
12.	{
13.		img = imread("lena.png");
14.		if (!img.data)
15.		{
16.			cout << "请确认输入图像名称是否正确!" << endl;
17.			return -1;
18.		}
19.		img.copyTo(imgPoint);
20.		imshow("图像窗口1", img);
21.		imshow("图像窗口2", imgPoint);
22.		setMouseCallback("图像窗口1", mouse,0 );  //鼠标影响
23.		waitKey(0);
24.		return 0;
25.	}
26.	
27.	void mouse(int event, int x, int y, int flags, void*)
28.	{
29.		if (event == EVENT_RBUTTONDOWN)  //单击右键
30.		{
31.			cout << "点击鼠标左键才可以绘制轨迹" << endl;
32.		}
33.		if (event == EVENT_LBUTTONDOWN)  //单击左键,输出坐标
34.		{
35.			prePoint = Point(x, y);
36.			cout << "轨迹起使坐标" << prePoint << endl;
37.	
38.		}
39.		if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))  //鼠标按住左键移动
40.		{
41.			//通过改变图像像素显示鼠标移动轨迹
42.			imgPoint.at<Vec3b>(y, x) = Vec3b(0, 0, 255);
43.			imgPoint.at<Vec3b>(y, x-1) = Vec3b(0, 0, 255);
44.			imgPoint.at<Vec3b>(y, x+1) = Vec3b(0, 0, 255);
45.			imgPoint.at<Vec3b>(y+1, x) = Vec3b(0, 0, 255);
46.			imgPoint.at<Vec3b>(y+1, x) = Vec3b(0, 0, 255);
47.			imshow("图像窗口2", imgPoint);
48.	
49.			//通过绘制直线显示鼠标移动轨迹
50.			Point pt(x, y);
51.			line(img, prePoint, pt, Scalar(0, 0, 255), 2, 5, 0);
52.			prePoint = pt;
53.			imshow("图像窗口1", img);
54.		}
55.	}
【OpenCV 4开发详解】窗口交互操作_第2张图片
图3-35 myMouse.cpp程序中绘制的鼠标移动轨迹

 

OpenCV 4开发详解
往期推荐
【OpenCV 4开发详解】Windows系统中安装OpenCV 4
【OpenCV 4开发详解】Ubuntu系统中安装OpenCV 4
【OpenCV 4开发详解】opencv_contrib扩展模块的安装
【OpenCV 4开发详解】Image Watch插件的使用
【OpenCV 4开发详解】安装过程中问题解决方案
【OpenCV 4开发详解】了解OpenCV的模块架构
【OpenCV 4开发详解】Mat类介绍
【OpenCV 4开发详解】Mat类构造与赋值
【OpenCV 4开发详解】4种读取Mat类元素的的方法
【OpenCV 4开发详解】图像的读取与显示
【OpenCV 4开发详解】视频加载与摄像头调用
【OpenCV 4开发详解】图像与视频的保存
【OpenCV 4开发详解】保存和读取XML和YMAL文件
【OpenCV 4开发详解】颜色模型与转换
【OpenCV 4开发详解】多通道分离与合并
【OpenCV 4开发详解】图像像素统计
【OpenCV 4开发详解】两图像间的像素操作
【OpenCV 4开发详解】图像二值化
【OpenCV 4开发详解】图像LUT查找表
【OpenCV 4开发详解】图像连接
【OpenCV 4开发详解】图像仿射变换
【OpenCV 4开发详解】图像透视变换
【OpenCV 4开发详解】图像极坐标变换
【OpenCV 4开发详解】图像上绘制几何图形
【OpenCV 4开发详解】图像金字塔
经过几个月的努力,市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》将春节后由人民邮电出版社发行。如果小伙伴觉得内容有帮助,希望到时候多多支持!
关注小白的小伙伴可以提前看到书中的内容,我们创建了学习交流群,欢迎各位小伙伴添加小白微信加入交流群,添加小白时请备注“学习OpenCV 4”。

你可能感兴趣的:(OpenCV,4开发详解)