暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

python开发之HighGUI上位机开发(二):键盘事件监听、窗口销毁、窗口显示图像、滑动条组件、按键组件以及鼠标事件监听

做一个柔情的程序猿 2020-08-28
556

点击上方“蓝字”关注我!
这篇博文主要分析HighGUI上位机开发过程中的一些项目实战开发的重点函数分析。主要包括:键盘事件监听、窗口销毁、窗口显示图像、滑动条组件、按键组件以及鼠标事件监听。。

字数可能有点多,请慢慢学习查看,相信你肯定会有所收获

键盘事件监听

HighGUI里面的有
wait
ey键盘事件监听函数

,文章最后提供了一个waitKey
Demo

键盘监听事件如下:

1.

waitKey函数API讲解

讲一下opencv中一个键盘事件监听函数waitKey

cv2.waitKey(delay_ms)

这个函数其实有两个功能

  1. 等待一个按键事件的发生

  2. 延时delay_ms个毫秒

它的逻辑是这样的, 如果过了n个ms仍然也没等到有按键事件发生, 就继续执行下面的函数, 所以变相等于延时(delay)

注意 , 这个函数只有在当前至少有一个窗口是激活状态下, 才会生效

换句话说:

  • 如果你在这期间, 点开了另外一个无关窗口, 无论你怎么按键都不会响应。

  •  如果等待设置为0, 就意味着永久等待, 直到有任意一个按键按下。

cv2.waitKey(0)
  •  waitKey 返回的数值 是按下的按键字符,对应的ASCII编码

key_num = cv2.waitKey(0)
  •  如果是等待有限时间例如,如果等待1000ms 也就是1s之后, 没有按键按下, 那么返回的这个值就是-1

key_num = cv2.waitKey(1000)

我们在进行按键字符匹配的时候, 一般不会直接比对字符数值。

你可以使用python的强制类型转换, 将数值转换为字符串chr(value)

例如:我们判断, 按键是否是k键的时候, 判断可以这么写:

key_num = cv2.waitKey(0)if chr(key_num) == 'k':  print("k pressed...")

或者,你可以这么写

我们利用函数ord(char)
, 可以将字符,转换为对应ASCII编码的数值:

key_num = cv2.waitKey(0)if key_num == ord('k'):  print("k pressed...")

2.

demo例子:waitkey_demo.py

import cv2# 创建一个窗口cv2.namedWindow('image')while True:    # 等待按键事件发生    key_code = cv2.waitKey(1000)    if key_code != -1:        print('key {} pressed!!! value={}'.format(chr(key_code), key_code))        if chr(key_code) == 'q':            # 退出程序            print('Quit')            break    else:        # 没有按键按下        print('no key pressed , wait 1s')cv2.destroyWindow('image')

窗口销毁

1.

销毁窗口API讲解

销毁所有窗口:

cv2.destroyAllWindows()

销毁单个窗口, 传入要销毁的窗口名称:

cv2.destroyWindow(window_name)

2.

关闭单个窗口的样例

等待任意按键按下,然后关闭特定的窗口

import cv2# 创建一个窗口cv2.namedWindow('image')# 等待键盘按键按下cv2.waitKey(0)# 销毁窗口cv2.destroyWindow('image')

思考题:如果我不加cv2.destroyWindow
会怎么样, 如果意外中断程序,窗口会怎么样?

3.

关闭所有窗口的样例

import cv2# 创建一个窗口cv2.namedWindow('image1')cv2.namedWindow('image2')cv2.namedWindow('image3')# 等待键盘按键按下cv2.waitKey(0)# 销毁所有窗口cv2.destroyAllWindows()


会产生三个image窗口,按下任意键后,三个窗口同时销毁。。。

综合实验-窗口显示图像

讲解了如何使用HighGUI显示单张图片,以及在多个窗口上显示图片

1.

综合实验1-单个窗口展示图像

这里我们设计一个综合实验, 组合之前所学到的知识。

import numpy as npimport cv2# 导入一张图像 模式为彩色图片img = cv2.imread('lena1.jpg', cv2.IMREAD_COLOR)# 展示图像cv2.imshow('image',img)# 等待按键摁下 最多5s钟# 如果超时key_pressed 就会等于-1key_pressed = cv2.waitKey(5000)print("有按键摁下或者已超时")# 使用chr()print("Key Pressed : {}  == {}".format(key_pressed, chr(key_pressed)))# 关闭所有窗口cv2.destroyAllWindows()# 或者是这样, 销毁创建的单个窗口# cv2.destroyWindow('image')

当有按键按下时,会有准确的按键响应:

超过5s没按下按键就会报如下错误:

2.

综合实验2-同时展示多个窗口

我们读入lena的图片, 将其分别转换为IMREAD_COLOR
 与 IMREAD_UNCHANGED

这里稍稍讲解一下IMREAD_UNCHANGED
 :
我们普通的图片BGR格式, 每个像素点的取值是从0-255,
8bit的位去存储像素点的值. 而市面上大多数SLR 相机, 可以支持更高的颜色分辨率(颜色深度 , depth) ,
可以使用16-bit来存储单个通道像素点的值(PNG图片或者TIFF图片)

同时将三者通过窗口展示:

import numpy as npimport cv2# 导入一张图像 模式为彩色图片 cv2.IMREAD_COLOR = 1img_color = cv2.imread('lena1.jpg', cv2.IMREAD_COLOR)# 导入一张图片 模式为灰度图 cv2.IMREAD_GRAYSCALE = 0img_gray = cv2.imread('lena1.jpg', cv2.IMREAD_GRAYSCALE)# 导入一张图片  cv2.IMREAD_UNCHANGED = -1 包括 alpha透明度通道img_alpha = cv2.imread('lena1.jpg', cv2.IMREAD_UNCHANGED)# 创建一个名字叫做 image_color 的窗口 窗口可拉伸cv2.namedWindow('image_color', cv2.WINDOW_NORMAL)# 在名字叫做 image_color 的窗口下展示图像cv2.imshow('image_color',img_color)cv2.namedWindow('image_grayscale', cv2.WINDOW_NORMAL)cv2.imshow('image_grayscale', img_gray)cv2.namedWindow('image_alpha', cv2.WINDOW_NORMAL)cv2.imshow('image_alpha', img_alpha)# 检测按下的按钮print("请按 按键 e (exit)键关闭窗口")while True:    key_pressed = cv2.waitKey(100)    if key_pressed >= 0:        # 打印一下按键记录        print("Key Pressed : {}  == {}".format(key_pressed, chr(key_pressed)))    # 匹配为e后 跳出 while循环    if key_pressed == ord('e'):        break# 关闭所有打开的窗口cv2.destroyAllWindows()

展示效果:

滑动条组件

主要讲解trackar的api
,包括创建trackar
trackbar回调函数的使用
, 获取多个trackar的取值

1.

创建滑动条

首先我们需要创建一个Trackbar
 , 调用createTrackbar
 这个函数

cv2.createTrackbar(trackbar_name,window_name,min_value,max_value,callback_func)

依次传入的函数

  • trackbar_name
     滑条的名称,获取这个滑条的数值也是通过名称

  • window_name
     滑条所在窗口 (window) 的名称

  • min_value
     滑条最小值

  • max_value
     滑条最大值

  • callback_func
     回调函数,这个参数其实类似C语言中的函数指针,我传入的是函数名称,每次滑条被拖动的时候,都会执行这个函数.

例如:

# 这个nothing的意思就是啥也不做。def nothing(x):    passcv2.createTrackbar('gray_value','image',0,255,nothing)

这里的nothing(x)
 , 被传入的x 实际上是滑条的当前取值

你也可以改成这样, 看一下x 的值。

# 这个nothing的意思就是啥也不做。def nothing(x):    print(x)cv2.createTrackbar('gray_value','image',0,255,nothing)

x 是我命名的值, 你可以命名为任意名称。

Trackbar的使用实例可以见通过HighGUI的Trackbar制作可变色背景

2.

设置滑动条的位置

初始化滑动条的位置需要用到setTrackbarPos
这个函数。

cv2.setTrackbarPos('trackbar_name','window_name', value)

依次传入Trackbar
的名字,Trackbar
所在的窗口的名字, 还有Trackbar
的初始值。

使用样例

cv2.setTrackbarPos('gray_value','image'10)

3.

获取滑动条的位置

除了在回调函数中获取Trackbar
的取值, 还可以通过getTrackbarPos
 函数获取Trackbar的取值。

依次传入Trackbar的名字,Trackbar所在的窗口的名字, 返回当前Trackbar的取值。

value = cv2.getTrackbarPos('trackbar_name','window_name')

使用样例

gvalue = cv2.getTrackbarPos('gray_value','image')

4.

实例1-单个Trackbar

单个Trackbar的使用样例:

import cv2# 创建窗口cv2.namedWindow('image_win')value = Nonedef update(x):    # 回调函数 更新value的值    global value    value = x    print('Update Value, value ={}'.format(value))# 创建一个滑动条对象 数值名字叫做 value_name# 滑动条创建在 image_win 窗口之下# 取值范围为 0-255, 回调函数为updatecv2.createTrackbar('value_name','image_win',0,255,update)# 等待按键按下cv2.waitKey(0)# 销毁窗口cv2.destroyAllWindows()

展示效果:

5.

实例2-设定trackbar的默认取值

设定Trackbar上的默认值为125

import cv2# 创建窗口cv2.namedWindow('image_win')value = Nonedef update(x):    # 回调函数 更新value的值    global value    value = x    print('Update Value, value ={}'.format(value))# 创建一个滑动条对象 数值名字叫做 value_name# 滑动条创建在 image_win 窗口之下# 取值范围为 0-255, 回调函数为updatecv2.createTrackbar('value_name','image_win',0,255,update)cv2.setTrackbarPos('value_name','image_win',125)# 等待按键按下cv2.waitKey(0)# 销毁窗口cv2.destroyAllWindows()

展示效果:

6.

实例3-获取多个Trackbar的Pos

三个trackar,每次有任意一个变更的时候都同步所有的值。

import cv2# 创建窗口cv2.namedWindow('image_win')value = (0, 0, 0)def update(x):    # 回调函数 更新value的值    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))# 创建一个滑动条对象 数值名字叫做 R  G  B# 滑动条创建在 image_win 窗口之下# 取值范围为 0-255, 回调函数为updatecv2.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()

展示效果:

按键组件

主要理解如何使用HighGUI实现按键功能。

1.

按键组件的潜规则

OpenCV里面的按键组件其实不存在的, 有两种方式可以实现按键效果

  • 第一种就是键盘事件监听(waitKey), 这一种可以算是实体按键.

  • 另外一种是改造滑动条组件(Trackbar)变成按键.

Trackbar有两个取值0(逻辑假,按键未按下)跟1(逻辑真,按键按下).

2.

演示代码

import cv2import time# 创建窗口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()

3.

展示效果

鼠标事件监听

主要理解如何使用HighGUI进行鼠标事件监听,介绍了都有哪些鼠标事件及其用法。

1.

鼠标事件分类

大家想一想鼠标都可以有哪些事件?

其实我们可以用脚本的方式,查看cv2
 所有以EVENT
开头的预定义变量的名称列表

'''查看cv2都支持哪些事件'''import cv2events=[i for i in dir(cv2) if 'EVENT'in i]for event in events:    print(event)

运行结果:

EVENT_FLAG_ALTKEYEVENT_FLAG_CTRLKEYEVENT_FLAG_LBUTTONEVENT_FLAG_MBUTTONEVENT_FLAG_RBUTTONEVENT_FLAG_SHIFTKEYEVENT_LBUTTONDBLCLKEVENT_LBUTTONDOWNEVENT_LBUTTONUPEVENT_MBUTTONDBLCLKEVENT_MBUTTONDOWNEVENT_MBUTTONUPEVENT_MOUSEHWHEELEVENT_MOUSEMOVEEVENT_MOUSEWHEELEVENT_RBUTTONDBLCLKEVENT_RBUTTONDOWNEVENT_RBUTTONUP

快去试一试吧。

1.

鼠标事件列表(event list)

大家想一想鼠标都可以有哪些事件?

  • EVENT_MOUSEMOVE
     鼠标移动 Mouse MoveEVENT_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

2.

鼠标事件的回调参数

鼠标事件举例:

def onMouse(event,x,y,flags,param):     # 判断事件是否为 Left Button Double Clicck    if event == cv2.EVENT_LBUTTONDBLCLK:          # 判断事件类型 执行相关操作        do_something()
  • event
     鼠标事件类型, 如上文所述EVENT_MOUSEMOVE等。

  • x
     鼠标当前在窗口Windows下的x坐标

  • y
     鼠标在当前窗口Windows下的y坐标

  • flags
     鼠标事件发生过程值中的一些其他事件标志/状态

  • EVENT_FLAG_LBUTTON
     左键正在按下

  • EVENT_FLAG_RBUTTON
     右键正在被按下

  • EVENT_FLAG_MBUTTON
     中键正在被按下

  • EVENT_FLAG_CTRLKEY
     CTRL键正在被按下

  • EVENT_FLAG_SHIFTKEY
     SHIFT键正在被按下

  • EVENT_FLAG_ALTKEY
     ALT键正在被按下

  • param
     用户自定义的参数

例如, 我们判断鼠标左键是否被按下, 如果按下的话就绘制一个圆圈

def draw_circle(event,x,y,flags,param):     # 判断事件是否为 Left Button Double Clicck    if event == cv2.EVENT_LBUTTONDBLCLK:          cv2.circle(img,(x,y),20,(255,0,0),-1)  

更复杂一些的判断方法, 是结合flags

我们起始可以在很多函数的参数看到flags 这类语句。

例如我们想判断当前左键跟ALT键是不是处于同时被按下的状态, 我们可以这么写:

def onMouse(event,x,y,flags,param):     if flags == ( cv2.EVENT_FLAG_LBUTTON | cv2.EVENT_FLAG_ALTKEY):          # 判断事件类型 执行相关操作        do_something()

你也可以使用+运算, 两者的效果是相同的, 二进制位表示状态。

def onMouse(event,x,y,flags,param):     if flags == ( cv2.EVENT_FLAG_LBUTTON + cv2.EVENT_FLAG_ALTKEY):          # 判断事件类型 执行相关操作        do_something()

我们也可以结合两者。做一个复杂的状态检测。 CTRL + 鼠标左键, 移动鼠标,绘制一个系列圆圈

# CTRL + 鼠标左键, 移动鼠标,绘制一个系列圆圈def onMouse(event,x,y,flags,param):     # 判断事件是否为 Left Button Double Clicck    print(flags)    print(cv2.EVENT_FLAG_LBUTTON | cv2.EVENT_FLAG_CTRLKEY)    if event == cv2.EVENT_MOUSEMOVE and flags == (cv2.EVENT_FLAG_LBUTTON | cv2.EVENT_FLAG_CTRLKEY ):          cv2.circle(img,(x,y),20,(255,0,0),-1)

欢迎大家三连(关注、评论、点赞)一起学习

END

排版:做一个柔情的程序猿

图:做一个柔情的程序猿

文:做一个柔情的程序猿



文章转载自做一个柔情的程序猿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论