How to Build GUI Barcode Reader with PySide2 on Raspberry Pi

If you want to build a cross-platform GUI app with Python and Qt, you can either use PyQt or PySide. Both of them are Qt bindings for Python. The main difference is the license: PyQt5 is released under GPL or commercial, whereas PySide2 is released under LGPL. Since PySide2 is recommended officially, I will use PySid2 and Dynamsoft Python Barcode SDK to create a GUI barcode reader app on Raspberry Pi.


  • OpenCV Python
  • Dynamsoft Python Barcode SDK
  • PySide2

GUI Barcode Reader for Raspberry Pi OS

Let’s get started with the UI widgets:

  • A button for loading image files:
  • A button for opening the live camera stream:
  • A button for stopping the camera stream:
  • A label for displaying the camera frames and a text area for showing the barcode decoding results:

We use OpenCV to read image files and capture webcam frames:

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 =

The next step is significant. We need to consider how to integrate the barcode decoding API.

The simplest way we instantly come up with is to call the decoding method once you get a frame:

      if not ret:
self.showMessageBox('Failed to get camera frame!')
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, which will block the UI thread if it takes too much time. So we have to execute the UI code and barcode recognition code respectively in different threads. Due to the performance restriction of Python’s GIL, the Python thread is not viable either. What about QThread? QThread is implemented in the same way as Python thread. To verify the QThread performance, we can make a test with the following code:

class BarcodeManager(QThread):
def __init__(self, license):
super(BarcodeManager, self).__init__()
self.signals = WorkerSignals()
self._reader = BarcodeReader()
settings = self._reader.get_runtime_settings()
settings.max_algorithm_thread_count = 1
self.frameQueue = Queue(1)
def register_callback(self, fn):
def run(self):
while True:
frame = self.frameQueue.get(False, 10)
if type(frame) is str:
results = self._reader.decode_buffer(frame)
except BarcodeReaderError as error:

It turns out there is no performance improvement. So the most feasible way is to do barcode decoding tasks in another Python Process:

def process_barcode_frame(license, frameQueue, resultQueue):
# Create Dynamsoft Barcode Reader
reader = BarcodeReader()
# Apply for a trial license:
settings = reader.get_runtime_settings()
settings.max_algorithm_thread_count = 1
while True:
results = None
frame = frameQueue.get(False, 10)
if type(frame) is str:
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:
resultQueue.put(results, False, 10)
def create_decoding_process(license):
size = 1
frameQueue = Queue(size)
resultQueue = Queue(size)
barcodeScanning = Process(target=process_barcode_frame, args=(license, frameQueue, resultQueue))
return frameQueue, resultQueue, barcodeScanning

We create two queues as the data tunnel between the two processes.

So far, the app is done. One more thing is to apply for a free trial license and save it to the local disk.

Connect a USB webcam to Raspberry Pi, and then run the app:

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


Source Code

Manager of Dynamsoft Open Source Projects | Tech Lover

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store