OpenCV中按住按键导致视频采集冻结问题求助
解决OpenCV按住按键时视频采集冻结的问题
问题描述
我开发了一款从工业相机获取视频的程序,使用OpenCV进行视频显示与图像分析。程序中图像上显示有若干可通过键盘移动的圆圈,但按住按键时视频采集会冻结,不过圆圈的移动逻辑仍在运行(松开按键后可看到圆圈已移动)。
简化示例代码如下:
import numpy as np import cv2 WINDOW_NAME = 'program' cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL) cv2.setWindowProperty(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_GUI_EXPANDED) while True: # 简化的图像采集逻辑 frame = (np.random.rand(1080, 1920, 3)*255).astype(np.uint8) cv2.imshow(WINDOW_NAME, frame) pressed_key_code = cv2.waitKey(1) if pressed_key_code == ord('q'): cv2.destroyAllWindows() break # 简化的按键响应动作 elif pressed_key_code == ord('p'): print('moving action')
在该示例中,按住p键时图像采集会停止,但仍能看到打印输出。我尝试过使用不同的按键等待函数:cv2.pollKey()、cv2.waitKeyEx(),也调整过等待时长,还尝试过同时使用多个cv2.waitKey()函数,但问题仍未解决。我期望实现按键操作时不冻结视频采集,请问该如何解决?
相关环境信息:
- OpenCV版本:4.7.0
- 平台:Windows 10.0.17763 AMD64
- HighGUI后端:WIN32UI
问题根源
该问题本质是Windows WIN32UI后端下OpenCV的waitKey函数特性导致:按住按键时,操作系统会持续发送按键重复事件,waitKey会不断返回该按键的编码,窗口刷新事件被大量按键事件挤占,导致视频无法及时更新,但程序逻辑本身仍在运行。
解决方案
方案一:使用pynput库监听按键状态
通过后台线程监听按键的按下/释放事件,维护按键状态,主线程仅读取状态执行动作,不依赖waitKey的返回值,避免窗口刷新阻塞。
- 安装依赖:
pip install pynput
- 修改后的代码:
import numpy as np import cv2 from pynput.keyboard import Key, Listener WINDOW_NAME = 'program' cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL) cv2.setWindowProperty(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_GUI_EXPANDED) # 维护按键状态:键名 -> 是否按下 key_states = {'p': False} def on_press(key): try: if key.char == 'p': key_states['p'] = True except AttributeError: pass def on_release(key): try: if key.char == 'p': key_states['p'] = False elif key == Key.esc or key.char == 'q': # 停止监听线程 return False except AttributeError: if key == Key.esc: return False # 启动按键监听线程 listener = Listener(on_press=on_press, on_release=on_release) listener.start() try: while True: # 替换为工业相机的实际采集逻辑 frame = (np.random.rand(1080, 1920, 3)*255).astype(np.uint8) # 根据按键状态执行移动逻辑 if key_states['p']: print('moving action') # 显示帧 cv2.imshow(WINDOW_NAME, frame) # 处理窗口事件并检测退出 if cv2.waitKey(1) & 0xFF == ord('q'): break finally: # 停止监听并清理窗口 listener.stop() cv2.destroyAllWindows()
方案二:调用Windows API直接获取按键状态
如果不想引入第三方库,可通过ctypes调用Windows系统APIGetAsyncKeyState,直接获取按键的实时状态,无需依赖waitKey的事件返回。
修改后的代码:
import numpy as np import cv2 import ctypes # 加载Windows用户32位库 user32 = ctypes.WinDLL('user32', use_last_error=True) # 虚拟键码:P键为0x50,Q键为0x51 VK_P = 0x50 VK_Q = 0x51 def is_key_pressed(vk_code): # GetAsyncKeyState返回值的高位为1表示按键处于按住状态 return user32.GetAsyncKeyState(vk_code) & 0x8000 != 0 WINDOW_NAME = 'program' cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL) cv2.setWindowProperty(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_GUI_EXPANDED) while True: # 替换为工业相机的实际采集逻辑 frame = (np.random.rand(1080, 1920, 3)*255).astype(np.uint8) # 检测P键是否按住,执行移动逻辑 if is_key_pressed(VK_P): print('moving action') # 显示帧 cv2.imshow(WINDOW_NAME, frame) # 检测退出条件 if cv2.waitKey(1) & 0xFF == ord('q') or is_key_pressed(VK_Q): break cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Dmytro Kolupaiev
相关产品推荐
相关产品推荐

