Detect and read barcodes and QR codes with ZBar in Python
This article describes how to detect and read barcodes and QR codes with ZBar (pyzbar) in Python.
- ZBar and pyzbar
- Detect and read barcodes and QR codes from an image
- Basic usage
- Specify the type to detect
- Use pyzbar with Pillow
- Use pyzbar with OpenCV
- Detect and read barcodes and QR codes from camera video
See the following article for creating QR codes.
OpenCV alone can detect and read barcodes and QR codes. Although not thoroughly verified, ZBar (pyzbar) seems to have better detection accuracy.
The version of pyzbar used in the sample code is 0.1.9
.
import pyzbar
print(pyzbar.__version__)
# 0.1.9
ZBar and pyzbar
ZBar is a library for reading barcodes. It is currently being developed as a forked version of the original.
Pyzbar is a library for using ZBar in Python. You can install it with pip
.
For Windows, ZBar DLL is included in the package, so no additional installation is required. For macOS and Linux, you need to install ZBar itself. For details, see the README on GitHub above.
Detect and read barcodes and QR codes from an image
Basic usage
Specify an image for pyzbar.pyzbar.decode()
.
Pillow(PIL) is used here, but you can also specify numpy.ndarray
loaded by OpenCV. Examples of OpenCV are described later.
The following image is used as an example.
from PIL import Image
from pyzbar.pyzbar import decode, ZBarSymbol
img = Image.open('data/src/barcode_qrcode.jpg')
decode()
returns a list whose elements are pyzbar.pyzbar.Decoded
storing the information of detected barcodes/QR codes. An empty list is returned if no barcode or QR code is detected.
img = Image.open('data/src/barcode_qrcode.jpg')
decoded_list = decode(img)
print(type(decoded_list))
# <class 'list'>
print(len(decoded_list))
# 3
print(type(decoded_list[0]))
# <class 'pyzbar.pyzbar.Decoded'>
print(decoded_list[0])
# Decoded(data=b'QR Code Example', type='QRCODE', rect=Rect(left=8, top=6, width=159, height=160), polygon=[Point(x=8, y=66), Point(x=66, y=166), Point(x=167, y=109), Point(x=108, y=6)], quality=1, orientation='UP')
print(decoded_list[1])
# Decoded(data=b'1923055034006', type='EAN13', rect=Rect(left=161, top=217, width=175, height=32), polygon=[Point(x=161, y=229), Point(x=239, y=249), Point(x=330, y=248), Point(x=332, y=242), Point(x=335, y=226), Point(x=336, y=220), Point(x=336, y=218), Point(x=248, y=217), Point(x=165, y=217), Point(x=164, y=219), Point(x=162, y=225)], quality=37, orientation='UP')
print(decoded_list[2])
# Decoded(data=b'9784873117980', type='EAN13', rect=Rect(left=196, top=128, width=158, height=26), polygon=[Point(x=196, y=137), Point(x=267, y=151), Point(x=348, y=154), Point(x=349, y=152), Point(x=352, y=138), Point(x=354, y=128), Point(x=199, y=129), Point(x=197, y=133)], quality=25, orientation='UP')
data
is the content stored in the barcode/QR code. Since it is a byte string bytes
, use the decode()
method if you want to convert it to a string str
.
print(decoded_list[0].data)
# b'QR Code Example'
print(type(decoded_list[0].data))
# <class 'bytes'>
print(decoded_list[0].data.decode())
# QR Code Example
type
is the type of barcode/QR code.
print(decoded_list[0].type)
# QRCODE
print(decoded_list[1].type)
# EAN13
Supported types are as follows:
for s in ZBarSymbol:
print(s)
# ZBarSymbol.NONE
# ZBarSymbol.PARTIAL
# ZBarSymbol.EAN2
# ZBarSymbol.EAN5
# ZBarSymbol.EAN8
# ZBarSymbol.UPCE
# ZBarSymbol.ISBN10
# ZBarSymbol.UPCA
# ZBarSymbol.EAN13
# ZBarSymbol.ISBN13
# ZBarSymbol.COMPOSITE
# ZBarSymbol.I25
# ZBarSymbol.DATABAR
# ZBarSymbol.DATABAR_EXP
# ZBarSymbol.CODABAR
# ZBarSymbol.CODE39
# ZBarSymbol.PDF417
# ZBarSymbol.QRCODE
# ZBarSymbol.SQCODE
# ZBarSymbol.CODE93
# ZBarSymbol.CODE128
The rect
and polygon
represent the position and shape of the detected barcode/QR code. The rect
is a bounding box, and the polygon
is a polygon that represents the detected area itself. For the difference between them, see the results of figure drawing described below.
print(decoded_list[0].rect)
# Rect(left=8, top=6, width=159, height=160)
print(decoded_list[0].polygon)
# [Point(x=8, y=66), Point(x=66, y=166), Point(x=167, y=109), Point(x=108, y=6)]
Specify the type to detect
As in the example above, by default, all barcodes and QR codes are detected.
If you want to specify the types to be detected, specify a list in the symbols
argument of decode()
.
print(len(decode(img, symbols=[ZBarSymbol.QRCODE])))
# 1
print(len(decode(img, symbols=[ZBarSymbol.EAN13])))
# 2
print(len(decode(img, symbols=[ZBarSymbol.QRCODE, ZBarSymbol.EAN13])))
# 3
Use pyzbar with Pillow
Using pyzbar and Pillow, draw frames for the detected barcode/QR code and superimpose the decoded text.
from PIL import Image, ImageDraw, ImageFont
from pyzbar.pyzbar import decode
img = Image.open('data/src/barcode_qrcode.jpg')
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('Arial.ttf', size=20) # Set 'arial.ttf' for Windows
for d in decode(img):
draw.rectangle(((d.rect.left, d.rect.top), (d.rect.left + d.rect.width, d.rect.top + d.rect.height)),
outline=(0, 0, 255), width=3)
draw.polygon(d.polygon, outline=(0, 255, 0), width=3)
draw.text((d.rect.left, d.rect.top + d.rect.height), d.data.decode(),
(255, 0, 0), font=font)
img.save('data/dst/barcode_qrcode_pillow.jpg')
For more information on how to draw shapes with Pillow, see the following article.
Use pyzbar with OpenCV
Using pyzbar and OpenCV, draw frames for the detected barcode/QR code and superimpose the decoded text.
As mentioned above, you can specify the numpy.ndarray
image loaded by OpenCV in pyzbar.pyzbar.decode()
.
import cv2
import numpy as np
from pyzbar.pyzbar import decode
img = cv2.imread('data/src/barcode_qrcode.jpg')
for d in decode(img):
img = cv2.rectangle(img, (d.rect.left, d.rect.top),
(d.rect.left + d.rect.width, d.rect.top + d.rect.height), (255, 0, 0), 2)
img = cv2.polylines(img, [np.array(d.polygon)], True, (0, 255, 0), 2)
img = cv2.putText(img, d.data.decode(), (d.rect.left, d.rect.top + d.rect.height),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1, cv2.LINE_AA)
cv2.imwrite('data/dst/barcode_qrcode_opencv.jpg', img)
# True
Detect and read barcodes and QR codes from camera video
The following is a sample code that detects and reads barcodes and QR codes from real-time camera video with OpenCV.
See the following article for more information on the handling of videos in OpenCV.
Press q
on the keyboard to exit.
import cv2
from pyzbar.pyzbar import decode
camera_id = 0
delay = 1
window_name = 'OpenCV pyzbar'
cap = cv2.VideoCapture(camera_id)
while True:
ret, frame = cap.read()
if ret:
for d in decode(frame):
s = d.data.decode()
print(s)
frame = cv2.rectangle(frame, (d.rect.left, d.rect.top),
(d.rect.left + d.rect.width, d.rect.top + d.rect.height), (0, 255, 0), 3)
frame = cv2.putText(frame, s, (d.rect.left, d.rect.top + d.rect.height),
cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 2, cv2.LINE_AA)
cv2.imshow(window_name, frame)
if cv2.waitKey(delay) & 0xFF == ord('q'):
break
cv2.destroyWindow(window_name)
In an actual application, the while
loop would be terminated by break
when the string stored in the target barcode/QR code is obtained, and the application would move on to operation using that string.