Python Forum
[PyQt] Exit Clean from PyQt5 and CV2 App
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] Exit Clean from PyQt5 and CV2 App
#1
Hi,

The app works, however if I don't stop the camera stream before closing then (sometimes) I get the error:
FATAL: exception not rethrown

Can you spot why, or even tell me how to find out what it is referring to... I've tried to catch the app close and propagate and close things properly (namely the thread handling CV2)

Many thanks

"""
FATAL: exception not rethrown
Aborted (core dumped)
"""

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QKeyEvent
import PyQt5.QtCore as QtCore

import sys
import signal		#	for exit
import cv2


class w_cam_view(QWidget):
	def __init__(self):
		super(w_cam_view, self).__init__()

		self.layout = QVBoxLayout()

		self.lbl_img = QLabel()
		self.lbl_img.setMaximumSize(200, 200)
		self.layout.addWidget(self.lbl_img)
		
		#	VIEW TOOLBAR
		self.layout2 = QHBoxLayout()
		
		self.txt_addr = QLineEdit(self)
		self.txt_addr.setText("0")
		self.txt_addr.setFixedWidth(120)
		self.layout2.addWidget(self.txt_addr)
		
		self.btn_start = QPushButton("Start")
		self.btn_start.clicked.connect(self.feed_start)
		self.layout2.addWidget(self.btn_start)
		
		self.btn_stop = QPushButton("Stop")
		self.btn_stop.clicked.connect(self.feed_stop)
		self.layout2.addWidget(self.btn_stop)
		
		#	OPENCV THREAD
		self.cam_thread = cam_thread()
		self.cam_thread.update_img.connect(self.update_img)
		
		self.layout.addLayout(self.layout2)
		
		self.setLayout(self.layout)

	def update_img(self, img):
		self.lbl_img.setPixmap(QPixmap.fromImage(img).scaled(self.lbl_img.size(), aspectRatioMode=QtCore.Qt.KeepAspectRatio))

	def feed_stop(self):
		self.cam_thread.on_stop()
	
	def feed_start(self):
		self.cam_thread.cam_path = int(self.txt_addr.text())
		self.cam_thread.on_start()
	
	def on_exit(self):
		print("EXIT widget")
		self.cam_thread.on_exit()

class cam_thread(QThread):
	update_img = pyqtSignal(QImage)
	cam_path = 2		#0
	
	resize_w = 640
	resize_h = 480

	def run(self):
		self.ThreadActive = True
		try:
			#	INIT CV STREAM
			cap = cv2.VideoCapture(self.cam_path)
			cap.setExceptionMode(True)
			
			while self.ThreadActive:
				ret, frame = cap.read()	#	throws exception if no stream!
				if ret:
					img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
					img_f = cv2.flip(img, 1)
					img_qt = QImage(img_f.data, img_f.shape[1], img_f.shape[0], QImage.Format_RGB888)
					img_qt = img_qt.scaled(self.resize_w, self.resize_h, Qt.KeepAspectRatio)
					self.update_img.emit(img_qt)
		except:
			print("Error caught!")
			self.on_stop()
		
	def on_stop(self):
		self.ThreadActive = False
		self.quit()

	def on_start(self):
		self.start()
		
	def on_exit(self):
		print("EXIT worker")
		self.on_stop()

class App(QMainWindow):

	def __init__(self):
		super().__init__()
		self.title = 'Cam'
		self.left = 10
		self.top = 10
		self.width = 1000
		self.height = 400
		self.init_ui()

	def init_ui(self):
		self.setWindowTitle(self.title)
		self.setGeometry(self.left, self.top, self.width, self.height)
		
		#	ADD WIDGETS
		self.w_cam = w_cam_view()
		
		#	LAYOUT
		layout = QVBoxLayout()
		layout.addWidget(self.w_cam)
		
		#	SET CONTENT
		widget = QWidget()
		widget.setLayout(layout)
		self.setCentralWidget(widget)
	
	def on_exit(self):
		print("EXIT window")
		self.w_cam.on_exit()
		
	def closeEvent(self, event):
		print('Window closing...')
		self.on_exit()
		event.accept()

#ex = None

def exit_application(signum, frame):
	print("exit_application")
	#ex.on_exit()
	QApplication.quit()

if __name__ == "__main__":
	
	#	START QT AND APP
	app = QApplication(sys.argv)
	ex = App()
	ex.show()
	
	try:
		signal.signal(signal.SIGINT, exit_application)
		sys.exit(app.exec_())
	except KeyboardInterrupt:
		signal.signal(signal.SIGINT, exit_application)
		sys.exit(app.exec_())
		#sys.exit(0)
	  
	#signal.signal(signal.SIGINT, exit_application)
	#sys.exit(app.exec_())
Reply
#2
Please supply the complete, unedited error traceback. It contains critical debug information.
Reply
#3
@Larz60+ Cheers!

That was basically it... I just tried to do again, but it wouldn't (more in a mo...)
From further up in bash:
Quote:$ python main.py
QSocketNotifier: Can only be used with threads started with QThread
Window closing...
EXIT window
EXIT scan
EXIT widget
EXIT worker
FATAL: exception not rethrown
Aborted (core dumped)

Since... I have added such to the QThread class:
	def on_stop(self):
		print("on_stop()")
		
		if self.cap != None:
			self.cap.release()
			self.cap = None
		
		if self.out != None:
			self.out.release()
			self.out = None
		
		self.ThreadActive = False
		self.quit()
* also initialised cap to None

So... I'm now thinking it was improper closure of cap!?

* Where do I find the core dump please?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Huge code problems (buttons(PyQt5),PyQt5 Threads, Windows etc) ZenWoR 0 4,035 Apr-06-2019, 11:15 PM
Last Post: ZenWoR

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020