本章将介绍OpenCV中自带组件HighGUI的简单使用。当我们在测试算法,查看算法效果的时候,需要用到可视化,动态调参的界面,也可能需要监听鼠标,键盘等的动作,这时,HighGUI就发挥大作用了,HighGUI作为OpenCV的图形化(GUI)组件,可以通过HighGUI开发一些简易的上位机。
1 HighGUI所提供的接口类型
OpenCV的HighGUI提供了以下几种接口:
- 创建多个窗口,在窗口中显示图像
- 监听鼠标相关的操作
- 创建按钮,滑块等简单交互组件,并获取其值
下面将分别讲解该接口,最后通过一个综合案例了解该接口的使用。
2 HighGUI窗口
2.1 namedWindow接口
函数原型:
python3
None = cv.namedWindow(winname[, flags])
C++
void cv::namedWindow(const String & winname, int flags = WINDOW_AUTOSIZE )
该函数可以传入一些参数(flags)来实现窗口的一些设定。
设置选项1:窗口大小
- WINDOW_NORMAL 1 代表允许拖动窗口变换窗口大小。
- WINDOW_AUTOSIZE 0 默认根据屏幕跟图片的大小, 自动缩放。 不允许手动变化窗口大小。
设置选项2:设置宽高比
- WINDOW_FREERATIO 256 不固定宽高比。
- WINDOW_KEEPRATIO 0 默认固定宽高比, 也就是窗口拖拽缩放, 必须保持原来的宽高比。
设置选项3:窗口GUI版本
- WINDOW_GUI_NORMAL 16 旧版窗口组件。 不支持statusbar跟toolbar。 就是窗口上方的状态栏,工具栏。
- WINDOW_GUI_EXPANDED 0 默认新版本功能增强的GUI窗口。
一般地,我们想设置可以自由拖动,又不固定宽高比的窗口,那我们可以这样写:
python3
cv2.namedWindow('image_win', flags=cv2.WINDOW_NORMAL|cv2.WINDOW_FREERATIO|cv2.WINDOW_GUI_EXPANDED)
C++
namedWindow("image_win", WINDOW_NORMAL|WINDOW_FREERATIO|WINDOW_GUI_EXPANDED);
2.2 imshow接口
函数原型:
python3
None=cv.imshow(winname, mat)
C++
void cv::imshow(const String & winname,InputArray mat )
在这里,调用imshow函数时,如果”image_win”这个窗口之前并没有被声明,那么会先创建一个名字叫”image_win”的窗口,然后再更新这个窗口里面的图像。
该函数具体使用如下:
python3
cv2.imshow('image_win',img)
C++
imshow("image_win",img)
2.3 窗口销毁
该函数负责销毁窗口,但该函数对于小型项目而言,并不是很有必要,因为一般在程序结束时,会自动销毁窗口。该函数的具体使用如下:
python3
cv2.destroyWindow('image_win')
C++
destroyWindow("image_win")
3 HighGUI鼠标事件监听
3.1 鼠标支持的事件
首先,鼠标支持以下事件:
- EVENT_MOUSEMOVE 鼠标移动 Mouse Move
- EVENT_LBUTTONDOWN 鼠标左键点击 Left Button Down
- EVENT_RBUTTONDOWN 鼠标右键点击 Right Button Down
- EVENT_MBUTTONDOWN 鼠标中键点击 Middle Button Down
- EVENT_LBUTTONUP 鼠标左键抬起 Left Button Up
- EVENT_RBUTTONUP 鼠标右键抬起 Right Button Up
- EVENT_MBUTTONUP 鼠标中键抬起 Middle Button Up
- EVENT_LBUTTONDBLCLK 鼠标左键双击 Left Button Double Click
- EVENT_RBUTTONDBLCLK 鼠标右键双击 Right Button Double Click
- EVENT_MBUTTONDBLCLK 鼠标中键双击 Middle Button Double Click
3.2 鼠标支持的事件标志
- EVENT_FLAG_LBUTTON 左键正在按下
- EVENT_FLAG_RBUTTON 右键正在被按下
- EVENT_FLAG_MBUTTON 中键正在被按下
- EVENT_FLAG_CTRLKEY CTRL键正在被按下
- EVENT_FLAG_SHIFTKEY SHIFT键正在被按下
- EVENT_FLAG_ALTKEY ALT键正在被按下
3.3 鼠标事件回调函数及其设置
将通过一个案例来了解该函数的具体使用,在该案例中,只有当鼠标在移动,并且Ctrl和鼠标左键同时按下时,才打印出相关信息:
Python3:
def onMouse(event,x,y,flags,param):
if event == cv2.EVENT_MOUSEMOVE and flags == (cv2.EVENT_FLAG_LBUTTON|cv2.EVENT_FLAG_CTRLKEY ):
print(x)
print(y)
print(event)
print(flags)
cv2.setMouseCallback('image', onMouse)
C++:
static void onMouse( int event, int x, int y, int flags, void* )
{
if(event==EVENT_MOUSEMOVE)&&(flags==(EVENT_FLAG_LBUTTON|EVENT_FLAG_CTRLKEY))
{
printf("%d\r\n",x);
printf("%d\r\n",y);
printf("%d\r\n",event);
printf("%d\r\n",flags);
}
}
setMouseCallback("image", onMouse);
在回调函数中:
- event 鼠标事件类型,详见3.1中鼠标支持的事件
- x 鼠标当前在窗口Windows下的x坐标
- y 鼠标在当前窗口Windows下的y坐标
- flags 鼠标事件发生过程值中的一些其他事件标志/状态,详见3.2中鼠标支持的事件标志
- param 用户自定义的参数
4 HighGUI滑动条组件
将通过一个案例来演示如何使用滑动组件,在本案例中,首先通过简单案例演示滑动组件的基本使用,接着,来做一个彩色画布。
4.1 python3实现
简单案例,先演示如何使用滑动组件。
import cv2
cv2.namedWindow('image_win')
value = (0, 0, 0)
def update(x):
global value
r_value = cv2.getTrackbarPos('R','image_win')
g_value = cv2.getTrackbarPos('G', 'image_win')
b_value = cv2.getTrackbarPos('B', 'image_win')
value = (r_value, g_value, b_value)
print('Update Value, value ={}'.format(value))
cv2.createTrackbar('R','image_win',0,255,update)
cv2.createTrackbar('G','image_win',0,255,update)
cv2.createTrackbar('B','image_win',0,255,update)
cv2.setTrackbarPos('R','image_win',125)
cv2.setTrackbarPos('G','image_win',125)
cv2.setTrackbarPos('B','image_win',125)
cv2.waitKey(0)
cv2.destroyAllWindows()
程序运行后的GUI界面如下图所示:
下面进阶案例,演示如何实现可变色画布
import cv2
import numpy as np
canvas = np.zeros((300,300,3), np.uint8)
color = (0, 0, 0)
def updateImage():
global color
canvas[:,:] = color
cv2.imshow('image',canvas)
def updateColor(x):
global color
r_value = cv2.getTrackbarPos('Channel_Red','image')
g_value = cv2.getTrackbarPos('Channel_Green','image')
b_value = cv2.getTrackbarPos('Channel_Blue','image')
color = (b_value,g_value,r_value)
print('Update Value, value={}'.format(color))
updateImage()
cv2.namedWindow('image')
cv2.createTrackbar('Channel_Red','image',0,255,updateColor)
cv2.createTrackbar('Channel_Green','image',0,255,updateColor)
cv2.createTrackbar('Channel_Blue','image',0,255,updateColor)
cv2.setTrackbarPos('Channel_Red','image',125)
cv2.setTrackbarPos('Channel_Green','image',125)
cv2.setTrackbarPos('Channel_Blue','image',125)
print("进入RGB滑块实验, 键盘摁q退出程序")
updateImage()
while cv2.waitKey(0) != ord('q'):
continue
cv2.destroyAllWindows()
程序运行后,运行结果如下图所示,拖动滑动条即可进行调色:
4.2 C++实现
其C++实现如下所示,其中像素点的操作没有Python中Numpy的操作那么便捷,采用的是容器访问像素点。
#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#define WINDOW_NAME "image"
using namespace std;
using namespace cv;
int r_value = 125;
int g_value = 125;
int b_value = 125;
Mat canvas(300,300,CV_8UC3,Scalar(125,125,125));
void updateColor(int, void *)
{
for(int row=0; row < canvas.rows; row++)
{
for(int col = 0; col < canvas.cols; col++)
{
canvas.at<Vec3b>(row,col)[0] = (unsigned char)b_value;
canvas.at<Vec3b>(row,col)[1] = (unsigned char)g_value;
canvas.at<Vec3b>(row,col)[2] = (unsigned char)r_value;
}
}
imshow(WINDOW_NAME,canvas);
}
int main()
{
namedWindow(WINDOW_NAME, WINDOW_NORMAL|WINDOW_FREERATIO);
imshow(WINDOW_NAME,canvas);
createTrackbar("Channel_Red", WINDOW_NAME, &r_value,255,updateColor);
createTrackbar("Channel_Green", WINDOW_NAME, &g_value,255,updateColor);
createTrackbar("Channel_Blue", WINDOW_NAME, &b_value,255,updateColor);
waitKey();
return 0;
}
代码执行效果如下图所示:
5 用滑条模拟按键
在OpenCV中,按键组件是不存在的,一种比较主要的实现按键的方法是采用滑条组件来实现按键。
首先演示其实现的Python代码
import cv2
cv2.namedWindow('image_win')
def do_something():
print('Button Pressed!!')
print('Do Something')
def update(x):
if x == 1:
do_something()
cv2.waitKey(500)
cv2.setTrackbarPos('button', 'image_win', 0)
cv2.createTrackbar('button','image_win',0,1,update)
cv2.waitKey(0)
cv2.destroyAllWindows()
其相应的实现效果如下图所示:
相应的,其C++代码如下所示:
#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#define WINDOW_NAME "image_win"
int position = 0;
using namespace std;
using namespace cv;
void do_something()
{
cout<<"Button Pressed"<<endl;
cout<<"Do Something"<<endl;
}
void update(int, void *)
{
if(position == 1)
{
do_something();
waitKey(500);
setTrackbarPos("button",WINDOW_NAME,0);
}
}
int main()
{
namedWindow(WINDOW_NAME, WINDOW_NORMAL|WINDOW_FREERATIO);
createTrackbar("button", WINDOW_NAME, &position, 1,update);
waitKey();
return 0;
}
其实现效果同Python。