Detect and read barcodes and QR codes with ZBar in Python

Posted: | Tags: Python, Image Processing, Pillow, OpenCV

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')

Barcode and QR code sample

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')

Detect and decode barcode and QR code with pyzbar and Pillow

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 decode barcode and QR code with pyzbar and OpenCV

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.

Related Categories

Related Articles