《OpenCV 4计算机视觉项目实战 》 —3.3 OpenCV的基本图形用户界面
3.3 OpenCV的基本图形用户界面
我们将使用OpenCV创建一个基本用户界面。OpenCV用户界面使我们能够创建窗口,然后在里面添加图像,并移动、调整大小和销毁所添加的图像。用户界面位于OpenCV的highui模块中。在下面的代码中,我们将学习如何创建和显示两个图像,具体来说,可以在桌面上通过按键来显示多个窗口,并使图像移入这些窗口中。
不要担心阅读完整的代码,我们会用小代码块来逐个解释它:
我们来理解这段代码:
1. 为了便于使用图形用户界面,第一项必须完成的任务是导入OpenCV的highui模块:
2. 完成创建新窗口的准备工作之后,我们必须加载一些图像:
3. 要创建窗口,我们使用namedWindow函数。该函数有两个参数。第一个参数是带有窗口名称的常量字符串,第二个参数是我们需要的标志,第二个参数是可选的:
4. 在这个例子中,我们创建了两个窗口:第一个叫作Lena,第二个叫作Photo。
对于Qt和原生界面,默认有三个标志:
WINDOW_NORMAL:此标志允许用户调整窗口的大小
WINDOW_AUTOSIZE:如果设置了此标志,则窗口大小为自动调整以适应显示图像,但不能调整窗口的大小
WINDOW_OPENGL:此标志启用OpenGL支持
Qt有许多额外的标志:
WINDOW_FREERATIO或WINDOW_KEEPRATIO:如果设置了WINDOW_FREERATIO,则调整图像时不考虑其比例。如果设置了WINDOW_KEEPRATIO,则根据其比例调整图像。
WINDOW_GUI_NORMAL或WINDOW_GUI_EXPANDED:第一个标志提供没有状态栏和工具栏的基本界面。第二个标志使用状态栏和工具栏来支持最高级的图形用户界面。
如果使用Qt编译OpenCV,默认情况下,我们创建的所有窗口都在展开的界面中,但我们可以添加CV_GUI_NORMAL标志使用原生界面和更基本的界面。默认情况下,标志为WINDOW_AUTOSIZE、WINDOW_KEEPRATIO和WINDOW_GUI_EXPANDED。
5. 当创建多个窗口时,它们是叠加的,但我们可以使用moveWindow函数将窗口移动到桌面的任何区域,如下所示:
6. 在这段代码中,我们将Lena窗口向左移动了10个像素,向上移动了10个像素,将Photo窗口向左移动了520个像素,向上移动了10个像素。
在使用imshow函数显示此前加载的图像之后,我们通过调用resizeWindow函数将Lena窗口的大小调整为512像素,该函数有三个参数:window name、width和height。
具体的窗口大小是指图像区域,工具栏不计算在内,只有未启用WINDOW_AUTOSIZE标志的窗口才能调整大小。
7. 在利用waitKey函数等待按键按下之后,我们用destroyWindow函数删除这个窗口,其中,窗口的名称是唯一需要的参数:
8. OpenCV可以通过一次调用删除所创建的所有窗口,该函数称为destroyAllWindows。为了演示它是如何工作的,我们在样本中创建10个窗口,然后等待按键按下。当用户按下任意键时,它就会销毁所有得窗口:
在任何情况下,OpenCV都会在应用程序终止时自动销毁所有窗口,因此在我们的应用程序结束时不必调用此函数。
所有这些代码的结果可以在以下图像中看到。首先,它显示两个窗口,如图3-2所示。
按下任意键之后,应用程序继续运行,并在不同的位置绘制出几个窗口,如图3-3所示。
只需几行代码,我们就可以创建和操作窗口并显示图像。我们现在已经准备好进行用户与图像的交互,并添加用户界面控件。
图 3-2
图 3-3
将滑块和鼠标事件添加到界面
鼠标事件和滑块控件在计算机视觉和OpenCV中非常有用。使用这些控件,可以直接与界面交互,并改变输入图像或变量的属性。在本节中,我们将介绍用于基本交互的鼠标事件和滑块控件。为了便于正确理解,我们创建了以下代码,通过这些代码,我们将使用鼠标事件在图像中绘制绿色圆圈,并使用滑块对图像进行模糊处理:
我们来理解这段代码。
首先,创建一个变量来保存滑块位置。我们需要保存滑块位置,以便从其他函数访问它:
现在,为滑块和鼠标事件定义回调函数,这是OpenCV的setMouseCallback函数和createTrackbar函数必需的:
在main函数中,加载一个图像并创建一个名为Lena的新窗口:
现在创建滑块。OpenCV的createTrackbar函数用于生成滑块,其参数按顺序如下所示:
1. 跟踪条名称。
2. 窗口名称。
3. 将作为值使用的整数指针。该参数是可选的,如果被设置,则滑块会在创建时获得该位置。
4. 滑块上的最大位置。
5. 滑块位置变化时的回调函数。
6. 要发送到回调函数的用户数据。它可用于在不使用全局变量的情况下将数据发送到回调函数。
对于这段代码,我们为Lena窗口添加了trackbar,然后调用Lena跟踪条对图像进行模糊处理。跟踪条的值存储在将会作为指针传递的blurAmount整数中,并将跟踪条的最大值设置为30。把onChange设置为回调函数,并将lena mat图像作为用户数据发送:
滑块创建好以后,当用户单击鼠标左键时,我们添加鼠标事件来绘制圆形。这需要使用OpenCV的setMouseCallback函数,该函数有三个参数:
获取鼠标事件的窗口名称。
当有任何鼠标交互时调用的回调函数。
用户数据:这是在触发时将要发送给回调函数的任意数据。在这个例子中,我们将会发送整个Lena图像。
使用以下代码,可以向Lena窗口添加鼠标回调,并将onMouse设置为回调函数,从而将lena mat图像作为用户数据进行传递:
为了完成主函数,需要使用与滑块相同的参数来初始化图像。要执行初始化,只需调用onChange回调函数,并在使用destroyWindow关闭窗口之前等待事件,如下面的代码所示:
滑块回调函数使用滑块值作为模糊量,将基本的模糊滤镜应用于图像:
该函数使用变量pos来检查滑块值是否为0。在这种情况下,我们不使用过滤器,因为它会生成执行错误,也不能用0像素模糊。检查滑块值后,我们创建一个名为imgBlur的空矩阵来存储模糊结果。要检索通过回调函数中的用户数据发送的图像,必须把void * userData转换为正确的图像类型指针Mat*。
现在我们有了正确的变量来应用模糊滤镜。模糊函数将基本的中值滤波器应用于输入图像,在这个例子中是* img。对于输出图像,最后需要的参数是想要应用的模糊内核的大小(内核是用于计算内核和图像之间卷积平均值的小矩阵)。在这个例子中使用的是pos大小的平方内核。最后,只需用imshow函数更新图像界面。
鼠标事件的回调函数有五个输入参数:第一个参数定义事件类型,第二个和第三个定义鼠标位置,第四个参数定义滚轮动作,第五个参数定义用户输入数据。
鼠标事件类型如下:
在这个例子中,我们只处理单击鼠标左键所产生的事件,并且丢弃除EVENT_LBUTTONDOWN之外的任何事件。丢弃其他事件后,用滑块回调获取输入图像,并用OpenCV的circle函数获取图像中的圆:
- 点赞
- 收藏
- 关注作者
评论(0)