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失效核心原因
- 缺少必要的GUI窗口:OpenCV的
waitKey仅对自身HighGUI模块创建的活跃窗口生效,现有代码中没有调用cv2.imshow()创建显示窗口,waitKey根本不会捕获键盘事件,这是最主要的原因。 - waitKey参数使用错误:尝试的两种写法都用了
waitKey(0),参数0代表无限阻塞等待按键,仅适合静态图片展示场景,放在实时视频流循环中会直接卡停帧读取逻辑,完全不适用。 - 可能安装了无GUI版本的OpenCV:Ubuntu环境下如果通过pip安装了
opencv-python-headless版本,该版本剔除了所有HighGUI相关组件,天生不支持窗口渲染和键盘事件捕获。 - 代码逻辑bug:
out.write(frame)写在了遍历人脸的for循环内部,既会导致同一帧被重复写入输出视频,还存在变量名不统一问题——写帧用的变量是out,最后释放资源时调用的是videoWrite.release(),会触发变量不存在报错。
修复waitKey功能的步骤
- 先确认OpenCV版本:执行
pip list | grep opencv,如果存在opencv-python-headless,先卸载后重装普通桌面版:pip uninstall opencv-python-headless -y pip install opencv-python==4.6.0 - 在帧处理逻辑后补上窗口显示代码,确保有活跃GUI窗口供waitKey捕获事件:
cv2.imshow('Face Emotion Recognition', frame) - 修正waitKey判断逻辑,使用
&0xFF做跨平台返回值掩码,参数使用1(代表等待1毫秒,兼顾实时性和事件处理):k = cv2.waitKey(1) & 0xFF if k == 27: # 27是ESC键的ASCII码 break - 把
out.write(frame)移到遍历人脸的for循环外部,确保每帧仅写入一次,同时统一VideoWriter的变量名,避免释放资源时报错。
waitKey替代方案(无GUI场景适用)
如果不需要实时显示画面,只是后台跑视频处理逻辑,可以用pynput库实现全局键盘监听,完全不依赖OpenCV的GUI组件:
- 安装依赖:
pip install pynput - 代码实现示例:
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
相关产品推荐
相关产品推荐

