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

关闭PyQt应用后Webcam实例未释放的问题解决咨询

嘿,这个问题我之前也踩过坑!核心问题出在摄像头的捕获循环阻塞了PyQt的主线程——你点击按钮后,hello()函数里的while True直接把主线程卡死了,PyQt的UI事件(包括窗口关闭)根本没法及时处理。而且摄像头资源是hello()里的局部变量,窗口关闭时那个循环还没跑完,camera.release()根本没机会执行,所以摄像头一直被占着不放。

下面给你一套完整的解决方案:

核心思路

  • 把摄像头操作移到独立的Qt线程中,避免阻塞主线程(PyQt的UI必须在主线程运行,阻塞会导致窗口假死)
  • 封装摄像头控制类,提供启动、停止的接口,方便主动释放资源
  • 在窗口的closeEvent中先停止摄像头,等资源完全释放后再确认退出

修改后的完整代码

1. 封装摄像头线程类(可单独存为Webcam.py)

import cv2
from PyQt5.QtCore import QThread, pyqtSignal

class WebcamThread(QThread):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.camera = None
        self.is_running = False

    def run(self):
        self.is_running = True
        # 初始化摄像头
        self.camera = cv2.VideoCapture(0)
        top, right, bottom, left = 10, 350, 225, 590

        while self.is_running and self.camera.isOpened():
            success, frame = self.camera.read()
            if not success:
                break
            
            # 绘制ROI区域
            clone = frame.copy()
            cv2.rectangle(clone, (left, top), (right, bottom), (0, 255, 0), 2)
            cv2.imshow("Video Feed", clone)

            # 监听Q键退出,同时留足时间让线程响应停止信号
            keypress = cv2.waitKey(1) & 0xFF
            if keypress == ord("q"):
                self.stop()
                break

        # 线程结束时自动清理资源
        self.cleanup()

    def stop(self):
        # 设置标志位,让循环退出
        self.is_running = False

    def cleanup(self):
        # 释放摄像头资源
        if self.camera and self.camera.isOpened():
            self.camera.release()
        # 销毁OpenCV的窗口
        cv2.destroyAllWindows()

2. 修改PyQt应用代码(Application.py)

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        self.window = MainWindow
        self.window.setObjectName("MainWindow")
        self.window.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(self.window)
        self.centralwidget.setObjectName("centralwidget")
        
        # 调整按钮位置,方便显示
        self.startButton = QtWidgets.QPushButton(self.centralwidget)
        self.startButton.setGeometry(QtCore.QRect(350, 250, 100, 30))
        self.startButton.setText("&Start")
        
        self.window.setCentralWidget(self.centralwidget)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

class MyWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setupUi(self)
        self.webcam_thread = None
        # 绑定按钮点击事件
        self.startButton.clicked.connect(self.toggle_camera)

    def toggle_camera(self):
        # 切换摄像头启停状态
        if self.webcam_thread is None or not self.webcam_thread.isRunning():
            self.webcam_thread = WebcamThread(self)
            # 线程结束后重置按钮状态
            self.webcam_thread.finished.connect(lambda: self.startButton.setText("&Start"))
            self.webcam_thread.start()
            self.startButton.setText("&Stop")
        else:
            self.webcam_thread.stop()
            self.startButton.setText("&Start")

    def closeEvent(self, event):
        # 窗口关闭前的确认逻辑
        result = QtWidgets.QMessageBox.question(
            self,
            "Confirm Exit...",
            "Are you sure you want to exit?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
        )

        if result == QtWidgets.QMessageBox.Yes:
            # 先停止摄像头线程,等待资源释放
            if self.webcam_thread and self.webcam_thread.isRunning():
                self.webcam_thread.stop()
                self.webcam_thread.wait()  # 等待线程完全结束
            event.accept()
        else:
            event.ignore()

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

关键改动说明

  • 线程隔离:用QThread把摄像头逻辑从主线程分离,保证UI始终响应流畅,窗口关闭事件能正常触发
  • 可控循环:用is_running标志代替while True,可以主动停止循环,避免无法中断的问题
  • 主动清理:在closeEvent中先停止摄像头线程,等待它执行cleanup()释放资源后再退出应用
  • 用户体验优化:把按钮改成启停切换,不用重复点击,线程结束后自动重置按钮状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:48:21