Use PySide2 to build a GUI barcode reader on Raspberry Pi

Dynamsoft Barcode Reader SDK is a multi-functional barcode reading control that can embed the barcode reading function into web or desktop applications with just a few lines of code. This can save months of development time and cost. It can support a variety of image file formats and DIB formats obtained from cameras or scanners. Using Dynamsoft Barcode Reader SDK, you can create powerful and practical barcode scanner software to meet your business needs.

Click to download the latest version of Dynamsoft Barcode Reader

If you want to use Python and Qt to build cross-platform GUI applications, you can use PyQt or PySide. They are all Python Qt bindings. The main difference lies in the license: whether PyQt5 is released under the GPL or the commercial PySide2, and under the LGPL. Since PySide2 is officially recommended, I will use PySid2 and Dynamsoft Python barcode SDK to create a GUI barcode reader application on the Raspberry Pi.

Claim

OpenCV Python

python3 -m pip install opencv-python

Dynamsoft Python Barcode SDK

python3 -m pip install dbr

PySide2

sudo apt-get install python3-pyside2.qt3dcore python3-pyside2.qt3dinput python3-pyside2.qt3dlogic python3-pyside2.qt3drender python3-pyside2.qtcharts python3-pyside2.qtconcurrent python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qthelp python3-pyside2.qtlocation python3-pyside2.qtmultimedia python3-pyside2.qtmultimediawidgets python3-pyside2.qtnetwork python3-pyside2.qtopengl python3-pyside2.qtpositioning python3-pyside2.qtprintsupport python3-pyside2.qtqml python3-pyside2.qtquick python3-pyside2.qtquickwidgets python3-pyside2.qtscript python3-pyside2.qtscripttools python3-pyside2.qtsensors python3-pyside2.qtsql python3-pyside2.qtsvg python3-pyside2.qttest python3-pyside2.qttexttospeech python3-pyside2.qtuitools python3-pyside2.qtwebchannel python3-pyside2.qtwebsockets python3-pyside2.qtwidgets python3-pyside2.qtx11extras python3-pyside2.qtxml python3-pyside2.qtxmlpatterns python3-pyside2uic

GUI barcode reader for Raspberry Pi OS

Let's start using UI widgets:

  • Button for loading image files:
self.btn = QPushButton("Load an image")
self.btn.clicked.connect(self.pickFile)

def pickFile(self):
    filename = QFileDialog.getOpenFileName(self, 'Open file',
                                            self._path, "Barcode images (*)")
    if filename is None or filename[0] == '':
        self.showMessageBox("No file selected")
        return
  • Button to open the live camera stream:
btnCamera = QPushButton("Open camera")
btnCamera.clicked.connect(self.openCamera)

self.timer = QTimer()
self.timer.timeout.connect(self.nextFrameUpdate)

def openCamera(self):

    if not self._cap.isOpened(): 
        self.showMessageBox("Failed to open camera.")
        return

    self.timer.start(1000./24)
  • Button to stop the camera stream:
btnCamera = QPushButton("Stop camera")
btnCamera.clicked.connect(self.stopCamera)

def stopCamera(self):
    self.timer.stop()

The label used to display the camera frame and the text area used to display the barcode decoding result:

self.label = QLabel()
self.label.setFixedSize(self.WINDOW_WIDTH - 30, self.WINDOW_HEIGHT - 160)

self.results = QTextEdit()

def showResults(self, frame, results):
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
    pixmap = QPixmap.fromImage(image)
    pixmap = self.resizeImage(pixmap)
    self.label.setPixmap(pixmap)
    self.results.setText(results)

We use OpenCV to read the image file and capture the webcam frame:

frame = cv2.imread(filename)

self._cap = cv2.VideoCapture(0)
self._cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
self._cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
ret, frame = self._cap.read()

The next step is important. We need to consider how to integrate barcode decoding API.
The simplest method that we immediately thought of was to call the decoding method once the frame was obtained:

def nextFrameSlot(self):
      ret, frame = self._cap.read()

      if not ret:
          self.showMessageBox('Failed to get camera frame!')
          return

      frame, results = self._manager.decode_frame(frame)
      self.showResults(frame, results)

However, we cannot do this on Raspberry Pi! Barcode scanning is a CPU-intensive task. If it takes too much time, it will block the UI thread. Therefore, we must execute the UI code and barcode recognition code separately in different threads. Due to the performance limitations of the Python GIL, Python threads are also not feasible. What about QThread? QThread is implemented in the same way as Python threads. In order to verify the performance of QThread, we can use the following code to test:

class WorkerSignals(QObject):
    result = Signal(object)

class BarcodeManager(QThread):
    def __init__(self, license):
        super(BarcodeManager, self).__init__()
        self.signals = WorkerSignals()

        self._reader = BarcodeReader()
        self._reader.init_license(license)
        settings = self._reader.get_runtime_settings()
        settings.max_algorithm_thread_count = 1
        self._reader.update_runtime_settings(settings)
        self.frameQueue = Queue(1)

    def register_callback(self, fn):
        self.signals.result.connect(fn)

    def run(self):
        while True:
            try:
                frame = self.frameQueue.get(False, 10)

                if type(frame) is str:
                    break
            except:
                time.sleep(0.01)
                continue

            try:
                results = self._reader.decode_buffer(frame)
                self.signals.result.emit(results)

            except BarcodeReaderError as error:
                print(error)

It turns out that there is no improvement in performance. Therefore, the most feasible method is to perform the barcode decoding task Python Process in another method:

from multiprocessing import Process, Queue
import time
import numpy as np


def process_barcode_frame(license, frameQueue, resultQueue):
    # Create Dynamsoft Barcode Reader
    reader = BarcodeReader()
    # Apply for a trial license: https://www.dynamsoft.com/customer/license/trialLicense
    reader.init_license(license)
    settings = reader.get_runtime_settings()
    settings.max_algorithm_thread_count = 1
    reader.update_runtime_settings(settings)

    while True:
        results = None

        try:
            frame = frameQueue.get(False, 10)
            if type(frame) is str:
                break
        except:
            time.sleep(0.01)
            continue

        try:
            frameHeight, frameWidth, channel = frame.shape[:3]
            results = reader.decode_buffer_manually(np.array(frame).tobytes(), frameWidth, frameHeight, frame.strides[0], EnumImagePixelFormat.IPF_RGB_888)
        except BarcodeReaderError as error:
            print(error)

        try:
            resultQueue.put(results, False, 10)
        except:
            pass

def create_decoding_process(license):
        size = 1
        frameQueue = Queue(size)
        resultQueue = Queue(size)
        barcodeScanning = Process(target=process_barcode_frame, args=(license, frameQueue, resultQueue))
        barcodeScanning.start()
        return frameQueue, resultQueue, barcodeScanning

We create two queues as a data tunnel between the two processes.
So far, the application is complete. Another thing is to apply for a free trial license and save it to a local disk.

Connect the USB webcam to the Raspberry Pi, and then run the application:
Insert picture description here

The GUI barcode reader application is cross-platform. It can also work on Windows, Linux and macOS.

Guess you like

Origin blog.csdn.net/RoffeyYang/article/details/114136760