Multiprocessing using a webcam and pyqtgraph - pickling error, how to solve it?

48 views Asked by At

I am trying to produce a GUI using PyQT6 to interface a camera with a pyqtgraph viewer. I created three classes, one for the QT interface (CharacViewer), one for the camera (cameraClass) and one for the pyqtgraph viewer (imageViewer). I want the camera and viewer to work as processes: once the camera has acquired a frame, it will send it to the pyqtgraph process through a queue. The pyqtgraph process will extract the frame from the queue and display it. I need to do it this way because I want to interact with the pyqtgraph window later during the acquisition. However, I am encountering a pickling issue because the process function can't pickle the camera and pyqtgraph objects. Does anybody have experience with this? Pathos seems to solve a similar issue, but I don't want to create a Pool, rather two distinct Processes.

Here are the different codes I have written so far:

main.py:

import sys
from PyQt6 import uic
from PyQt6.QtWidgets import QApplication
from CharacViewer import CharacViewer
from cameraClass import camera
from imageViewer import imageViewer
import multiprocessing as mp

if __name__ == '__main__':
    app = QApplication([])
    app.setStyle('Fusion')
    queue = mp.Queue()

    camera = camera(queue)
    imageViewer = imageViewer(queue)
    charac_viewer = CharacViewer()
    charac_viewer.move(900,0)
    charac_viewer.resize(650,830)
    charac_viewer.show()
    charac_viewer.setImageViewer(imageViewer)
    charac_viewer.setCamera(camera)
    charac_viewer.initialiseCamera()
    charac_viewer.initialiseViewer()

    print('All set!')
    sys.exit(app.exec())

    print('Killing GUI')

CharacViewer.py:

import cv2
from PyQt6 import QtWidgets, uic, QtCore
from PyQt6.QtWidgets import QApplication, QFileDialog
import threading

import queue
from multiprocessing import Process, Queue
from multiprocessing.shared_memory import SharedMemory
import numpy as np
import pyqtgraph as pg
from PyQt6.QtCore import QTimer, QSize

class CharacViewer(QtWidgets.QMainWindow):
    def __init__(self):
        super(CharacViewer, self).__init__()
        self.ui = uic.loadUi("gui_interface.ui", self)
        self.ui.pushButton_RunCamera.clicked.connect(self.startImagingProcess)
        self.width = 720
        self.height = 1280
        self.counter = 0

    def setImageViewer(self, imv):
        self.imv = imv

    def setCamera(self, cam):
        self.cam = cam

    def startImagingProcess(self):
        print('Start Imaging...')
        self.cam.start()
        self.imv.start()

    def initialiseCamera(self):
        self.cam.initialiseCamera(self.width, self.height)

    def initialiseViewer(self):
        self.imv.initialiseViewer()

cameraClass.py:

import cv2
import multiprocessing
import matplotlib.pyplot as plt
import numpy as np
import queue


class camera(multiprocessing.Process):
    # def __init__(self, sync_queue, param, conn):
    def __init__(self, queue):
        multiprocessing.Process.__init__(self)
        self.queue = queue
        print('Camera class initialized!')

    def initialiseCamera(self, width, height):
        self.width = width
        self.height = height
        self.vid = cv2.VideoCapture(0)
        self.vid.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
        self.vid.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
        print('Camera initialized!')
    def run(self):
        while 1:
            if self.queue.empty():
                ret, frame = self.vid.read()
                arr = np.array(frame)
                print(np.shape(arr))
                width = np.shape(arr)[0]
                height = np.shape(arr)[1]
                colors = np.shape(arr)[2]
                arr = arr.flatten()
                arr = np.append(arr, np.array([width, height, colors]))
                self.queue.put(arr)

imageViewer.py:

import cv2
import multiprocessing
import matplotlib.pyplot as plt
import pyqtgraph as pg
import numpy as np
import queue


class imageViewer(multiprocessing.Process):

    def __init__(self, queue):
        multiprocessing.Process.__init__(self)
        self.queue = queue
        self.counter = 0
        print('Image Viewer Class initialized!')

    def initialiseViewer(self):
        self.imv = pg.ImageView()
        self.imv.show()
        self.imv.resize(800, 600)
        print('Image Viewer initialized!')

    def run(self):
        while 1:
            if not self.queue.empty():
                data = self.queue.get()
                dataToPrint = data[:-3]
                self.width = data[-3]
                self.height = data[-2]
                self.colors = data[-1]
                dataToPrint = np.reshape(dataToPrint, (self.width, self.height, self.colors))
                self.imv.setImage(dataToPrint)

The error I get is the following:

TypeError: cannot pickle 'cv2.VideoCapture' object

0

There are 0 answers