继上一篇博文:python开发之HighGUI上位机开发(一)
作者:ywsydwsbn
博客主页:https://blog.csdn.net/ywsydwsbn
时间:2020-08-25 20:48
字数:10914
简介:先点赞在看,养成习惯!!!
“ 这篇博文主要分析HighGUI上位机开发过程中的一些项目实战开发的重点函数分析。主要包括:键盘事件监听、窗口销毁、窗口显示图像、滑动条组件、按键组件以及鼠标事件监听。。
字数可能有点多,请慢慢学习查看,相信你肯定会有所收获”
01
—
键盘事件监听
HighGUI里面的有waitKey键盘事件监听函数
,文章最后提供了一个waitKey
的Demo
。
键盘监听事件如下:
waitKey函数API讲解
讲一下opencv中一个键盘事件监听函数waitKey
cv2.waitKey(delay_ms)
这个函数其实有两个功能:
等待一个按键事件的发生
延时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...")
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')
02
—
窗口销毁
讲解如何销毁窗口
销毁窗口API讲解
销毁所有窗口:
cv2.destroyAllWindows()
销毁单个窗口, 传入要销毁的窗口名称:
cv2.destroyWindow(window_name)
关闭单个窗口的样例
等待任意按键按下,然后关闭特定的窗口
import cv2# 创建一个窗口cv2.namedWindow('image')# 等待键盘按键按下cv2.waitKey(0)# 销毁窗口cv2.destroyWindow('image')
思考题:如果我不加
cv2.destroyWindow
会怎么样, 如果意外中断程序,窗口会怎么样?

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

会产生三个image窗口,按下任意键后,三个窗口同时销毁。。。
03
—
综合实验-窗口显示图像
讲解了如何使用HighGUI显示单张图片,以及在多个窗口上显示图片
综合实验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 - 同时展示多个窗口
我们读入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()
展示效果:
04
—
滑动条组件
主要讲解trackar的api
,包括创建trackar
,trackbar回调函数的使用
, 获取多个trackar的取值
。
创建滑动条
首先我们需要创建一个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制作可变色背景
设置滑动条的位置
初始化滑动条的位置需要用到setTrackbarPos
这个函数。
cv2.setTrackbarPos('trackbar_name','window_name', value)
依次传入Trackbar
的名字,Trackbar
所在的窗口的名字, 还有Trackbar
的初始值。
使用样例
cv2.setTrackbarPos('gray_value','image', 10)
获取滑动条的位置
除了在回调函数中获取Trackbar
的取值, 还可以通过getTrackbarPos
函数获取Trackbar的取值。
依次传入Trackbar的名字,Trackbar所在的窗口的名字, 返回当前Trackbar的取值。
value = cv2.getTrackbarPos('trackbar_name','window_name')
使用样例
gvalue = cv2.getTrackbarPos('gray_value','image')
实例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()
展示效果:
实例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()
展示效果:
实例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()
展示效果:
05
—
按键组件
主要理解如何使用HighGUI实现按键功能。
按键组件的潜规则
OpenCV里面的按键组件其实不存在的, 有两种方式可以实现按键效果:
第一种就是键盘事件监听(waitKey), 这一种可以算是实体按键.
另外一种是改造滑动条组件(Trackbar)变成按键.
Trackbar有两个取值0(逻辑假,按键未按下)跟1(逻辑真,按键按下).
演示代码
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()
展示效果

06
—
鼠标事件监听
主要理解如何使用HighGUI进行鼠标事件监听,介绍了都有哪些鼠标事件及其用法。
鼠标事件分类
大家想一想鼠标都可以有哪些事件?
其实我们可以用脚本的方式,查看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
快去试一试吧。
鼠标事件列表(event list)
EVENT_MOUSEMOVE
鼠标移动 Mouse MoveEVENT_LBUTTONDOWN
鼠标左键点击 Left Button DownEVENT_RBUTTONDOWN
鼠标右键点击 Right Button DownEVENT_MBUTTONDOWN
鼠标中键点击 Middle Button DownEVENT_LBUTTONUP
鼠标左键抬起 Left Button UpEVENT_RBUTTONUP
鼠标右键抬起 Right Button UpEVENT_MBUTTONUP
鼠标中键抬起 Middle Button UpEVENT_LBUTTONDBLCLK
鼠标左键双击 Left Button Double ClickEVENT_RBUTTONDBLCLK
鼠标右键双击 Right Button Double ClickEVENT_MBUTTONDBLCLK
鼠标中键双击 Middle Button Double Click
鼠标事件的回调参数
鼠标事件举例:
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)
欢迎大家三连(关注、评论、点赞)一起学习




