Hi,
This is beginner’s question on using a variable between different classes. I’m building an application that involves counting objects on video frames from a usb camera. I use OpenCV’s simple blob detector. I used code from here to embed simple blob detector in a PyQT-based GUI-application.
I manage to print the number of counted objects on each video frame using print(len(keypoints)) added in the while loop within the run function (see code below).
However, I do not manage to access the value of ‘keypoints’ outside the VideoThread class (e.g., to read out the value and display it in a QPlainTextEdit box in the GUI when the mouse is clicked).
In the below example, I try to read out the length of keypoints on a mousePressEvent in the Tab class of the GUI.
When using: print(len(keypoints)) in the mousePressEvent function in the Tab class, I get: NameError: name 'keypoints' is not defined
When using print(len(VideoThread.keypoints)), I get: AttributeError: type object 'VideoThread' has no attribute 'keypoints'
When I declare keypoints in the VideoThread class as a list (keypoints = []), I get no errors but len(VideoThread.keypoints) returns 0, because keypoints remains an empty list.
I experimented with declaring keypoins as a global variable within the run function (based on info from here), but I get Global variable 'keypoints' is undefined at the module level (in Pycharm). When I define it at the module level, I find again that it is not updated in the run method (remains 0).
How do I access the keypoints variable from outside the VideoThread class?
The code:
videothread.py for the thread that reads the camera frames:
import cv2
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QThread, QStringListModel
import numpy as np
class VideoThread(QThread):
change_pixmap_signal = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
self._run_flag = True
def run(self):
cap = cv2.VideoCapture(0)
while self._run_flag:
ret, cv_img = cap.read()
if ret:
detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(cv_img)
cv_img = cv2.drawKeypoints(cv_img, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
self.change_pixmap_signal.emit(cv_img)
cap.release()
def stop(self):
self._run_flag = False
self.wait()
view.py for the user interface
from videothread import VideoThread
from threading import Thread
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QWidget, QAction, QTabWidget, QVBoxLayout
class Tab(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
# Instantiate 'tabs' as an object from the QTabWidget() class
self.tabs = QTabWidget()
# All tabs are instantiated as seperate QWidget() objects
self.tab1 = QWidget()
self.tab2 = QWidget()
# Add tab1 and tab2 to QTabWidget 'tabs'
self.tabs.addTab(self.tab1, "Beeldacquisitie")
self.tabs.addTab(self.tab2, "Resultaten")
def mousePressEvent(self, event):
# self.output is a QPlainTextEdit box
self.output.setPlainText(str(len(VideoThread.keypoints)))