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

Ubuntu环境OpenCV4.6中cv2.waitKey()按键失效 寻求替代方案

开发环境
I'm using 
    OS : Ubuntu
    Python : 3.8*
    Opencv version: 4.6.0
开发目标

基于OpenCV实现人脸情绪识别功能,同时支持处理后的视频流保存。

现有实现代码
while True:
    ret, frame = cap.read()
    frame = cv2.resize(frame, (720, 480))

    if not ret:
        break

    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    rects = detector(grayFrame, 0)
    for rect in rects:
        shape = predictor(grayFrame, rect)
        points = shapePoints(shape)
        (x, y, w, h) = rectPoints(rect)
        grayFace = grayFrame[y:y + h, x:x + w]
        try:
            grayFace = cv2.resize(grayFace, (emotionTargetSize))
        except:
            continue

        grayFace = grayFace.astype('float32')
        grayFace = grayFace / 255.0
        grayFace = (grayFace - 0.5) * 2.0
        grayFace = np.expand_dims(grayFace, 0)
        grayFace = np.expand_dims(grayFace, -1)
        emotion_prediction = emotionClassifier.predict(grayFace)
        emotion_probability = np.max(emotion_prediction)
        if (emotion_probability > 0.36):
            emotion_label_arg = np.argmax(emotion_prediction)
            color = emotions[emotion_label_arg]['color']
            cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
            cv2.line(frame, (x, y + h), (x + 20, y + h + 20),
                     color,
                     thickness=2)
            cv2.rectangle(frame, (x + 20, y + h + 20), (x + 110, y + h + 40),
                          color, -1)
            cv2.putText(frame, emotions[emotion_label_arg]['emotion'],
                        (x + 25, y + h + 36), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                        (255, 255, 255), 1, cv2.LINE_AA)
        else:
            color = (255, 255, 255)
            cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)

    
        
        out.write(frame)
    #Wait for user input - q, then you will stop the loop
    k = cv2.waitKey(1)
    if k == 27:
        break

cap.release()
if args["isVideoWriter"] == True:
    videoWrite.release()
cv2.destroyAllWindows()
问题描述

cv2.waitKey()功能异常,按下ESC键时程序无法正常退出循环,尝试网上常见写法均无效,目前仅能通过Ctrl+C键盘中断终止程序。已尝试的无效写法如下:

# Method1: Not working :(
c = cv2.waitKey(0) % 256
if c == ord('a'):
    break

# Method 2: Not working :(
if cv2.waitKey(0) & 0xFF == ord('q'):
    break
问题排查与解决

waitKey失效核心原因

  1. 缺少必要的GUI窗口:OpenCV的waitKey仅对自身HighGUI模块创建的活跃窗口生效,现有代码中没有调用cv2.imshow()创建显示窗口,waitKey根本不会捕获键盘事件,这是最主要的原因。
  2. waitKey参数使用错误:尝试的两种写法都用了waitKey(0),参数0代表无限阻塞等待按键,仅适合静态图片展示场景,放在实时视频流循环中会直接卡停帧读取逻辑,完全不适用。
  3. 可能安装了无GUI版本的OpenCV:Ubuntu环境下如果通过pip安装了opencv-python-headless版本,该版本剔除了所有HighGUI相关组件,天生不支持窗口渲染和键盘事件捕获。
  4. 代码逻辑bug:out.write(frame)写在了遍历人脸的for循环内部,既会导致同一帧被重复写入输出视频,还存在变量名不统一问题——写帧用的变量是out,最后释放资源时调用的是videoWrite.release(),会触发变量不存在报错。

修复waitKey功能的步骤

  1. 先确认OpenCV版本:执行pip list | grep opencv,如果存在opencv-python-headless,先卸载后重装普通桌面版:
    pip uninstall opencv-python-headless -y
    pip install opencv-python==4.6.0
    
  2. 在帧处理逻辑后补上窗口显示代码,确保有活跃GUI窗口供waitKey捕获事件:
    cv2.imshow('Face Emotion Recognition', frame)
    
  3. 修正waitKey判断逻辑,使用&0xFF做跨平台返回值掩码,参数使用1(代表等待1毫秒,兼顾实时性和事件处理):
    k = cv2.waitKey(1) & 0xFF
    if k == 27: # 27是ESC键的ASCII码
        break
    
  4. 把out.write(frame)移到遍历人脸的for循环外部,确保每帧仅写入一次,同时统一VideoWriter的变量名,避免释放资源时报错。

waitKey替代方案(无GUI场景适用)

如果不需要实时显示画面,只是后台跑视频处理逻辑,可以用pynput库实现全局键盘监听,完全不依赖OpenCV的GUI组件:

  1. 安装依赖:
    pip install pynput
    
  2. 代码实现示例:
    from pynput import keyboard
    import cv2
    import numpy as np
    
    # 初始化退出标志位
    exit_flag = False
    
    # 键盘按键回调
    def on_press(key):
        global exit_flag
        if key == keyboard.Key.esc:
            exit_flag = True
            return False # 停止监听
    
    # 启动键盘监听线程
    listener = keyboard.Listener(on_press=on_press)
    listener.start()
    
    # 原有初始化逻辑(cap、detector、predictor、emotionClassifier、out等)
    # ...
    
    # 替换原有while True的循环条件
    while not exit_flag:
        ret, frame = cap.read()
        if not ret:
            break
        frame = cv2.resize(frame, (720, 480))
        grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        rects = detector(grayFrame, 0)
        for rect in rects:
            # 原有情绪识别、画框标注逻辑保持不变
            shape = predictor(grayFrame, rect)
            points = shapePoints(shape)
            (x, y, w, h) = rectPoints(rect)
            grayFace = grayFrame[y:y + h, x:x + w]
            try:
                grayFace = cv2.resize(grayFace, (emotionTargetSize))
            except:
                continue
            grayFace = grayFace.astype('float32')
            grayFace = grayFace / 255.0
            grayFace = (grayFace - 0.5) * 2.0
            grayFace = np.expand_dims(grayFace, 0)
            grayFace = np.expand_dims(grayFace, -1)
            emotion_prediction = emotionClassifier.predict(grayFace)
            emotion_probability = np.max(emotion_prediction)
            if (emotion_probability > 0.36):
                emotion_label_arg = np.argmax(emotion_prediction)
                color = emotions[emotion_label_arg]['color']
                cv2.rectangle(frame, (x, y), (x+w, y+h), color, 2)
                cv2.line(frame, (x, y+h), (x+20, y+h+20), color, thickness=2)
                cv2.rectangle(frame, (x+20, y+h+20), (x+110, y+h+40), color, -1)
                cv2.putText(frame, emotions[emotion_label_arg]['emotion'], (x+25, y+h+36), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
            else:
                color = (255,255,255)
                cv2.rectangle(frame, (x, y), (x+w, y+h), color, 2)
        # 写视频移到for循环外
        out.write(frame)
        # 不需要显示画面可以注释掉imshow
        # cv2.imshow('Face Emotion Recognition', frame)
    
    # 统一释放资源
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    listener.stop()
    

内容的提问来源于stack exchange,提问作者user17993062

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 08:57:21