1

I developed an application which contains a button. On button click, it starts running the webcam to capture frames using OpenCV in an infinite loop. The program releases the webcam instance when the user press 'Q'. When I close the application the application gets closed successfully but the webcam instance are not getting released and keeps on running. How do I make sure to release the webcam resources when I close the application.

Webcam.py:-

import cv2

def hello():

    camera = cv2.VideoCapture(0)
    top, right, bottom, left = 10, 350, 225, 590
    num_frames = 0

    while True:
        _, frame = camera.read()

        clone = frame.copy()
        roi = frame[top:bottom, right:left]

        cv2.rectangle(clone, (left, top), (right, bottom), (0, 255, 0), 2)
        num_frames += 1
        cv2.imshow("Video Feed", clone)

        keypress = cv2.waitKey(1) & 0xFF

        if keypress == ord("q"):
            break

    camera.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    hello()

Application.py:-

from PyQt5 import QtCore, QtGui, QtWidgets
from Webcam import hello
import sys

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):

        self.window = MainWindow
        self.window.setObjectName("self.window")
        self.window.resize(800, 600)

        self.centralwidget = QtWidgets.QWidget(self.window)
        self.centralwidget.setObjectName("centralwidget")

        self.startButton = QtWidgets.QPushButton(self.centralwidget)
        self.startButton.setText("&Start")
        self.startButton.clicked.connect(self.open_cam)

        self.window.setCentralWidget(self.centralwidget)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def open_cam(self):
        hello()

class MyWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, parent=None):

        super(MyWindow, self).__init__(parent)
        self.setupUi(self)

    def closeEvent(self, event):
        result = QtWidgets.QMessageBox.question(self,
                      "Confirm Exit...",
                      "Are you sure you want to exit ?",
                      QtWidgets.QMessageBox.Yes| QtWidgets.QMessageBox.No)
        event.ignore()
        if result == QtWidgets.QMessageBox.Yes:
            event.accept()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())
Rock star
  • 49
  • 1
  • 8
  • Try adding the `from PyQt5 import QtCore` line to the `Webcam.py` module – S. Nick Mar 30 '19 at 16:35
  • Nope it is still unable to release the resources – Rock star Mar 30 '19 at 17:02
  • It worked for me. Then try adding the line `QtCore.QCoreApplication.quit ()` after the line `cv2.destroyAllWindows ()` – S. Nick Mar 30 '19 at 17:13
  • Ok, I understand now. what you were doing is trying to close the application by pressing 'q' which releases the webcam instance first and closes the application. But what I am looking is close the application pressing 'X' which should also release the webcam resources but in this case, the webcam resources are not getting released and the application is getting closed. – Rock star Mar 30 '19 at 17:41

1 Answers1

1

It may be a camera issue. I would try changing how you implemented your camera based on this example https://stackoverflow.com/a/11449901/8150685. I also would recommend changing the camera to a class so you can control how it is setup and how it dies.

Note: I am not on a computer with Qt so this is not tested. I may take some debugging or it may not work.

import cv2

class Camera:
    def __init__(self):

        self.alive = True
        self.vc = None


    def run(self):

        self.vc = cv2.VideoCapture(0)
        if self.vc.isOpened(): # try to get the first frame
            self.rval, self.frame = self.vc.read()
        else:
            self.rval = False

        while self.rval:
            cv2.imshow("preview", self.frame)
            self.rval, self.frame = self.vc.read()
            key = cv2.waitKey(20)
            if key == ord("q"): # exit on q
                break
        self.destroy()

    def destroy(self):
        if self.alive and self.vc:
            cv2.destroyWindow("preview")
            self.vc.release()
            self.alive = False

Now in Qt you can create a Camera object.

from PyQt5 import QtCore, QtGui, QtWidgets
from Webcam import Camera
import sys

class Ui_MainWindow(object):
    def setupUi(self, MainWindow, camera):

        self.camera = camera
        self.window = MainWindow
        self.window.setObjectName("self.window")
        self.window.resize(800, 600)

        self.centralwidget = QtWidgets.QWidget(self.window)
        self.centralwidget.setObjectName("centralwidget")

        self.startButton = QtWidgets.QPushButton(self.centralwidget)
        self.startButton.setText("&Start")
        self.startButton.clicked.connect(self.open_cam)

        self.window.setCentralWidget(self.centralwidget)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def open_cam(self):
        self.camera.run() # Run the camera

class MyWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, camera, parent=None):
        self.camera = camera
        super(MyWindow, self).__init__(parent)
        self.setupUi(self, self.camera) # Pass our camera pointer

    def closeEvent(self, event):
        result = QtWidgets.QMessageBox.question(self,
                      "Confirm Exit...",
                      "Are you sure you want to exit ?",
                      QtWidgets.QMessageBox.Yes| QtWidgets.QMessageBox.No)
        event.ignore()
        if result == QtWidgets.QMessageBox.Yes:
            self.camera.destroy() # Destroy the camera if it is not already
            event.accept()


if __name__ == "__main__":
    cam = Camera()
    app = QtWidgets.QApplication(sys.argv)
    w = MyWindow(cam)
    w.show()
    sys.exit(app.exec_())
Rock star
  • 49
  • 1
  • 8