How to Build a Python Barcode Scanner for Windows, Linux, and macOS
Barcode Scanning has become an essential tool across various industries, from retail and logistics to healthcare. On desktop platforms, it enables the quick capture and processing of information without manual data entry, saving time and reducing errors. In this tutorial, we will continue exploring the capabilities of the Dynamsoft Capture Vision SDK by building a Python barcode scanner for Windows, Linux, and macOS.
This article is Part 3 in a 3-Part Series.
Python Barcode Scanner Demo on macOS
Prerequisites
-
Dynamsoft Capture Vision Trial License: Obtain a 30-Day trial license key for the Dynamsoft Capture Vision SDK.
-
Python Packages: Install the required Python packages using the following commands:
pip install dynamsoft-capture-vision-bundle opencv-python
What are these packages for?
dynamsoft-capture-vision-bundle
is the Dynamsoft Capture Vision SDK for Python.opencv-python
captures camera frames and displays processed image results.
Reading Barcodes from Static Images
Since the Dynamsoft Capture Vision SDK is a unified framework integrated with various image processing tasks, we can easily switch between image processing modes by passing the PresetTemplate name to the capture()
method.
Built-in Templates of the Dynamsoft Capture Vision SDK
The following code snippet shows the built-in PresetTemplate enumeration in the Dynamsoft Capture Vision SDK:
class EnumPresetTemplate(Enum):
PT_DEFAULT = _DynamsoftCaptureVisionRouter.getPT_DEFAULT()
PT_READ_BARCODES = _DynamsoftCaptureVisionRouter.getPT_READ_BARCODES()
PT_RECOGNIZE_TEXT_LINES = _DynamsoftCaptureVisionRouter.getPT_RECOGNIZE_TEXT_LINES()
PT_DETECT_DOCUMENT_BOUNDARIES = (
_DynamsoftCaptureVisionRouter.getPT_DETECT_DOCUMENT_BOUNDARIES()
)
PT_DETECT_AND_NORMALIZE_DOCUMENT = (
_DynamsoftCaptureVisionRouter.getPT_DETECT_AND_NORMALIZE_DOCUMENT()
)
PT_NORMALIZE_DOCUMENT = _DynamsoftCaptureVisionRouter.getPT_NORMALIZE_DOCUMENT()
PT_READ_BARCODES_SPEED_FIRST = (
_DynamsoftCaptureVisionRouter.getPT_READ_BARCODES_SPEED_FIRST()
)
PT_READ_BARCODES_READ_RATE_FIRST = (
_DynamsoftCaptureVisionRouter.getPT_READ_BARCODES_READ_RATE_FIRST()
)
PT_READ_SINGLE_BARCODE = _DynamsoftCaptureVisionRouter.getPT_READ_SINGLE_BARCODE()
PT_RECOGNIZE_NUMBERS = _DynamsoftCaptureVisionRouter.getPT_RECOGNIZE_NUMBERS()
PT_RECOGNIZE_LETTERS = _DynamsoftCaptureVisionRouter.getPT_RECOGNIZE_LETTERS()
PT_RECOGNIZE_NUMBERS_AND_LETTERS = (
_DynamsoftCaptureVisionRouter.getPT_RECOGNIZE_NUMBERS_AND_LETTERS()
)
PT_RECOGNIZE_NUMBERS_AND_UPPERCASE_LETTERS = (
_DynamsoftCaptureVisionRouter.getPT_RECOGNIZE_NUMBERS_AND_UPPERCASE_LETTERS()
)
PT_RECOGNIZE_UPPERCASE_LETTERS = (
_DynamsoftCaptureVisionRouter.getPT_RECOGNIZE_UPPERCASE_LETTERS()
)
The PT_DEFAULT
template supports multiple tasks, including document detection, MRZ recognition, and barcode detection. To optimize performance specifically for barcode detection, set the template to EnumPresetTemplate.PT_READ_BARCODES.value
.
Python Code for Barcode Detection
Referencing the previous document detection and MRZ recognition examples, the following code can be used to read barcodes from static images:
import sys
from dynamsoft_capture_vision_bundle import *
import os
import cv2
import numpy as np
from utils import *
if __name__ == '__main__':
print("**********************************************************")
print("Welcome to Dynamsoft Capture Vision - Barcode Sample")
print("**********************************************************")
error_code, error_message = LicenseManager.init_license(
"LICENSE-KEY")
if error_code != EnumErrorCode.EC_OK and error_code != EnumErrorCode.EC_LICENSE_CACHE_USED:
print("License initialization failed: ErrorCode:",
error_code, ", ErrorString:", error_message)
else:
cvr_instance = CaptureVisionRouter()
while (True):
image_path = input(
">> Input your image full path:\n"
">> 'Enter' for sample image or 'Q'/'q' to quit\n"
).strip('\'"')
if image_path.lower() == "q":
sys.exit(0)
if image_path == "":
image_path = "../../../images/multi.png"
if not os.path.exists(image_path):
print("The image path does not exist.")
continue
result = cvr_instance.capture(
image_path, EnumPresetTemplate.PT_READ_BARCODES.value)
if result.get_error_code() != EnumErrorCode.EC_OK:
print("Error:", result.get_error_code(),
result.get_error_string())
else:
cv_image = cv2.imread(image_path)
items = result.get_items()
print('Found {} barcodes.'.format(len(items)))
for item in items:
format_type = item.get_format()
text = item.get_text()
print("Barcode Format:", format_type)
print("Barcode Text:", text)
location = item.get_location()
x1 = location.points[0].x
y1 = location.points[0].y
x2 = location.points[1].x
y2 = location.points[1].y
x3 = location.points[2].x
y3 = location.points[2].y
x4 = location.points[3].x
y4 = location.points[3].y
del location
cv2.drawContours(
cv_image, [np.intp([(x1, y1), (x2, y2), (x3, y3), (x4, y4)])], 0, (0, 255, 0), 2)
cv2.putText(cv_image, text, (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv2.imshow(
"Original Image with Detected Barcodes", cv_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
input("Press Enter to quit...")
Note: Replace the
LICENSE-KEY
with your valid license key.
Testing Python Barcode Reader with a Multi-barcode Image
Decoding multiple barcodes from a single image is a common use case in retail and logistics. The following image contains multiple barcodes of different formats:
Real-time Multi-barcode Detection with a Webcam
When reading barcodes from an image file, we invoke the capture()
method in the main thread. However, for processing real-time video streams from a webcam, a different approach is needed to avoid blocking the main thread. The Dynamsoft Capture Vision SDK provides a built-in mechanism for handling real-time video frames and processing them asynchronously on a native C++ worker thread. To implement this, extend the ImageSourceAdapter
and CapturedResultReceiver
classes to handle the image data and captured results, respectively, then call the start_capturing()
method to begin processing the video stream.
from dynamsoft_capture_vision_bundle import *
import cv2
import numpy as np
import queue
from utils import *
class FrameFetcher(ImageSourceAdapter):
def has_next_image_to_fetch(self) -> bool:
return True
def add_frame(self, imageData):
self.add_image_to_buffer(imageData)
class MyCapturedResultReceiver(CapturedResultReceiver):
def __init__(self, result_queue):
super().__init__()
self.result_queue = result_queue
def on_captured_result_received(self, captured_result):
self.result_queue.put(captured_result)
if __name__ == '__main__':
errorCode, errorMsg = LicenseManager.init_license(
"LICENSE-KEY")
if errorCode != EnumErrorCode.EC_OK and errorCode != EnumErrorCode.EC_LICENSE_CACHE_USED:
print("License initialization failed: ErrorCode:",
errorCode, ", ErrorString:", errorMsg)
else:
vc = cv2.VideoCapture(0)
if not vc.isOpened():
print("Error: Camera is not opened!")
exit(1)
cvr = CaptureVisionRouter()
fetcher = FrameFetcher()
cvr.set_input(fetcher)
# Create a thread-safe queue to store captured items
result_queue = queue.Queue()
receiver = MyCapturedResultReceiver(result_queue)
cvr.add_result_receiver(receiver)
errorCode, errorMsg = cvr.start_capturing(
EnumPresetTemplate.PT_READ_BARCODES.value)
if errorCode != EnumErrorCode.EC_OK:
print("error:", errorMsg)
while True:
ret, frame = vc.read()
if not ret:
print("Error: Cannot read frame!")
break
fetcher.add_frame(convertMat2ImageData(frame))
if not result_queue.empty():
captured_result = result_queue.get_nowait()
items = captured_result.get_items()
for item in items:
if item.get_type() == EnumCapturedResultItemType.CRIT_BARCODE:
text = item.get_text()
location = item.get_location()
x1 = location.points[0].x
y1 = location.points[0].y
x2 = location.points[1].x
y2 = location.points[1].y
x3 = location.points[2].x
y3 = location.points[2].y
x4 = location.points[3].x
y4 = location.points[3].y
cv2.drawContours(
frame, [np.intp([(x1, y1), (x2, y2), (x3, y3), (x4, y4)])], 0, (0, 255, 0), 2)
cv2.putText(frame, text, (x1, y1),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
del location
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.imshow('frame', frame)
cvr.stop_capturing()
vc.release()
cv2.destroyAllWindows()
Explanation
- The
FrameFetcher
class implements theImageSourceAdapter
interface to feed frame data into the built-in buffer. - The
MyCapturedResultReceiver
class implements theCapturedResultReceiver
interface. Theon_captured_result_received
method runs on a native C++ worker thread and sendsCapturedResult
objects to the main thread where they are stored in a thread-safe queue for further use. - A
CapturedResult
contains severalCapturedResultItem
objects. TheCRIT_BARCODE
type represents recognized barcode data.
Testing Python Barcode Scanner on macOS
Source Code
https://github.com/yushulx/python-barcode-qrcode-sdk/tree/main/examples/official/10.x