Python, ZBarでバーコード・QRコードを検出・読み取り
PythonとZBar(pyzbar)でバーコードとQRコードを検出し、格納された文字列を読み取る方法について説明する。
- ZBarとpyzbar
- 画像からバーコード・QRコードを検出・読み取り
- 基本的な使い方
- 検出するタイプを指定
- Pillowとpyzbarの組み合わせ
- OpenCVとpyzbarの組み合わせ
- カメラの動画からバーコード・QRコードを検出・読み取り
QRコードの作成については以下の記事を参照。
OpenCV単体でもバーコード・QRコードの検出・読み取りが可能。厳密には検証していないが、検出精度はZBar(pyzbar)のほうが良さそう。
本記事のサンプルコードで使用しているpyzbarのバージョンは0.1.9
。
import pyzbar
print(pyzbar.__version__)
# 0.1.9
※QRコードは株式会社デンソーウェーブの登録商標です。
ZBarとpyzbar
ZBarはバーコードを読み取るためのオープンソースライブラリ。現在はオリジナルからフォークされたものが開発されている。
pyzbarはPythonでZBarを利用するためのライブラリ。pip
でインストールできる。
Windowsの場合、ZBarのDLLが同梱されているため追加のインストールは不要だが、macOSおよびLinuxでは別途ZBar本体のインストールが必要。詳細は上記GitHubのREADMEを参照。
画像からバーコード・QRコードを検出・読み取り
基本的な使い方
pyzbar.pyzbar.decode()
に画像を指定する。ここではPillow(PIL)を用いているが、OpenCVで読み込んだnumpy.ndarray
もそのまま指定可能。OpenCVの例は後述。
例として以下の画像を用いる。
from PIL import Image
from pyzbar.pyzbar import decode, ZBarSymbol
img = Image.open('data/src/barcode_qrcode.jpg')
decode()
は、検出したバーコード・QRコードの情報を保持するpyzbar.pyzbar.Decoded
型を要素とするリストを返す。一つも検出できなかった場合は空のリストとなる。
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
はバーコード・QRコードに格納された内容。バイト列bytes
なので、文字列str
に変換したい場合はdecode()
メソッドを使う。
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
は読み取ったバーコード・QRコードの種類。日本のバーコードで広く使われているJANコードはEANコードをベースに規格化されたものでEAN13
として認識される。
print(decoded_list[0].type)
# QRCODE
print(decoded_list[1].type)
# EAN13
対応する種類は以下の通り。
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
rect
とpolygon
は検出したバーコード・QRコードの位置・形状を表す。rect
はバウンディングボックス、polygon
は検出したエリアそのものを表す多角形。それぞれの違いは後述の図形描画の結果を参照。
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)]
検出するタイプを指定
上述のように、デフォルトではバーコードもQRコードもすべて検出する。
検出対象のタイプを限定したい場合はdecode()
のsymbols
引数にリストを指定する。一つだけでもリストで指定する必要があるので注意。
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
Pillowとpyzbarの組み合わせ
Pillowの図形描画機能を用いて、検出したバーコード・QRコードを枠で囲み、デコードした文字列を重畳して表示する。
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')
Pillowの図形描画についての詳細は以下の記事を参照。
ImageFont.truetype()
のフォント指定がうまくいかない場合はフォントファイルの絶対パスを指定すればよい。
OpenCVとpyzbarの組み合わせ
OpenCVの図形描画機能を用いて、検出したバーコード・QRコードを枠で囲み、デコードした文字列を重畳して表示する。
上述のように、pyzbar.pyzbar.decode()
にはOpenCVで読み込んだnumpy.ndarray
の画像もそのまま指定できる。
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
OpenCVの図形描画についての詳細は以下の記事を参照。
カメラの動画からバーコード・QRコードを検出・読み取り
OpenCVを用いてカメラのリアルタイム動画からバーコード・QRコードを検出し読み取るサンプルコードを示す。
OpenCVにおける動画の扱いについては以下の記事を参照。
キーボードのq
を押すと終了する。
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)
なお、実際のアプリケーションでは、ターゲットのバーコード・QRコードに格納された文字列を取得できた時点でbreak
でwhile
ループを終了し、その文字列を用いた処理に移行する形になることが多いだろう。