How to Use Python and PyQt to Read Barcodes from Webcam

In my previous article, I shared how to use PyQt and Dynamsoft Barcode Reader to create a simple Windows-styled GUI app to read barcodes from image files. Now I am going to add a little bit more code to scan barcodes from the webcam video stream.

Showing Webcam Video Stream using PyQt

Usually, we can use OpenCV for Python to capture webcam frames.

pip install opencv-python

The code is pretty simple:

import cv2
vc = cv2.VideoCapture(0)
while True:
        rval, frame = vc.read()
        cv2.imshow("Camera View", frame)

When using PyQt, we cannot keep drawing the frames in an infinite loop in the main thread. Instead, we need to use a timer. I got the workaround from the StackOverflow Q&A:

def __init__(self):
        # Create a timer.
        self.timer = QTimer()
        self.timer.timeout.connect(self.nextFrameSlot)

def nextFrameSlot(self):
        rval, frame = self.vc.read()
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        image = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
        pixmap = QPixmap.fromImage(image)
        self.label.setPixmap(pixmap)

        results = dbr.decodeBuffer(frame, 0x3FF | 0x2000000 | 0x4000000 | 0x8000000 | 0x10000000)
        out = ''
        index = 0
        for result in results:
            out += "Index: " + str(index) + "\n"
            out += "Barcode format: " + result[0] + '\n'
            out += "Barcode value: " + result[1] + '\n'
            out += '-----------------------------------\n'
            index += 1

        self.results.setText(out)

In the function that triggered periodically via the timer, we can use OpenCV to capture a frame and decode the frame by calling the API of Dynamsoft Barcode Reader SDK. Note: before creating a QImage with the frame, we have to convert the color space of the frame from BRG to RGB.

Create a horizontal layout QHBoxLayout, which contains two buttons:

button_layout = QHBoxLayout()

btnCamera = QPushButton("Open camera")
btnCamera.clicked.connect(self.openCamera)
button_layout.addWidget(btnCamera)

btnCamera = QPushButton("Stop camera")
btnCamera.clicked.connect(self.stopCamera)
button_layout.addWidget(btnCamera)

layout.addLayout(button_layout)

Connect the buttons to some click events:

def openCamera(self):
        self.vc = cv2.VideoCapture(0)
        # vc.set(5, 30)  #set FPS
        self.vc.set(3, 640) #set width
        self.vc.set(4, 480) #set height

        if not self.vc.isOpened(): 
            msgBox = QMessageBox()
            msgBox.setText("Failed to open camera.")
            msgBox.exec_()
            return

        self.timer.start(1000./24)
    
def stopCamera(self):
        self.timer.stop()

Use closeEvent to pop up a confirm box for exit prompt:

def closeEvent(self, event):
    
        msg = "Close the app?"
        reply = QMessageBox.question(self, 'Message', 
                        msg, QMessageBox.Yes, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()
            self.stopCamera()
        else:
            event.ignore()

Run the app:

Python barcode scanner built with PyQt and webcam

Source Code

https://github.com/dynamsoft-dbr/python/tree/master/examples/qt