You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的返回值,避免窗口刷新阻塞。

  1. 安装依赖:
pip install pynput
  1. 修改后的代码:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 13:46:05